Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
S
simplesamlphp
Manage
Activity
Members
Labels
Plan
Jira
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Model registry
Analyze
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
This is an archived project. Repository and other project resources are read-only.
Show more breadcrumbs
Perun
Perun ProxyIdP
v1
simplesamlphp
Commits
8de8f357
Commit
8de8f357
authored
9 years ago
by
Jaime Perez Crespo
Browse files
Options
Downloads
Patches
Plain Diff
Reformat the SimpleSAML_Auth_State class.
parent
f0d848d7
No related branches found
No related tags found
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
lib/SimpleSAML/Auth/State.php
+386
-365
386 additions, 365 deletions
lib/SimpleSAML/Auth/State.php
with
386 additions
and
365 deletions
lib/SimpleSAML/Auth/State.php
+
386
−
365
View file @
8de8f357
<?php
/**
* This is a helper class for saving and loading state information.
*
...
...
@@ -27,374 +28,394 @@
* @author Olav Morken, UNINETT AS.
* @package SimpleSAMLphp
*/
class
SimpleSAML_Auth_State
{
/**
* The index in the state array which contains the identifier.
*/
const
ID
=
'SimpleSAML_Auth_State.id'
;
/**
* The index in the cloned state array which contains the identifier of the
* original state.
*/
const
CLONE_ORIGINAL_ID
=
'SimpleSAML_Auth_State.cloneOriginalId'
;
/**
* The index in the state array which contains the current stage.
*/
const
STAGE
=
'SimpleSAML_Auth_State.stage'
;
/**
* The index in the state array which contains the restart URL.
*/
const
RESTART
=
'SimpleSAML_Auth_State.restartURL'
;
class
SimpleSAML_Auth_State
{
/**
* The index in the state array which contains the exception handler URL.
*/
const
EXCEPTION_HANDLER_URL
=
'SimpleSAML_Auth_State.exceptionURL'
;
/**
* The index in the state array which contains the exception handler function.
*/
const
EXCEPTION_HANDLER_FUNC
=
'SimpleSAML_Auth_State.exceptionFunc'
;
/**
* The index in the state array which contains the exception data.
*/
const
EXCEPTION_DATA
=
'SimpleSAML_Auth_State.exceptionData'
;
/**
* The index in the state array which contains the identifier.
*/
const
ID
=
'SimpleSAML_Auth_State.id'
;
/**
* The stage of a state with an exception.
*/
const
EXCEPTION_STAGE
=
'SimpleSAML_Auth_State.exceptionStage'
;
/**
* The URL parameter which contains the exception state id.
*/
const
EXCEPTION_PARAM
=
'SimpleSAML_Auth_State_exceptionId'
;
/**
* State timeout.
*/
private
static
$stateTimeout
=
NULL
;
/**
* Get the persistent authentication state from the state array.
*
* @param array $state The state array to analyze.
* @return array The persistent authentication state.
*/
public
static
function
getPersistentAuthData
(
array
$state
)
{
// save persistent authentication data
$persistent
=
array
();
if
(
array_key_exists
(
'PersistentAuthData'
,
$state
))
{
foreach
(
$state
[
'PersistentAuthData'
]
as
$key
)
{
if
(
isset
(
$state
[
$key
]))
{
$persistent
[
$key
]
=
$state
[
$key
];
}
}
}
// add those that should always be included
$mandatory
=
array
(
'Attributes'
,
'Expire'
,
'LogoutState'
,
'AuthInstant'
,
'RememberMe'
,
'saml:sp:NameID'
);
foreach
(
$mandatory
as
$key
)
{
if
(
isset
(
$state
[
$key
]))
{
$persistent
[
$key
]
=
$state
[
$key
];
}
}
return
$persistent
;
}
/**
* Retrieve the ID of a state array.
*
* Note that this function will not save the state.
*
* @param array &$state The state array.
* @param bool $rawId Return a raw ID, without a restart URL. Defaults to FALSE.
* @return string Identifier which can be used to retrieve the state later.
*/
public
static
function
getStateId
(
&
$state
,
$rawId
=
FALSE
)
{
assert
(
'is_array($state)'
);
assert
(
'is_bool($rawId)'
);
if
(
!
array_key_exists
(
self
::
ID
,
$state
))
{
$state
[
self
::
ID
]
=
SimpleSAML\Utils\Random
::
generateID
();
}
$id
=
$state
[
self
::
ID
];
if
(
$rawId
||
!
array_key_exists
(
self
::
RESTART
,
$state
))
{
// Either raw ID or no restart URL. In any case, return the raw ID.
return
$id
;
}
// We have a restart URL. Return the ID with that URL.
return
$id
.
':'
.
$state
[
self
::
RESTART
];
}
/**
* Retrieve state timeout.
*
* @return integer State timeout.
*/
private
static
function
getStateTimeout
()
{
if
(
self
::
$stateTimeout
===
NULL
)
{
$globalConfig
=
SimpleSAML_Configuration
::
getInstance
();
self
::
$stateTimeout
=
$globalConfig
->
getInteger
(
'session.state.timeout'
,
60
*
60
);
}
return
self
::
$stateTimeout
;
}
/**
* Save the state.
*
* This function saves the state, and returns an id which can be used to
* retrieve it later. It will also update the $state array with the identifier.
*
* @param array &$state The login request state.
* @param string $stage The current stage in the login process.
* @param bool $rawId Return a raw ID, without a restart URL.
* @return string Identifier which can be used to retrieve the state later.
*/
public
static
function
saveState
(
&
$state
,
$stage
,
$rawId
=
FALSE
)
{
assert
(
'is_array($state)'
);
assert
(
'is_string($stage)'
);
assert
(
'is_bool($rawId)'
);
$return
=
self
::
getStateId
(
$state
,
$rawId
);
$id
=
$state
[
self
::
ID
];
// Save stage
$state
[
self
::
STAGE
]
=
$stage
;
// Save state
$serializedState
=
serialize
(
$state
);
$session
=
SimpleSAML_Session
::
getSessionFromRequest
();
$session
->
setData
(
'SimpleSAML_Auth_State'
,
$id
,
$serializedState
,
self
::
getStateTimeout
());
SimpleSAML\Logger
::
debug
(
'Saved state: '
.
var_export
(
$return
,
TRUE
));
return
$return
;
}
/**
* Clone the state.
*
* This function clones and returns the new cloned state.
*
* @param array $state The original request state.
* @return array Cloned state data.
*/
public
static
function
cloneState
(
array
$state
)
{
$clonedState
=
$state
;
if
(
array_key_exists
(
self
::
ID
,
$state
))
{
$clonedState
[
self
::
CLONE_ORIGINAL_ID
]
=
$state
[
self
::
ID
];
unset
(
$clonedState
[
self
::
ID
]);
SimpleSAML\Logger
::
debug
(
'Cloned state: '
.
var_export
(
$state
[
self
::
ID
],
TRUE
));
}
else
{
SimpleSAML\Logger
::
debug
(
'Cloned state with undefined id.'
);
}
return
$clonedState
;
}
/**
* Retrieve saved state.
*
* This function retrieves saved state information. If the state information has been lost,
* it will attempt to restart the request by calling the restart URL which is embedded in the
* state information. If there is no restart information available, an exception will be thrown.
*
* @param string $id State identifier (with embedded restart information).
* @param string $stage The stage the state should have been saved in.
* @param bool $allowMissing Whether to allow the state to be missing.
* @return array|NULL State information, or NULL if the state is missing and $allowMissing is TRUE.
*/
public
static
function
loadState
(
$id
,
$stage
,
$allowMissing
=
FALSE
)
{
assert
(
'is_string($id)'
);
assert
(
'is_string($stage)'
);
assert
(
'is_bool($allowMissing)'
);
SimpleSAML\Logger
::
debug
(
'Loading state: '
.
var_export
(
$id
,
TRUE
));
$sid
=
self
::
parseStateID
(
$id
);
$session
=
SimpleSAML_Session
::
getSessionFromRequest
();
$state
=
$session
->
getData
(
'SimpleSAML_Auth_State'
,
$sid
[
'id'
]);
if
(
$state
===
NULL
)
{
// Could not find saved data
if
(
$allowMissing
)
{
return
NULL
;
}
if
(
$sid
[
'url'
]
===
NULL
)
{
throw
new
SimpleSAML_Error_NoState
();
}
\SimpleSAML\Utils\HTTP
::
redirectUntrustedURL
(
$sid
[
'url'
]);
}
$state
=
unserialize
(
$state
);
assert
(
'is_array($state)'
);
assert
(
'array_key_exists(self::ID, $state)'
);
assert
(
'array_key_exists(self::STAGE, $state)'
);
// Verify stage
if
(
$state
[
self
::
STAGE
]
!==
$stage
)
{
/* This could be a user trying to bypass security, but most likely it is just
* someone using the back-button in the browser. We try to restart the
* request if that is possible. If not, show an error.
*/
$msg
=
'Wrong stage in state. Was \''
.
$state
[
self
::
STAGE
]
.
'\', should be \''
.
$stage
.
'\'.'
;
SimpleSAML\Logger
::
warning
(
$msg
);
if
(
$sid
[
'url'
]
===
NULL
)
{
throw
new
Exception
(
$msg
);
}
\SimpleSAML\Utils\HTTP
::
redirectUntrustedURL
(
$sid
[
'url'
]);
}
return
$state
;
}
/**
* Delete state.
*
* This function deletes the given state to prevent the user from reusing it later.
*
* @param array &$state The state which should be deleted.
*/
public
static
function
deleteState
(
&
$state
)
{
assert
(
'is_array($state)'
);
if
(
!
array_key_exists
(
self
::
ID
,
$state
))
{
// This state hasn't been saved
return
;
}
SimpleSAML\Logger
::
debug
(
'Deleting state: '
.
var_export
(
$state
[
self
::
ID
],
TRUE
));
$session
=
SimpleSAML_Session
::
getSessionFromRequest
();
$session
->
deleteData
(
'SimpleSAML_Auth_State'
,
$state
[
self
::
ID
]);
}
/**
* Throw exception to the state exception handler.
*
* @param array $state The state array.
* @param SimpleSAML_Error_Exception $exception The exception.
*/
public
static
function
throwException
(
$state
,
SimpleSAML_Error_Exception
$exception
)
{
assert
(
'is_array($state)'
);
if
(
array_key_exists
(
self
::
EXCEPTION_HANDLER_URL
,
$state
))
{
// Save the exception
$state
[
self
::
EXCEPTION_DATA
]
=
$exception
;
$id
=
self
::
saveState
(
$state
,
self
::
EXCEPTION_STAGE
);
// Redirect to the exception handler
\SimpleSAML\Utils\HTTP
::
redirectTrustedURL
(
$state
[
self
::
EXCEPTION_HANDLER_URL
],
array
(
self
::
EXCEPTION_PARAM
=>
$id
));
}
elseif
(
array_key_exists
(
self
::
EXCEPTION_HANDLER_FUNC
,
$state
))
{
// Call the exception handler
$func
=
$state
[
self
::
EXCEPTION_HANDLER_FUNC
];
assert
(
'is_callable($func)'
);
call_user_func
(
$func
,
$exception
,
$state
);
assert
(
FALSE
);
}
else
{
/*
* No exception handler is defined for the current state.
*/
throw
$exception
;
}
}
/**
* Retrieve an exception state.
*
* @param string|NULL $id The exception id. Can be NULL, in which case it will be retrieved from the request.
* @return array|NULL The state array with the exception, or NULL if no exception was thrown.
*/
public
static
function
loadExceptionState
(
$id
=
NULL
)
{
assert
(
'is_string($id) || is_null($id)'
);
if
(
$id
===
NULL
)
{
if
(
!
array_key_exists
(
self
::
EXCEPTION_PARAM
,
$_REQUEST
))
{
// No exception
return
NULL
;
}
$id
=
$_REQUEST
[
self
::
EXCEPTION_PARAM
];
}
$state
=
self
::
loadState
(
$id
,
self
::
EXCEPTION_STAGE
);
assert
(
'array_key_exists(self::EXCEPTION_DATA, $state)'
);
return
$state
;
}
/**
* Get the ID and (optionally) a URL embedded in a StateID, in the form 'id:url'.
*
* @param string $stateId The state ID to use.
*
* @return array A hashed array with the ID and the URL (if any), in the 'id' and 'url' keys, respectively. If
* there's no URL in the input parameter, NULL will be returned as the value for the 'url' key.
*
* @author Andreas Solberg, UNINETT AS <andreas.solberg@uninett.no>
* @author Jaime Perez, UNINETT AS <jaime.perez@uninett.no>
*/
public
static
function
parseStateID
(
$stateId
)
{
$tmp
=
explode
(
':'
,
$stateId
,
2
);
$id
=
$tmp
[
0
];
$url
=
null
;
if
(
count
(
$tmp
)
===
2
)
{
$url
=
$tmp
[
1
];
}
return
array
(
'id'
=>
$id
,
'url'
=>
$url
);
}
/**
* The index in the cloned state array which contains the identifier of the
* original state.
*/
const
CLONE_ORIGINAL_ID
=
'SimpleSAML_Auth_State.cloneOriginalId'
;
/**
* The index in the state array which contains the current stage.
*/
const
STAGE
=
'SimpleSAML_Auth_State.stage'
;
/**
* The index in the state array which contains the restart URL.
*/
const
RESTART
=
'SimpleSAML_Auth_State.restartURL'
;
/**
* The index in the state array which contains the exception handler URL.
*/
const
EXCEPTION_HANDLER_URL
=
'SimpleSAML_Auth_State.exceptionURL'
;
/**
* The index in the state array which contains the exception handler function.
*/
const
EXCEPTION_HANDLER_FUNC
=
'SimpleSAML_Auth_State.exceptionFunc'
;
/**
* The index in the state array which contains the exception data.
*/
const
EXCEPTION_DATA
=
'SimpleSAML_Auth_State.exceptionData'
;
/**
* The stage of a state with an exception.
*/
const
EXCEPTION_STAGE
=
'SimpleSAML_Auth_State.exceptionStage'
;
/**
* The URL parameter which contains the exception state id.
*/
const
EXCEPTION_PARAM
=
'SimpleSAML_Auth_State_exceptionId'
;
/**
* State timeout.
*/
private
static
$stateTimeout
=
null
;
/**
* Get the persistent authentication state from the state array.
*
* @param array $state The state array to analyze.
*
* @return array The persistent authentication state.
*/
public
static
function
getPersistentAuthData
(
array
$state
)
{
// save persistent authentication data
$persistent
=
array
();
if
(
array_key_exists
(
'PersistentAuthData'
,
$state
))
{
foreach
(
$state
[
'PersistentAuthData'
]
as
$key
)
{
if
(
isset
(
$state
[
$key
]))
{
$persistent
[
$key
]
=
$state
[
$key
];
}
}
}
// add those that should always be included
$mandatory
=
array
(
'Attributes'
,
'Expire'
,
'LogoutState'
,
'AuthInstant'
,
'RememberMe'
,
'saml:sp:NameID'
);
foreach
(
$mandatory
as
$key
)
{
if
(
isset
(
$state
[
$key
]))
{
$persistent
[
$key
]
=
$state
[
$key
];
}
}
return
$persistent
;
}
/**
* Retrieve the ID of a state array.
*
* Note that this function will not save the state.
*
* @param array &$state The state array.
* @param bool $rawId Return a raw ID, without a restart URL. Defaults to FALSE.
*
* @return string Identifier which can be used to retrieve the state later.
*/
public
static
function
getStateId
(
&
$state
,
$rawId
=
false
)
{
assert
(
'is_array($state)'
);
assert
(
'is_bool($rawId)'
);
if
(
!
array_key_exists
(
self
::
ID
,
$state
))
{
$state
[
self
::
ID
]
=
SimpleSAML\Utils\Random
::
generateID
();
}
$id
=
$state
[
self
::
ID
];
if
(
$rawId
||
!
array_key_exists
(
self
::
RESTART
,
$state
))
{
// Either raw ID or no restart URL. In any case, return the raw ID.
return
$id
;
}
// We have a restart URL. Return the ID with that URL.
return
$id
.
':'
.
$state
[
self
::
RESTART
];
}
/**
* Retrieve state timeout.
*
* @return integer State timeout.
*/
private
static
function
getStateTimeout
()
{
if
(
self
::
$stateTimeout
===
null
)
{
$globalConfig
=
SimpleSAML_Configuration
::
getInstance
();
self
::
$stateTimeout
=
$globalConfig
->
getInteger
(
'session.state.timeout'
,
60
*
60
);
}
return
self
::
$stateTimeout
;
}
/**
* Save the state.
*
* This function saves the state, and returns an id which can be used to
* retrieve it later. It will also update the $state array with the identifier.
*
* @param array &$state The login request state.
* @param string $stage The current stage in the login process.
* @param bool $rawId Return a raw ID, without a restart URL.
*
* @return string Identifier which can be used to retrieve the state later.
*/
public
static
function
saveState
(
&
$state
,
$stage
,
$rawId
=
false
)
{
assert
(
'is_array($state)'
);
assert
(
'is_string($stage)'
);
assert
(
'is_bool($rawId)'
);
$return
=
self
::
getStateId
(
$state
,
$rawId
);
$id
=
$state
[
self
::
ID
];
// Save stage
$state
[
self
::
STAGE
]
=
$stage
;
// Save state
$serializedState
=
serialize
(
$state
);
$session
=
SimpleSAML_Session
::
getSessionFromRequest
();
$session
->
setData
(
'SimpleSAML_Auth_State'
,
$id
,
$serializedState
,
self
::
getStateTimeout
());
SimpleSAML\Logger
::
debug
(
'Saved state: '
.
var_export
(
$return
,
true
));
return
$return
;
}
/**
* Clone the state.
*
* This function clones and returns the new cloned state.
*
* @param array $state The original request state.
*
* @return array Cloned state data.
*/
public
static
function
cloneState
(
array
$state
)
{
$clonedState
=
$state
;
if
(
array_key_exists
(
self
::
ID
,
$state
))
{
$clonedState
[
self
::
CLONE_ORIGINAL_ID
]
=
$state
[
self
::
ID
];
unset
(
$clonedState
[
self
::
ID
]);
SimpleSAML\Logger
::
debug
(
'Cloned state: '
.
var_export
(
$state
[
self
::
ID
],
true
));
}
else
{
SimpleSAML\Logger
::
debug
(
'Cloned state with undefined id.'
);
}
return
$clonedState
;
}
/**
* Retrieve saved state.
*
* This function retrieves saved state information. If the state information has been lost,
* it will attempt to restart the request by calling the restart URL which is embedded in the
* state information. If there is no restart information available, an exception will be thrown.
*
* @param string $id State identifier (with embedded restart information).
* @param string $stage The stage the state should have been saved in.
* @param bool $allowMissing Whether to allow the state to be missing.
*
* @throws SimpleSAML_Error_NoState If we couldn't find the state and there's no URL defined to redirect to.
* @throws Exception If the stage of the state is invalid and there's no URL defined to redirect to.
*
* @return array|NULL State information, or null if the state is missing and $allowMissing is true.
*/
public
static
function
loadState
(
$id
,
$stage
,
$allowMissing
=
false
)
{
assert
(
'is_string($id)'
);
assert
(
'is_string($stage)'
);
assert
(
'is_bool($allowMissing)'
);
SimpleSAML\Logger
::
debug
(
'Loading state: '
.
var_export
(
$id
,
true
));
$sid
=
self
::
parseStateID
(
$id
);
$session
=
SimpleSAML_Session
::
getSessionFromRequest
();
$state
=
$session
->
getData
(
'SimpleSAML_Auth_State'
,
$sid
[
'id'
]);
if
(
$state
===
null
)
{
// Could not find saved data
if
(
$allowMissing
)
{
return
null
;
}
if
(
$sid
[
'url'
]
===
null
)
{
throw
new
SimpleSAML_Error_NoState
();
}
\SimpleSAML\Utils\HTTP
::
redirectUntrustedURL
(
$sid
[
'url'
]);
}
$state
=
unserialize
(
$state
);
assert
(
'is_array($state)'
);
assert
(
'array_key_exists(self::ID, $state)'
);
assert
(
'array_key_exists(self::STAGE, $state)'
);
// Verify stage
if
(
$state
[
self
::
STAGE
]
!==
$stage
)
{
/* This could be a user trying to bypass security, but most likely it is just
* someone using the back-button in the browser. We try to restart the
* request if that is possible. If not, show an error.
*/
$msg
=
'Wrong stage in state. Was \''
.
$state
[
self
::
STAGE
]
.
'\', should be \''
.
$stage
.
'\'.'
;
SimpleSAML\Logger
::
warning
(
$msg
);
if
(
$sid
[
'url'
]
===
null
)
{
throw
new
Exception
(
$msg
);
}
\SimpleSAML\Utils\HTTP
::
redirectUntrustedURL
(
$sid
[
'url'
]);
}
return
$state
;
}
/**
* Delete state.
*
* This function deletes the given state to prevent the user from reusing it later.
*
* @param array &$state The state which should be deleted.
*/
public
static
function
deleteState
(
&
$state
)
{
assert
(
'is_array($state)'
);
if
(
!
array_key_exists
(
self
::
ID
,
$state
))
{
// This state hasn't been saved
return
;
}
SimpleSAML\Logger
::
debug
(
'Deleting state: '
.
var_export
(
$state
[
self
::
ID
],
true
));
$session
=
SimpleSAML_Session
::
getSessionFromRequest
();
$session
->
deleteData
(
'SimpleSAML_Auth_State'
,
$state
[
self
::
ID
]);
}
/**
* Throw exception to the state exception handler.
*
* @param array $state The state array.
* @param SimpleSAML_Error_Exception $exception The exception.
*
* @throws SimpleSAML_Error_Exception If there is no exception handler defined, it will just throw the $exception.
*/
public
static
function
throwException
(
$state
,
SimpleSAML_Error_Exception
$exception
)
{
assert
(
'is_array($state)'
);
if
(
array_key_exists
(
self
::
EXCEPTION_HANDLER_URL
,
$state
))
{
// Save the exception
$state
[
self
::
EXCEPTION_DATA
]
=
$exception
;
$id
=
self
::
saveState
(
$state
,
self
::
EXCEPTION_STAGE
);
// Redirect to the exception handler
\SimpleSAML\Utils\HTTP
::
redirectTrustedURL
(
$state
[
self
::
EXCEPTION_HANDLER_URL
],
array
(
self
::
EXCEPTION_PARAM
=>
$id
)
);
}
elseif
(
array_key_exists
(
self
::
EXCEPTION_HANDLER_FUNC
,
$state
))
{
// Call the exception handler
$func
=
$state
[
self
::
EXCEPTION_HANDLER_FUNC
];
assert
(
'is_callable($func)'
);
call_user_func
(
$func
,
$exception
,
$state
);
assert
(
false
);
}
else
{
/*
* No exception handler is defined for the current state.
*/
throw
$exception
;
}
}
/**
* Retrieve an exception state.
*
* @param string|NULL $id The exception id. Can be NULL, in which case it will be retrieved from the request.
*
* @return array|NULL The state array with the exception, or NULL if no exception was thrown.
*/
public
static
function
loadExceptionState
(
$id
=
null
)
{
assert
(
'is_string($id) || is_null($id)'
);
if
(
$id
===
null
)
{
if
(
!
array_key_exists
(
self
::
EXCEPTION_PARAM
,
$_REQUEST
))
{
// No exception
return
null
;
}
$id
=
$_REQUEST
[
self
::
EXCEPTION_PARAM
];
}
$state
=
self
::
loadState
(
$id
,
self
::
EXCEPTION_STAGE
);
assert
(
'array_key_exists(self::EXCEPTION_DATA, $state)'
);
return
$state
;
}
/**
* Get the ID and (optionally) a URL embedded in a StateID, in the form 'id:url'.
*
* @param string $stateId The state ID to use.
*
* @return array A hashed array with the ID and the URL (if any), in the 'id' and 'url' keys, respectively. If
* there's no URL in the input parameter, NULL will be returned as the value for the 'url' key.
*
* @author Andreas Solberg, UNINETT AS <andreas.solberg@uninett.no>
* @author Jaime Perez, UNINETT AS <jaime.perez@uninett.no>
*/
public
static
function
parseStateID
(
$stateId
)
{
$tmp
=
explode
(
':'
,
$stateId
,
2
);
$id
=
$tmp
[
0
];
$url
=
null
;
if
(
count
(
$tmp
)
===
2
)
{
$url
=
$tmp
[
1
];
}
return
array
(
'id'
=>
$id
,
'url'
=>
$url
);
}
}
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment