From: Diogo Cordeiro Date: Sat, 22 Jun 2019 21:23:21 +0000 (+0100) Subject: [CORE][COMPOSER] Move plugins extlibs to composer (where appropriate) X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=a1edc2c6a96591be69e9b881bcf1e4fb2273f402;p=quix0rs-gnu-social.git [CORE][COMPOSER] Move plugins extlibs to composer (where appropriate) --- diff --git a/composer.json b/composer.json index 4df065be26..06ef734464 100644 --- a/composer.json +++ b/composer.json @@ -19,7 +19,13 @@ "ezyang/htmlpurifier": "^4.10", "masterminds/html5": "^2.6", "mf2/mf2": "^0.4.6", - "openid/php-openid": "^2.3" + "openid/php-openid": "^2.3", + "michelf/php-markdown": "^1.8.0", + "paragonie/constant_time_encoding": "^1.0.4", + "stomp-php/stomp-php": "^4.5.1", + "phpseclib/phpseclib": "^2.0.19", + "diogocomposer/xmpphp": "^3.0", + "apereo/phpcas": "^1.3" }, "require-dev": { "phpdocumentor/phpdocumentor": "^2.9", diff --git a/composer.lock b/composer.lock index de5bdd7a8d..f697583607 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,134 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "36b1e5eb69507ed41082369ded69837c", + "content-hash": "dea0804dd9970a97dcd17a53410327a0", "packages": [ + { + "name": "apereo/phpcas", + "version": "1.3.7", + "source": { + "type": "git", + "url": "https://github.com/apereo/phpCAS.git", + "reference": "b5b29102c3a42f570c4a3e852f3cf67cae6d6082" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/apereo/phpCAS/zipball/b5b29102c3a42f570c4a3e852f3cf67cae6d6082", + "reference": "b5b29102c3a42f570c4a3e852f3cf67cae6d6082", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "~3.7.10" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "source/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Joachim Fritschi", + "homepage": "https://wiki.jasig.org/display/~fritschi" + }, + { + "name": "Adam Franco", + "homepage": "https://wiki.jasig.org/display/~adamfranco" + } + ], + "description": "Provides a simple API for authenticating users against a CAS server", + "homepage": "https://wiki.jasig.org/display/CASC/phpCAS", + "keywords": [ + "apereo", + "cas", + "jasig" + ], + "time": "2019-04-22T19:48:16+00:00" + }, + { + "name": "diogocomposer/xmpphp", + "version": "v3.0.0", + "source": { + "type": "git", + "url": "https://github.com/diogogithub/xmpphp.git", + "reference": "c7cdcc588aa47893ab41a1670c5dfe649674a4b0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/diogogithub/xmpphp/zipball/c7cdcc588aa47893ab41a1670c5dfe649674a4b0", + "reference": "c7cdcc588aa47893ab41a1670c5dfe649674a4b0", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "ext-xml": "*", + "php": ">=7.0.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "XMPPHP\\": "XMPPHP" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-2.0+" + ], + "authors": [ + { + "name": "Ivan Borzenkov", + "email": "ivan.borzenkov@gmail.com" + }, + { + "name": "bandroidx", + "email": "bandroidx@gmail.com" + }, + { + "name": "BirknerAlex", + "email": "alex.birkner@gmail.com" + }, + { + "name": "Stephan Wentz", + "email": "stephan@wentz.it" + }, + { + "name": "Nathan Fritz", + "email": "fritzy@netflint.net" + }, + { + "name": "Christian Weiske", + "email": "cweiske@cweiske.de" + }, + { + "name": "Vito Tafuni", + "email": "vitotafuni@gmail.com" + }, + { + "name": "Diogo Cordeiro", + "email": "diogo@fc.up.pt" + } + ], + "description": "XMPP PHP Library", + "keywords": [ + "jabber", + "xmpp", + "xmpphp" + ], + "time": "2019-06-19T02:32:32+00:00" + }, { "name": "ezyang/htmlpurifier", "version": "v4.10.0", @@ -176,6 +302,52 @@ ], "time": "2018-08-24T14:47:04+00:00" }, + { + "name": "michelf/php-markdown", + "version": "1.8.0", + "source": { + "type": "git", + "url": "https://github.com/michelf/php-markdown.git", + "reference": "01ab082b355bf188d907b9929cd99b2923053495" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/michelf/php-markdown/zipball/01ab082b355bf188d907b9929cd99b2923053495", + "reference": "01ab082b355bf188d907b9929cd99b2923053495", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Michelf\\": "Michelf/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Michel Fortin", + "email": "michel.fortin@michelf.ca", + "homepage": "https://michelf.ca/", + "role": "Developer" + }, + { + "name": "John Gruber", + "homepage": "https://daringfireball.net/" + } + ], + "description": "PHP Markdown", + "homepage": "https://michelf.ca/projects/php-markdown/", + "keywords": [ + "markdown" + ], + "time": "2018-01-15T00:49:33+00:00" + }, { "name": "openid/php-openid", "version": "2.3.0", @@ -224,6 +396,220 @@ "yadis" ], "time": "2015-07-30T18:07:43+00:00" + }, + { + "name": "paragonie/constant_time_encoding", + "version": "v1.0.4", + "source": { + "type": "git", + "url": "https://github.com/paragonie/constant_time_encoding.git", + "reference": "2132f0f293d856026d7d11bd81b9f4a23a1dc1f6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/2132f0f293d856026d7d11bd81b9f4a23a1dc1f6", + "reference": "2132f0f293d856026d7d11bd81b9f4a23a1dc1f6", + "shasum": "" + }, + "require": { + "php": "^5.3|^7" + }, + "require-dev": { + "paragonie/random_compat": "^1.4|^2", + "phpunit/phpunit": "4.*|5.*", + "vimeo/psalm": "^0.3|^1" + }, + "type": "library", + "autoload": { + "psr-4": { + "ParagonIE\\ConstantTime\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com", + "role": "Maintainer" + }, + { + "name": "Steve 'Sc00bz' Thomas", + "email": "steve@tobtu.com", + "homepage": "https://www.tobtu.com", + "role": "Original Developer" + } + ], + "description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)", + "keywords": [ + "base16", + "base32", + "base32_decode", + "base32_encode", + "base64", + "base64_decode", + "base64_encode", + "bin2hex", + "encoding", + "hex", + "hex2bin", + "rfc4648" + ], + "time": "2018-04-30T17:57:16+00:00" + }, + { + "name": "phpseclib/phpseclib", + "version": "2.0.19", + "source": { + "type": "git", + "url": "https://github.com/phpseclib/phpseclib.git", + "reference": "d2085db7b7394baa071a69c8f9159723c250f2ba" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/d2085db7b7394baa071a69c8f9159723c250f2ba", + "reference": "d2085db7b7394baa071a69c8f9159723c250f2ba", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phing/phing": "~2.7", + "phpunit/phpunit": "^4.8.35|^5.7|^6.0", + "sami/sami": "~2.0", + "squizlabs/php_codesniffer": "~2.0" + }, + "suggest": { + "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.", + "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.", + "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.", + "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations." + }, + "type": "library", + "autoload": { + "files": [ + "phpseclib/bootstrap.php" + ], + "psr-4": { + "phpseclib\\": "phpseclib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jim Wigginton", + "email": "terrafrost@php.net", + "role": "Lead Developer" + }, + { + "name": "Patrick Monnerat", + "email": "pm@datasphere.ch", + "role": "Developer" + }, + { + "name": "Andreas Fischer", + "email": "bantu@phpbb.com", + "role": "Developer" + }, + { + "name": "Hans-Jürgen Petrich", + "email": "petrich@tronic-media.com", + "role": "Developer" + }, + { + "name": "Graham Campbell", + "email": "graham@alt-three.com", + "role": "Developer" + } + ], + "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.", + "homepage": "http://phpseclib.sourceforge.net", + "keywords": [ + "BigInteger", + "aes", + "asn.1", + "asn1", + "blowfish", + "crypto", + "cryptography", + "encryption", + "rsa", + "security", + "sftp", + "signature", + "signing", + "ssh", + "twofish", + "x.509", + "x509" + ], + "time": "2019-06-20T03:34:11+00:00" + }, + { + "name": "stomp-php/stomp-php", + "version": "4.5.1", + "source": { + "type": "git", + "url": "https://github.com/stomp-php/stomp-php.git", + "reference": "4c5f0a95330085a86fd852b8ad0b1fbb4e8a4158" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/stomp-php/stomp-php/zipball/4c5f0a95330085a86fd852b8ad0b1fbb4e8a4158", + "reference": "4c5f0a95330085a86fd852b8ad0b1fbb4e8a4158", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "Stomp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Dejan Bosnanac", + "email": "dejan@nighttale.net", + "homepage": "http://www.nighttale.net" + }, + { + "name": "Sören Rohweder", + "email": "s.rohweder@blage.net", + "homepage": "http://www.monofone.de" + }, + { + "name": "Jens Radtke", + "email": "swefl@fin-sn.de", + "homepage": "http://www.fin-sn.de" + } + ], + "description": "stomp support for PHP", + "homepage": "http://github.com/stomp-php/stomp-php", + "keywords": [ + "activeMQ", + "apollomq", + "jms", + "messaging", + "rabbitmq", + "stomp" + ], + "time": "2019-04-09T08:25:54+00:00" } ], "packages-dev": [ diff --git a/plugins/CasAuthentication/extlib/CAS.php b/plugins/CasAuthentication/extlib/CAS.php deleted file mode 100644 index 62a6175794..0000000000 --- a/plugins/CasAuthentication/extlib/CAS.php +++ /dev/null @@ -1,1610 +0,0 @@ -=') && !(function_exists('domxml_new_doc'))) { - require_once (dirname(__FILE__) . '/CAS/domxml-php4-to-php5.php'); -} - -/** - * @file CAS/CAS.php - * Interface class of the phpCAS library - * - * @ingroup public - */ - -// ######################################################################## -// CONSTANTS -// ######################################################################## - -// ------------------------------------------------------------------------ -// CAS VERSIONS -// ------------------------------------------------------------------------ - -/** - * phpCAS version. accessible for the user by phpCAS::getVersion(). - */ -define('PHPCAS_VERSION', '1.1.2'); - -// ------------------------------------------------------------------------ -// CAS VERSIONS -// ------------------------------------------------------------------------ -/** - * @addtogroup public - * @{ - */ - -/** - * CAS version 1.0 - */ -define("CAS_VERSION_1_0", '1.0'); -/*! - * CAS version 2.0 - */ -define("CAS_VERSION_2_0", '2.0'); - -// ------------------------------------------------------------------------ -// SAML defines -// ------------------------------------------------------------------------ - -/** - * SAML protocol - */ -define("SAML_VERSION_1_1", 'S1'); - -/** - * XML header for SAML POST - */ -define("SAML_XML_HEADER", ''); - -/** - * SOAP envelope for SAML POST - */ -define("SAML_SOAP_ENV", ''); - -/** - * SOAP body for SAML POST - */ -define("SAML_SOAP_BODY", ''); - -/** - * SAMLP request - */ -define("SAMLP_REQUEST", ''); -define("SAMLP_REQUEST_CLOSE", ''); - -/** - * SAMLP artifact tag (for the ticket) - */ -define("SAML_ASSERTION_ARTIFACT", ''); - -/** - * SAMLP close - */ -define("SAML_ASSERTION_ARTIFACT_CLOSE", ''); - -/** - * SOAP body close - */ -define("SAML_SOAP_BODY_CLOSE", ''); - -/** - * SOAP envelope close - */ -define("SAML_SOAP_ENV_CLOSE", ''); - -/** - * SAML Attributes - */ -define("SAML_ATTRIBUTES", 'SAMLATTRIBS'); - -/** @} */ -/** - * @addtogroup publicPGTStorage - * @{ - */ -// ------------------------------------------------------------------------ -// FILE PGT STORAGE -// ------------------------------------------------------------------------ -/** - * Default path used when storing PGT's to file - */ -define("CAS_PGT_STORAGE_FILE_DEFAULT_PATH", '/tmp'); -/** - * phpCAS::setPGTStorageFile()'s 2nd parameter to write plain text files - */ -define("CAS_PGT_STORAGE_FILE_FORMAT_PLAIN", 'plain'); -/** - * phpCAS::setPGTStorageFile()'s 2nd parameter to write xml files - */ -define("CAS_PGT_STORAGE_FILE_FORMAT_XML", 'xml'); -/** - * Default format used when storing PGT's to file - */ -define("CAS_PGT_STORAGE_FILE_DEFAULT_FORMAT", CAS_PGT_STORAGE_FILE_FORMAT_PLAIN); -// ------------------------------------------------------------------------ -// DATABASE PGT STORAGE -// ------------------------------------------------------------------------ -/** - * default database type when storing PGT's to database - */ -define("CAS_PGT_STORAGE_DB_DEFAULT_DATABASE_TYPE", 'mysql'); -/** - * default host when storing PGT's to database - */ -define("CAS_PGT_STORAGE_DB_DEFAULT_HOSTNAME", 'localhost'); -/** - * default port when storing PGT's to database - */ -define("CAS_PGT_STORAGE_DB_DEFAULT_PORT", ''); -/** - * default database when storing PGT's to database - */ -define("CAS_PGT_STORAGE_DB_DEFAULT_DATABASE", 'phpCAS'); -/** - * default table when storing PGT's to database - */ -define("CAS_PGT_STORAGE_DB_DEFAULT_TABLE", 'pgt'); - -/** @} */ -// ------------------------------------------------------------------------ -// SERVICE ACCESS ERRORS -// ------------------------------------------------------------------------ -/** - * @addtogroup publicServices - * @{ - */ - -/** - * phpCAS::service() error code on success - */ -define("PHPCAS_SERVICE_OK", 0); -/** - * phpCAS::service() error code when the PT could not retrieve because - * the CAS server did not respond. - */ -define("PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE", 1); -/** - * phpCAS::service() error code when the PT could not retrieve because - * the response of the CAS server was ill-formed. - */ -define("PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE", 2); -/** - * phpCAS::service() error code when the PT could not retrieve because - * the CAS server did not want to. - */ -define("PHPCAS_SERVICE_PT_FAILURE", 3); -/** - * phpCAS::service() error code when the service was not available. - */ -define("PHPCAS_SERVICE_NOT AVAILABLE", 4); - -/** @} */ -// ------------------------------------------------------------------------ -// LANGUAGES -// ------------------------------------------------------------------------ -/** - * @addtogroup publicLang - * @{ - */ - -define("PHPCAS_LANG_ENGLISH", 'english'); -define("PHPCAS_LANG_FRENCH", 'french'); -define("PHPCAS_LANG_GREEK", 'greek'); -define("PHPCAS_LANG_GERMAN", 'german'); -define("PHPCAS_LANG_JAPANESE", 'japanese'); -define("PHPCAS_LANG_SPANISH", 'spanish'); -define("PHPCAS_LANG_CATALAN", 'catalan'); - -/** @} */ - -/** - * @addtogroup internalLang - * @{ - */ - -/** - * phpCAS default language (when phpCAS::setLang() is not used) - */ -define("PHPCAS_LANG_DEFAULT", PHPCAS_LANG_ENGLISH); - -/** @} */ -// ------------------------------------------------------------------------ -// DEBUG -// ------------------------------------------------------------------------ -/** - * @addtogroup publicDebug - * @{ - */ - -/** - * The default directory for the debug file under Unix. - */ -define('DEFAULT_DEBUG_DIR', '/tmp/'); - -/** @} */ -// ------------------------------------------------------------------------ -// MISC -// ------------------------------------------------------------------------ -/** - * @addtogroup internalMisc - * @{ - */ - -/** - * This global variable is used by the interface class phpCAS. - * - * @hideinitializer - */ -$GLOBALS['PHPCAS_CLIENT'] = null; - -/** - * This global variable is used to store where the initializer is called from - * (to print a comprehensive error in case of multiple calls). - * - * @hideinitializer - */ -$GLOBALS['PHPCAS_INIT_CALL'] = array ( - 'done' => FALSE, - 'file' => '?', - 'line' => -1, - 'method' => '?' -); - -/** - * This global variable is used to store where the method checking - * the authentication is called from (to print comprehensive errors) - * - * @hideinitializer - */ -$GLOBALS['PHPCAS_AUTH_CHECK_CALL'] = array ( - 'done' => FALSE, - 'file' => '?', - 'line' => -1, - 'method' => '?', - 'result' => FALSE -); - -/** - * This global variable is used to store phpCAS debug mode. - * - * @hideinitializer - */ -$GLOBALS['PHPCAS_DEBUG'] = array ( - 'filename' => FALSE, - 'indent' => 0, - 'unique_id' => '' -); - -/** @} */ - -// ######################################################################## -// CLIENT CLASS -// ######################################################################## - -// include client class -include_once (dirname(__FILE__) . '/CAS/client.php'); - -// ######################################################################## -// INTERFACE CLASS -// ######################################################################## - -/** - * @class phpCAS - * The phpCAS class is a simple container for the phpCAS library. It provides CAS - * authentication for web applications written in PHP. - * - * @ingroup public - * @author Pascal Aubry - * - * \internal All its methods access the same object ($PHPCAS_CLIENT, declared - * at the end of CAS/client.php). - */ - -class phpCAS { - - // ######################################################################## - // INITIALIZATION - // ######################################################################## - - /** - * @addtogroup publicInit - * @{ - */ - - /** - * phpCAS client initializer. - * @note Only one of the phpCAS::client() and phpCAS::proxy functions should be - * called, only once, and before all other methods (except phpCAS::getVersion() - * and phpCAS::setDebug()). - * - * @param $server_version the version of the CAS server - * @param $server_hostname the hostname of the CAS server - * @param $server_port the port the CAS server is running on - * @param $server_uri the URI the CAS server is responding on - * @param $start_session Have phpCAS start PHP sessions (default true) - * - * @return a newly created CASClient object - */ - function client($server_version, $server_hostname, $server_port, $server_uri, $start_session = true) { - global $PHPCAS_CLIENT, $PHPCAS_INIT_CALL; - - phpCAS :: traceBegin(); - if (is_object($PHPCAS_CLIENT)) { - phpCAS :: error($PHPCAS_INIT_CALL['method'] . '() has already been called (at ' . $PHPCAS_INIT_CALL['file'] . ':' . $PHPCAS_INIT_CALL['line'] . ')'); - } - if (gettype($server_version) != 'string') { - phpCAS :: error('type mismatched for parameter $server_version (should be `string\')'); - } - if (gettype($server_hostname) != 'string') { - phpCAS :: error('type mismatched for parameter $server_hostname (should be `string\')'); - } - if (gettype($server_port) != 'integer') { - phpCAS :: error('type mismatched for parameter $server_port (should be `integer\')'); - } - if (gettype($server_uri) != 'string') { - phpCAS :: error('type mismatched for parameter $server_uri (should be `string\')'); - } - - // store where the initializer is called from - $dbg = phpCAS :: backtrace(); - $PHPCAS_INIT_CALL = array ( - 'done' => TRUE, - 'file' => $dbg[0]['file'], - 'line' => $dbg[0]['line'], - 'method' => __CLASS__ . '::' . __FUNCTION__ - ); - - // initialize the global object $PHPCAS_CLIENT - $PHPCAS_CLIENT = new CASClient($server_version, FALSE /*proxy*/ - , $server_hostname, $server_port, $server_uri, $start_session); - phpCAS :: traceEnd(); - } - - /** - * phpCAS proxy initializer. - * @note Only one of the phpCAS::client() and phpCAS::proxy functions should be - * called, only once, and before all other methods (except phpCAS::getVersion() - * and phpCAS::setDebug()). - * - * @param $server_version the version of the CAS server - * @param $server_hostname the hostname of the CAS server - * @param $server_port the port the CAS server is running on - * @param $server_uri the URI the CAS server is responding on - * @param $start_session Have phpCAS start PHP sessions (default true) - * - * @return a newly created CASClient object - */ - function proxy($server_version, $server_hostname, $server_port, $server_uri, $start_session = true) { - global $PHPCAS_CLIENT, $PHPCAS_INIT_CALL; - - phpCAS :: traceBegin(); - if (is_object($PHPCAS_CLIENT)) { - phpCAS :: error($PHPCAS_INIT_CALL['method'] . '() has already been called (at ' . $PHPCAS_INIT_CALL['file'] . ':' . $PHPCAS_INIT_CALL['line'] . ')'); - } - if (gettype($server_version) != 'string') { - phpCAS :: error('type mismatched for parameter $server_version (should be `string\')'); - } - if (gettype($server_hostname) != 'string') { - phpCAS :: error('type mismatched for parameter $server_hostname (should be `string\')'); - } - if (gettype($server_port) != 'integer') { - phpCAS :: error('type mismatched for parameter $server_port (should be `integer\')'); - } - if (gettype($server_uri) != 'string') { - phpCAS :: error('type mismatched for parameter $server_uri (should be `string\')'); - } - - // store where the initialzer is called from - $dbg = phpCAS :: backtrace(); - $PHPCAS_INIT_CALL = array ( - 'done' => TRUE, - 'file' => $dbg[0]['file'], - 'line' => $dbg[0]['line'], - 'method' => __CLASS__ . '::' . __FUNCTION__ - ); - - // initialize the global object $PHPCAS_CLIENT - $PHPCAS_CLIENT = new CASClient($server_version, TRUE /*proxy*/ - , $server_hostname, $server_port, $server_uri, $start_session); - phpCAS :: traceEnd(); - } - - /** @} */ - // ######################################################################## - // DEBUGGING - // ######################################################################## - - /** - * @addtogroup publicDebug - * @{ - */ - - /** - * Set/unset debug mode - * - * @param $filename the name of the file used for logging, or FALSE to stop debugging. - */ - function setDebug($filename = '') { - global $PHPCAS_DEBUG; - - if ($filename != FALSE && gettype($filename) != 'string') { - phpCAS :: error('type mismatched for parameter $dbg (should be FALSE or the name of the log file)'); - } - - if (empty ($filename)) { - if (preg_match('/^Win.*/', getenv('OS'))) { - if (isset ($_ENV['TMP'])) { - $debugDir = $_ENV['TMP'] . '/'; - } else - if (isset ($_ENV['TEMP'])) { - $debugDir = $_ENV['TEMP'] . '/'; - } else { - $debugDir = ''; - } - } else { - $debugDir = DEFAULT_DEBUG_DIR; - } - $filename = $debugDir . 'phpCAS.log'; - } - - if (empty ($PHPCAS_DEBUG['unique_id'])) { - $PHPCAS_DEBUG['unique_id'] = substr(strtoupper(md5(uniqid(''))), 0, 4); - } - - $PHPCAS_DEBUG['filename'] = $filename; - - phpCAS :: trace('START phpCAS-' . PHPCAS_VERSION . ' ******************'); - } - - /** @} */ - /** - * @addtogroup internalDebug - * @{ - */ - - /** - * This method is a wrapper for debug_backtrace() that is not available - * in all PHP versions (>= 4.3.0 only) - */ - function backtrace() { - if (function_exists('debug_backtrace')) { - return debug_backtrace(); - } else { - // poor man's hack ... but it does work ... - return array (); - } - } - - /** - * Logs a string in debug mode. - * - * @param $str the string to write - * - * @private - */ - function log($str) { - $indent_str = "."; - global $PHPCAS_DEBUG; - - if ($PHPCAS_DEBUG['filename']) { - for ($i = 0; $i < $PHPCAS_DEBUG['indent']; $i++) { - $indent_str .= '| '; - } - error_log($PHPCAS_DEBUG['unique_id'] . ' ' . $indent_str . $str . "\n", 3, $PHPCAS_DEBUG['filename']); - } - - } - - /** - * This method is used by interface methods to print an error and where the function - * was originally called from. - * - * @param $msg the message to print - * - * @private - */ - function error($msg) { - $dbg = phpCAS :: backtrace(); - $function = '?'; - $file = '?'; - $line = '?'; - if (is_array($dbg)) { - for ($i = 1; $i < sizeof($dbg); $i++) { - if (is_array($dbg[$i])) { - if ($dbg[$i]['class'] == __CLASS__) { - $function = $dbg[$i]['function']; - $file = $dbg[$i]['file']; - $line = $dbg[$i]['line']; - } - } - } - } - echo "
\nphpCAS error: " . __CLASS__ . "::" . $function . '(): ' . htmlentities($msg) . " in " . $file . " on line " . $line . "
\n"; - phpCAS :: trace($msg); - phpCAS :: traceExit(); - exit (); - } - - /** - * This method is used to log something in debug mode. - */ - function trace($str) { - $dbg = phpCAS :: backtrace(); - phpCAS :: log($str . ' [' . basename($dbg[1]['file']) . ':' . $dbg[1]['line'] . ']'); - } - - /** - * This method is used to indicate the start of the execution of a function in debug mode. - */ - function traceBegin() { - global $PHPCAS_DEBUG; - - $dbg = phpCAS :: backtrace(); - $str = '=> '; - if (!empty ($dbg[2]['class'])) { - $str .= $dbg[2]['class'] . '::'; - } - $str .= $dbg[2]['function'] . '('; - if (is_array($dbg[2]['args'])) { - foreach ($dbg[2]['args'] as $index => $arg) { - if ($index != 0) { - $str .= ', '; - } - $str .= str_replace("\n", "", var_export($arg, TRUE)); - } - } - $str .= ') [' . basename($dbg[2]['file']) . ':' . $dbg[2]['line'] . ']'; - phpCAS :: log($str); - $PHPCAS_DEBUG['indent']++; - } - - /** - * This method is used to indicate the end of the execution of a function in debug mode. - * - * @param $res the result of the function - */ - function traceEnd($res = '') { - global $PHPCAS_DEBUG; - - $PHPCAS_DEBUG['indent']--; - $dbg = phpCAS :: backtrace(); - $str = ''; - $str .= '<= ' . str_replace("\n", "", var_export($res, TRUE)); - phpCAS :: log($str); - } - - /** - * This method is used to indicate the end of the execution of the program - */ - function traceExit() { - global $PHPCAS_DEBUG; - - phpCAS :: log('exit()'); - while ($PHPCAS_DEBUG['indent'] > 0) { - phpCAS :: log('-'); - $PHPCAS_DEBUG['indent']--; - } - } - - /** @} */ - // ######################################################################## - // INTERNATIONALIZATION - // ######################################################################## - /** - * @addtogroup publicLang - * @{ - */ - - /** - * This method is used to set the language used by phpCAS. - * @note Can be called only once. - * - * @param $lang a string representing the language. - * - * @sa PHPCAS_LANG_FRENCH, PHPCAS_LANG_ENGLISH - */ - function setLang($lang) { - global $PHPCAS_CLIENT; - if (!is_object($PHPCAS_CLIENT)) { - phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()'); - } - if (gettype($lang) != 'string') { - phpCAS :: error('type mismatched for parameter $lang (should be `string\')'); - } - $PHPCAS_CLIENT->setLang($lang); - } - - /** @} */ - // ######################################################################## - // VERSION - // ######################################################################## - /** - * @addtogroup public - * @{ - */ - - /** - * This method returns the phpCAS version. - * - * @return the phpCAS version. - */ - function getVersion() { - return PHPCAS_VERSION; - } - - /** @} */ - // ######################################################################## - // HTML OUTPUT - // ######################################################################## - /** - * @addtogroup publicOutput - * @{ - */ - - /** - * This method sets the HTML header used for all outputs. - * - * @param $header the HTML header. - */ - function setHTMLHeader($header) { - global $PHPCAS_CLIENT; - if (!is_object($PHPCAS_CLIENT)) { - phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()'); - } - if (gettype($header) != 'string') { - phpCAS :: error('type mismatched for parameter $header (should be `string\')'); - } - $PHPCAS_CLIENT->setHTMLHeader($header); - } - - /** - * This method sets the HTML footer used for all outputs. - * - * @param $footer the HTML footer. - */ - function setHTMLFooter($footer) { - global $PHPCAS_CLIENT; - if (!is_object($PHPCAS_CLIENT)) { - phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()'); - } - if (gettype($footer) != 'string') { - phpCAS :: error('type mismatched for parameter $footer (should be `string\')'); - } - $PHPCAS_CLIENT->setHTMLFooter($footer); - } - - /** @} */ - // ######################################################################## - // PGT STORAGE - // ######################################################################## - /** - * @addtogroup publicPGTStorage - * @{ - */ - - /** - * This method is used to tell phpCAS to store the response of the - * CAS server to PGT requests onto the filesystem. - * - * @param $format the format used to store the PGT's (`plain' and `xml' allowed) - * @param $path the path where the PGT's should be stored - */ - function setPGTStorageFile($format = '', $path = '') { - global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL; - - phpCAS :: traceBegin(); - if (!is_object($PHPCAS_CLIENT)) { - phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()'); - } - if (!$PHPCAS_CLIENT->isProxy()) { - phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()'); - } - if ($PHPCAS_AUTH_CHECK_CALL['done']) { - phpCAS :: error('this method should only be called before ' . $PHPCAS_AUTH_CHECK_CALL['method'] . '() (called at ' . $PHPCAS_AUTH_CHECK_CALL['file'] . ':' . $PHPCAS_AUTH_CHECK_CALL['line'] . ')'); - } - if (gettype($format) != 'string') { - phpCAS :: error('type mismatched for parameter $format (should be `string\')'); - } - if (gettype($path) != 'string') { - phpCAS :: error('type mismatched for parameter $format (should be `string\')'); - } - $PHPCAS_CLIENT->setPGTStorageFile($format, $path); - phpCAS :: traceEnd(); - } - - /** - * This method is used to tell phpCAS to store the response of the - * CAS server to PGT requests into a database. - * @note The connection to the database is done only when needed. - * As a consequence, bad parameters are detected only when - * initializing PGT storage, except in debug mode. - * - * @param $user the user to access the data with - * @param $password the user's password - * @param $database_type the type of the database hosting the data - * @param $hostname the server hosting the database - * @param $port the port the server is listening on - * @param $database the name of the database - * @param $table the name of the table storing the data - */ - function setPGTStorageDB($user, $password, $database_type = '', $hostname = '', $port = 0, $database = '', $table = '') { - global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL; - - phpCAS :: traceBegin(); - if (!is_object($PHPCAS_CLIENT)) { - phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()'); - } - if (!$PHPCAS_CLIENT->isProxy()) { - phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()'); - } - if ($PHPCAS_AUTH_CHECK_CALL['done']) { - phpCAS :: error('this method should only be called before ' . $PHPCAS_AUTH_CHECK_CALL['method'] . '() (called at ' . $PHPCAS_AUTH_CHECK_CALL['file'] . ':' . $PHPCAS_AUTH_CHECK_CALL['line'] . ')'); - } - if (gettype($user) != 'string') { - phpCAS :: error('type mismatched for parameter $user (should be `string\')'); - } - if (gettype($password) != 'string') { - phpCAS :: error('type mismatched for parameter $password (should be `string\')'); - } - if (gettype($database_type) != 'string') { - phpCAS :: error('type mismatched for parameter $database_type (should be `string\')'); - } - if (gettype($hostname) != 'string') { - phpCAS :: error('type mismatched for parameter $hostname (should be `string\')'); - } - if (gettype($port) != 'integer') { - phpCAS :: error('type mismatched for parameter $port (should be `integer\')'); - } - if (gettype($database) != 'string') { - phpCAS :: error('type mismatched for parameter $database (should be `string\')'); - } - if (gettype($table) != 'string') { - phpCAS :: error('type mismatched for parameter $table (should be `string\')'); - } - $PHPCAS_CLIENT->setPGTStorageDB($user, $password, $database_type, $hostname, $port, $database, $table); - phpCAS :: traceEnd(); - } - - /** @} */ - // ######################################################################## - // ACCESS TO EXTERNAL SERVICES - // ######################################################################## - /** - * @addtogroup publicServices - * @{ - */ - - /** - * This method is used to access an HTTP[S] service. - * - * @param $url the service to access. - * @param $err_code an error code Possible values are PHPCAS_SERVICE_OK (on - * success), PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE, PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE, - * PHPCAS_SERVICE_PT_FAILURE, PHPCAS_SERVICE_NOT AVAILABLE. - * @param $output the output of the service (also used to give an error - * message on failure). - * - * @return TRUE on success, FALSE otherwise (in this later case, $err_code - * gives the reason why it failed and $output contains an error message). - */ - function serviceWeb($url, & $err_code, & $output) { - global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL; - - phpCAS :: traceBegin(); - if (!is_object($PHPCAS_CLIENT)) { - phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()'); - } - if (!$PHPCAS_CLIENT->isProxy()) { - phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()'); - } - if (!$PHPCAS_AUTH_CHECK_CALL['done']) { - phpCAS :: error('this method should only be called after the programmer is sure the user has been authenticated (by calling ' . __CLASS__ . '::checkAuthentication() or ' . __CLASS__ . '::forceAuthentication()'); - } - if (!$PHPCAS_AUTH_CHECK_CALL['result']) { - phpCAS :: error('authentication was checked (by ' . $PHPCAS_AUTH_CHECK_CALL['method'] . '() at ' . $PHPCAS_AUTH_CHECK_CALL['file'] . ':' . $PHPCAS_AUTH_CHECK_CALL['line'] . ') but the method returned FALSE'); - } - if (gettype($url) != 'string') { - phpCAS :: error('type mismatched for parameter $url (should be `string\')'); - } - - $res = $PHPCAS_CLIENT->serviceWeb($url, $err_code, $output); - - phpCAS :: traceEnd($res); - return $res; - } - - /** - * This method is used to access an IMAP/POP3/NNTP service. - * - * @param $url a string giving the URL of the service, including the mailing box - * for IMAP URLs, as accepted by imap_open(). - * @param $service a string giving for CAS retrieve Proxy ticket - * @param $flags options given to imap_open(). - * @param $err_code an error code Possible values are PHPCAS_SERVICE_OK (on - * success), PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE, PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE, - * PHPCAS_SERVICE_PT_FAILURE, PHPCAS_SERVICE_NOT AVAILABLE. - * @param $err_msg an error message on failure - * @param $pt the Proxy Ticket (PT) retrieved from the CAS server to access the URL - * on success, FALSE on error). - * - * @return an IMAP stream on success, FALSE otherwise (in this later case, $err_code - * gives the reason why it failed and $err_msg contains an error message). - */ - function serviceMail($url, $service, $flags, & $err_code, & $err_msg, & $pt) { - global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL; - - phpCAS :: traceBegin(); - if (!is_object($PHPCAS_CLIENT)) { - phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()'); - } - if (!$PHPCAS_CLIENT->isProxy()) { - phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()'); - } - if (!$PHPCAS_AUTH_CHECK_CALL['done']) { - phpCAS :: error('this method should only be called after the programmer is sure the user has been authenticated (by calling ' . __CLASS__ . '::checkAuthentication() or ' . __CLASS__ . '::forceAuthentication()'); - } - if (!$PHPCAS_AUTH_CHECK_CALL['result']) { - phpCAS :: error('authentication was checked (by ' . $PHPCAS_AUTH_CHECK_CALL['method'] . '() at ' . $PHPCAS_AUTH_CHECK_CALL['file'] . ':' . $PHPCAS_AUTH_CHECK_CALL['line'] . ') but the method returned FALSE'); - } - if (gettype($url) != 'string') { - phpCAS :: error('type mismatched for parameter $url (should be `string\')'); - } - - if (gettype($flags) != 'integer') { - phpCAS :: error('type mismatched for parameter $flags (should be `integer\')'); - } - - $res = $PHPCAS_CLIENT->serviceMail($url, $service, $flags, $err_code, $err_msg, $pt); - - phpCAS :: traceEnd($res); - return $res; - } - - /** @} */ - // ######################################################################## - // AUTHENTICATION - // ######################################################################## - /** - * @addtogroup publicAuth - * @{ - */ - - /** - * Set the times authentication will be cached before really accessing the CAS server in gateway mode: - * - -1: check only once, and then never again (until you pree login) - * - 0: always check - * - n: check every "n" time - * - * @param $n an integer. - */ - function setCacheTimesForAuthRecheck($n) { - global $PHPCAS_CLIENT; - if (!is_object($PHPCAS_CLIENT)) { - phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()'); - } - if (gettype($n) != 'integer') { - phpCAS :: error('type mismatched for parameter $header (should be `string\')'); - } - $PHPCAS_CLIENT->setCacheTimesForAuthRecheck($n); - } - - /** - * This method is called to check if the user is authenticated (use the gateway feature). - * @return TRUE when the user is authenticated; otherwise FALSE. - */ - function checkAuthentication() { - global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL; - - phpCAS :: traceBegin(); - if (!is_object($PHPCAS_CLIENT)) { - phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()'); - } - - $auth = $PHPCAS_CLIENT->checkAuthentication(); - - // store where the authentication has been checked and the result - $dbg = phpCAS :: backtrace(); - $PHPCAS_AUTH_CHECK_CALL = array ( - 'done' => TRUE, - 'file' => $dbg[0]['file'], - 'line' => $dbg[0]['line'], - 'method' => __CLASS__ . '::' . __FUNCTION__, - 'result' => $auth - ); - phpCAS :: traceEnd($auth); - return $auth; - } - - /** - * This method is called to force authentication if the user was not already - * authenticated. If the user is not authenticated, halt by redirecting to - * the CAS server. - */ - function forceAuthentication() { - global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL; - - phpCAS :: traceBegin(); - if (!is_object($PHPCAS_CLIENT)) { - phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()'); - } - - $auth = $PHPCAS_CLIENT->forceAuthentication(); - - // store where the authentication has been checked and the result - $dbg = phpCAS :: backtrace(); - $PHPCAS_AUTH_CHECK_CALL = array ( - 'done' => TRUE, - 'file' => $dbg[0]['file'], - 'line' => $dbg[0]['line'], - 'method' => __CLASS__ . '::' . __FUNCTION__, - 'result' => $auth - ); - - if (!$auth) { - phpCAS :: trace('user is not authenticated, redirecting to the CAS server'); - $PHPCAS_CLIENT->forceAuthentication(); - } else { - phpCAS :: trace('no need to authenticate (user `' . phpCAS :: getUser() . '\' is already authenticated)'); - } - - phpCAS :: traceEnd(); - return $auth; - } - - /** - * This method is called to renew the authentication. - **/ - function renewAuthentication() { - global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL; - - phpCAS :: traceBegin(); - if (!is_object($PHPCAS_CLIENT)) { - phpCAS :: error('this method should not be called before' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()'); - } - - // store where the authentication has been checked and the result - $dbg = phpCAS :: backtrace(); - $PHPCAS_AUTH_CHECK_CALL = array ( - 'done' => TRUE, - 'file' => $dbg[0]['file'], - 'line' => $dbg[0]['line'], - 'method' => __CLASS__ . '::' . __FUNCTION__, - 'result' => $auth - ); - - $PHPCAS_CLIENT->renewAuthentication(); - phpCAS :: traceEnd(); - } - - /** - * This method has been left from version 0.4.1 for compatibility reasons. - */ - function authenticate() { - phpCAS :: error('this method is deprecated. You should use ' . __CLASS__ . '::forceAuthentication() instead'); - } - - /** - * This method is called to check if the user is authenticated (previously or by - * tickets given in the URL). - * - * @return TRUE when the user is authenticated. - */ - function isAuthenticated() { - global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL; - - phpCAS :: traceBegin(); - if (!is_object($PHPCAS_CLIENT)) { - phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()'); - } - - // call the isAuthenticated method of the global $PHPCAS_CLIENT object - $auth = $PHPCAS_CLIENT->isAuthenticated(); - - // store where the authentication has been checked and the result - $dbg = phpCAS :: backtrace(); - $PHPCAS_AUTH_CHECK_CALL = array ( - 'done' => TRUE, - 'file' => $dbg[0]['file'], - 'line' => $dbg[0]['line'], - 'method' => __CLASS__ . '::' . __FUNCTION__, - 'result' => $auth - ); - phpCAS :: traceEnd($auth); - return $auth; - } - - /** - * Checks whether authenticated based on $_SESSION. Useful to avoid - * server calls. - * @return true if authenticated, false otherwise. - * @since 0.4.22 by Brendan Arnold - */ - function isSessionAuthenticated() { - global $PHPCAS_CLIENT; - if (!is_object($PHPCAS_CLIENT)) { - phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()'); - } - return ($PHPCAS_CLIENT->isSessionAuthenticated()); - } - - /** - * This method returns the CAS user's login name. - * @warning should not be called only after phpCAS::forceAuthentication() - * or phpCAS::checkAuthentication(). - * - * @return the login name of the authenticated user - */ - function getUser() { - global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL; - if (!is_object($PHPCAS_CLIENT)) { - phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()'); - } - if (!$PHPCAS_AUTH_CHECK_CALL['done']) { - phpCAS :: error('this method should only be called after ' . __CLASS__ . '::forceAuthentication() or ' . __CLASS__ . '::isAuthenticated()'); - } - if (!$PHPCAS_AUTH_CHECK_CALL['result']) { - phpCAS :: error('authentication was checked (by ' . $PHPCAS_AUTH_CHECK_CALL['method'] . '() at ' . $PHPCAS_AUTH_CHECK_CALL['file'] . ':' . $PHPCAS_AUTH_CHECK_CALL['line'] . ') but the method returned FALSE'); - } - return $PHPCAS_CLIENT->getUser(); - } - - /** - * This method returns the CAS user's login name. - * @warning should not be called only after phpCAS::forceAuthentication() - * or phpCAS::checkAuthentication(). - * - * @return the login name of the authenticated user - */ - function getAttributes() { - global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL; - if (!is_object($PHPCAS_CLIENT)) { - phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()'); - } - if (!$PHPCAS_AUTH_CHECK_CALL['done']) { - phpCAS :: error('this method should only be called after ' . __CLASS__ . '::forceAuthentication() or ' . __CLASS__ . '::isAuthenticated()'); - } - if (!$PHPCAS_AUTH_CHECK_CALL['result']) { - phpCAS :: error('authentication was checked (by ' . $PHPCAS_AUTH_CHECK_CALL['method'] . '() at ' . $PHPCAS_AUTH_CHECK_CALL['file'] . ':' . $PHPCAS_AUTH_CHECK_CALL['line'] . ') but the method returned FALSE'); - } - return $PHPCAS_CLIENT->getAttributes(); - } - /** - * Handle logout requests. - */ - function handleLogoutRequests($check_client = true, $allowed_clients = false) { - global $PHPCAS_CLIENT; - if (!is_object($PHPCAS_CLIENT)) { - phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()'); - } - return ($PHPCAS_CLIENT->handleLogoutRequests($check_client, $allowed_clients)); - } - - /** - * This method returns the URL to be used to login. - * or phpCAS::isAuthenticated(). - * - * @return the login name of the authenticated user - */ - function getServerLoginURL() { - global $PHPCAS_CLIENT; - if (!is_object($PHPCAS_CLIENT)) { - phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()'); - } - return $PHPCAS_CLIENT->getServerLoginURL(); - } - - /** - * Set the login URL of the CAS server. - * @param $url the login URL - * @since 0.4.21 by Wyman Chan - */ - function setServerLoginURL($url = '') { - global $PHPCAS_CLIENT; - phpCAS :: traceBegin(); - if (!is_object($PHPCAS_CLIENT)) { - phpCAS :: error('this method should only be called after - ' . __CLASS__ . '::client()'); - } - if (gettype($url) != 'string') { - phpCAS :: error('type mismatched for parameter $url (should be - `string\')'); - } - $PHPCAS_CLIENT->setServerLoginURL($url); - phpCAS :: traceEnd(); - } - - /** - * Set the serviceValidate URL of the CAS server. - * Used only in CAS 1.0 validations - * @param $url the serviceValidate URL - * @since 1.1.0 by Joachim Fritschi - */ - function setServerServiceValidateURL($url = '') { - global $PHPCAS_CLIENT; - phpCAS :: traceBegin(); - if (!is_object($PHPCAS_CLIENT)) { - phpCAS :: error('this method should only be called after - ' . __CLASS__ . '::client()'); - } - if (gettype($url) != 'string') { - phpCAS :: error('type mismatched for parameter $url (should be - `string\')'); - } - $PHPCAS_CLIENT->setServerServiceValidateURL($url); - phpCAS :: traceEnd(); - } - - /** - * Set the proxyValidate URL of the CAS server. - * Used for all CAS 2.0 validations - * @param $url the proxyValidate URL - * @since 1.1.0 by Joachim Fritschi - */ - function setServerProxyValidateURL($url = '') { - global $PHPCAS_CLIENT; - phpCAS :: traceBegin(); - if (!is_object($PHPCAS_CLIENT)) { - phpCAS :: error('this method should only be called after - ' . __CLASS__ . '::client()'); - } - if (gettype($url) != 'string') { - phpCAS :: error('type mismatched for parameter $url (should be - `string\')'); - } - $PHPCAS_CLIENT->setServerProxyValidateURL($url); - phpCAS :: traceEnd(); - } - - /** - * Set the samlValidate URL of the CAS server. - * @param $url the samlValidate URL - * @since 1.1.0 by Joachim Fritschi - */ - function setServerSamlValidateURL($url = '') { - global $PHPCAS_CLIENT; - phpCAS :: traceBegin(); - if (!is_object($PHPCAS_CLIENT)) { - phpCAS :: error('this method should only be called after - ' . __CLASS__ . '::client()'); - } - if (gettype($url) != 'string') { - phpCAS :: error('type mismatched for parameter $url (should be - `string\')'); - } - $PHPCAS_CLIENT->setServerSamlValidateURL($url); - phpCAS :: traceEnd(); - } - - /** - * This method returns the URL to be used to login. - * or phpCAS::isAuthenticated(). - * - * @return the login name of the authenticated user - */ - function getServerLogoutURL() { - global $PHPCAS_CLIENT; - if (!is_object($PHPCAS_CLIENT)) { - phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()'); - } - return $PHPCAS_CLIENT->getServerLogoutURL(); - } - - /** - * Set the logout URL of the CAS server. - * @param $url the logout URL - * @since 0.4.21 by Wyman Chan - */ - function setServerLogoutURL($url = '') { - global $PHPCAS_CLIENT; - phpCAS :: traceBegin(); - if (!is_object($PHPCAS_CLIENT)) { - phpCAS :: error('this method should only be called after - ' . __CLASS__ . '::client()'); - } - if (gettype($url) != 'string') { - phpCAS :: error('type mismatched for parameter $url (should be - `string\')'); - } - $PHPCAS_CLIENT->setServerLogoutURL($url); - phpCAS :: traceEnd(); - } - - /** - * This method is used to logout from CAS. - * @params $params an array that contains the optional url and service parameters that will be passed to the CAS server - * @public - */ - function logout($params = "") { - global $PHPCAS_CLIENT; - phpCAS :: traceBegin(); - if (!is_object($PHPCAS_CLIENT)) { - phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()'); - } - $parsedParams = array (); - if ($params != "") { - if (is_string($params)) { - phpCAS :: error('method `phpCAS::logout($url)\' is now deprecated, use `phpCAS::logoutWithUrl($url)\' instead'); - } - if (!is_array($params)) { - phpCAS :: error('type mismatched for parameter $params (should be `array\')'); - } - foreach ($params as $key => $value) { - if ($key != "service" && $key != "url") { - phpCAS :: error('only `url\' and `service\' parameters are allowed for method `phpCAS::logout($params)\''); - } - $parsedParams[$key] = $value; - } - } - $PHPCAS_CLIENT->logout($parsedParams); - // never reached - phpCAS :: traceEnd(); - } - - /** - * This method is used to logout from CAS. Halts by redirecting to the CAS server. - * @param $service a URL that will be transmitted to the CAS server - */ - function logoutWithRedirectService($service) { - global $PHPCAS_CLIENT; - phpCAS :: traceBegin(); - if (!is_object($PHPCAS_CLIENT)) { - phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()'); - } - if (!is_string($service)) { - phpCAS :: error('type mismatched for parameter $service (should be `string\')'); - } - $PHPCAS_CLIENT->logout(array ( - "service" => $service - )); - // never reached - phpCAS :: traceEnd(); - } - - /** - * This method is used to logout from CAS. Halts by redirecting to the CAS server. - * @param $url a URL that will be transmitted to the CAS server - */ - function logoutWithUrl($url) { - global $PHPCAS_CLIENT; - phpCAS :: traceBegin(); - if (!is_object($PHPCAS_CLIENT)) { - phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()'); - } - if (!is_string($url)) { - phpCAS :: error('type mismatched for parameter $url (should be `string\')'); - } - $PHPCAS_CLIENT->logout(array ( - "url" => $url - )); - // never reached - phpCAS :: traceEnd(); - } - - /** - * This method is used to logout from CAS. Halts by redirecting to the CAS server. - * @param $service a URL that will be transmitted to the CAS server - * @param $url a URL that will be transmitted to the CAS server - */ - function logoutWithRedirectServiceAndUrl($service, $url) { - global $PHPCAS_CLIENT; - phpCAS :: traceBegin(); - if (!is_object($PHPCAS_CLIENT)) { - phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()'); - } - if (!is_string($service)) { - phpCAS :: error('type mismatched for parameter $service (should be `string\')'); - } - if (!is_string($url)) { - phpCAS :: error('type mismatched for parameter $url (should be `string\')'); - } - $PHPCAS_CLIENT->logout(array ( - "service" => $service, - "url" => $url - )); - // never reached - phpCAS :: traceEnd(); - } - - /** - * Set the fixed URL that will be used by the CAS server to transmit the PGT. - * When this method is not called, a phpCAS script uses its own URL for the callback. - * - * @param $url the URL - */ - function setFixedCallbackURL($url = '') { - global $PHPCAS_CLIENT; - phpCAS :: traceBegin(); - if (!is_object($PHPCAS_CLIENT)) { - phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()'); - } - if (!$PHPCAS_CLIENT->isProxy()) { - phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()'); - } - if (gettype($url) != 'string') { - phpCAS :: error('type mismatched for parameter $url (should be `string\')'); - } - $PHPCAS_CLIENT->setCallbackURL($url); - phpCAS :: traceEnd(); - } - - /** - * Set the fixed URL that will be set as the CAS service parameter. When this - * method is not called, a phpCAS script uses its own URL. - * - * @param $url the URL - */ - function setFixedServiceURL($url) { - global $PHPCAS_CLIENT; - phpCAS :: traceBegin(); - if (!is_object($PHPCAS_CLIENT)) { - phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()'); - } - if (gettype($url) != 'string') { - phpCAS :: error('type mismatched for parameter $url (should be `string\')'); - } - $PHPCAS_CLIENT->setURL($url); - phpCAS :: traceEnd(); - } - - /** - * Get the URL that is set as the CAS service parameter. - */ - function getServiceURL() { - global $PHPCAS_CLIENT; - if (!is_object($PHPCAS_CLIENT)) { - phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()'); - } - return ($PHPCAS_CLIENT->getURL()); - } - - /** - * Retrieve a Proxy Ticket from the CAS server. - */ - function retrievePT($target_service, & $err_code, & $err_msg) { - global $PHPCAS_CLIENT; - if (!is_object($PHPCAS_CLIENT)) { - phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()'); - } - if (gettype($target_service) != 'string') { - phpCAS :: error('type mismatched for parameter $target_service(should be `string\')'); - } - return ($PHPCAS_CLIENT->retrievePT($target_service, $err_code, $err_msg)); - } - - /** - * Set the certificate of the CAS server. - * - * @param $cert the PEM certificate - */ - function setCasServerCert($cert) { - global $PHPCAS_CLIENT; - phpCAS :: traceBegin(); - if (!is_object($PHPCAS_CLIENT)) { - phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()'); - } - if (gettype($cert) != 'string') { - phpCAS :: error('type mismatched for parameter $cert (should be `string\')'); - } - $PHPCAS_CLIENT->setCasServerCert($cert); - phpCAS :: traceEnd(); - } - - /** - * Set the certificate of the CAS server CA. - * - * @param $cert the CA certificate - */ - function setCasServerCACert($cert) { - global $PHPCAS_CLIENT; - phpCAS :: traceBegin(); - if (!is_object($PHPCAS_CLIENT)) { - phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()'); - } - if (gettype($cert) != 'string') { - phpCAS :: error('type mismatched for parameter $cert (should be `string\')'); - } - $PHPCAS_CLIENT->setCasServerCACert($cert); - phpCAS :: traceEnd(); - } - - /** - * Set no SSL validation for the CAS server. - */ - function setNoCasServerValidation() { - global $PHPCAS_CLIENT; - phpCAS :: traceBegin(); - if (!is_object($PHPCAS_CLIENT)) { - phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()'); - } - $PHPCAS_CLIENT->setNoCasServerValidation(); - phpCAS :: traceEnd(); - } - - /** @} */ - - /** - * Change CURL options. - * CURL is used to connect through HTTPS to CAS server - * @param $key the option key - * @param $value the value to set - */ - function setExtraCurlOption($key, $value) { - global $PHPCAS_CLIENT; - phpCAS :: traceBegin(); - if (!is_object($PHPCAS_CLIENT)) { - phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()'); - } - $PHPCAS_CLIENT->setExtraCurlOption($key, $value); - phpCAS :: traceEnd(); - } - -} - -// ######################################################################## -// DOCUMENTATION -// ######################################################################## - -// ######################################################################## -// MAIN PAGE - -/** - * @mainpage - * - * The following pages only show the source documentation. - * - */ - -// ######################################################################## -// MODULES DEFINITION - -/** @defgroup public User interface */ - -/** @defgroup publicInit Initialization - * @ingroup public */ - -/** @defgroup publicAuth Authentication - * @ingroup public */ - -/** @defgroup publicServices Access to external services - * @ingroup public */ - -/** @defgroup publicConfig Configuration - * @ingroup public */ - -/** @defgroup publicLang Internationalization - * @ingroup publicConfig */ - -/** @defgroup publicOutput HTML output - * @ingroup publicConfig */ - -/** @defgroup publicPGTStorage PGT storage - * @ingroup publicConfig */ - -/** @defgroup publicDebug Debugging - * @ingroup public */ - -/** @defgroup internal Implementation */ - -/** @defgroup internalAuthentication Authentication - * @ingroup internal */ - -/** @defgroup internalBasic CAS Basic client features (CAS 1.0, Service Tickets) - * @ingroup internal */ - -/** @defgroup internalProxy CAS Proxy features (CAS 2.0, Proxy Granting Tickets) - * @ingroup internal */ - -/** @defgroup internalPGTStorage PGT storage - * @ingroup internalProxy */ - -/** @defgroup internalPGTStorageDB PGT storage in a database - * @ingroup internalPGTStorage */ - -/** @defgroup internalPGTStorageFile PGT storage on the filesystem - * @ingroup internalPGTStorage */ - -/** @defgroup internalCallback Callback from the CAS server - * @ingroup internalProxy */ - -/** @defgroup internalProxied CAS proxied client features (CAS 2.0, Proxy Tickets) - * @ingroup internal */ - -/** @defgroup internalConfig Configuration - * @ingroup internal */ - -/** @defgroup internalOutput HTML output - * @ingroup internalConfig */ - -/** @defgroup internalLang Internationalization - * @ingroup internalConfig - * - * To add a new language: - * - 1. define a new constant PHPCAS_LANG_XXXXXX in CAS/CAS.php - * - 2. copy any file from CAS/languages to CAS/languages/XXXXXX.php - * - 3. Make the translations - */ - -/** @defgroup internalDebug Debugging - * @ingroup internal */ - -/** @defgroup internalMisc Miscellaneous - * @ingroup internal */ - -// ######################################################################## -// EXAMPLES - -/** - * @example example_simple.php - */ -/** - * @example example_proxy.php - */ -/** - * @example example_proxy2.php - */ -/** - * @example example_lang.php - */ -/** - * @example example_html.php - */ -/** - * @example example_file.php - */ -/** - * @example example_db.php - */ -/** - * @example example_service.php - */ -/** - * @example example_session_proxy.php - */ -/** - * @example example_session_service.php - */ -/** - * @example example_gateway.php - */ -/** - * @example example_custom_urls.php - */ -?> diff --git a/plugins/CasAuthentication/extlib/CAS/PGTStorage/pgt-db.php b/plugins/CasAuthentication/extlib/CAS/PGTStorage/pgt-db.php deleted file mode 100644 index 1e316b6f6a..0000000000 --- a/plugins/CasAuthentication/extlib/CAS/PGTStorage/pgt-db.php +++ /dev/null @@ -1,218 +0,0 @@ - - * - * @ingroup internalPGTStorageDB - */ - -class PGTStorageDB extends PGTStorage -{ - /** - * @addtogroup internalPGTStorageDB - * @{ - */ - - /** - * a string representing a PEAR DB URL to connect to the database. Written by - * PGTStorageDB::PGTStorageDB(), read by getURL(). - * - * @hideinitializer - * @private - */ - var $_url=''; - - /** - * This method returns the PEAR DB URL to use to connect to the database. - * - * @return a PEAR DB URL - * - * @private - */ - function getURL() - { - return $this->_url; - } - - /** - * The handle of the connection to the database where PGT's are stored. Written by - * PGTStorageDB::init(), read by getLink(). - * - * @hideinitializer - * @private - */ - var $_link = null; - - /** - * This method returns the handle of the connection to the database where PGT's are - * stored. - * - * @return a handle of connection. - * - * @private - */ - function getLink() - { - return $this->_link; - } - - /** - * The name of the table where PGT's are stored. Written by - * PGTStorageDB::PGTStorageDB(), read by getTable(). - * - * @hideinitializer - * @private - */ - var $_table = ''; - - /** - * This method returns the name of the table where PGT's are stored. - * - * @return the name of a table. - * - * @private - */ - function getTable() - { - return $this->_table; - } - - // ######################################################################## - // DEBUGGING - // ######################################################################## - - /** - * This method returns an informational string giving the type of storage - * used by the object (used for debugging purposes). - * - * @return an informational string. - * @public - */ - function getStorageType() - { - return "database"; - } - - /** - * This method returns an informational string giving informations on the - * parameters of the storage.(used for debugging purposes). - * - * @public - */ - function getStorageInfo() - { - return 'url=`'.$this->getURL().'\', table=`'.$this->getTable().'\''; - } - - // ######################################################################## - // CONSTRUCTOR - // ######################################################################## - - /** - * The class constructor, called by CASClient::SetPGTStorageDB(). - * - * @param $cas_parent the CASClient instance that creates the object. - * @param $user the user to access the data with - * @param $password the user's password - * @param $database_type the type of the database hosting the data - * @param $hostname the server hosting the database - * @param $port the port the server is listening on - * @param $database the name of the database - * @param $table the name of the table storing the data - * - * @public - */ - function PGTStorageDB($cas_parent,$user,$password,$database_type,$hostname,$port,$database,$table) - { - phpCAS::traceBegin(); - - // call the ancestor's constructor - $this->PGTStorage($cas_parent); - - if ( empty($database_type) ) $database_type = CAS_PGT_STORAGE_DB_DEFAULT_DATABASE_TYPE; - if ( empty($hostname) ) $hostname = CAS_PGT_STORAGE_DB_DEFAULT_HOSTNAME; - if ( $port==0 ) $port = CAS_PGT_STORAGE_DB_DEFAULT_PORT; - if ( empty($database) ) $database = CAS_PGT_STORAGE_DB_DEFAULT_DATABASE; - if ( empty($table) ) $table = CAS_PGT_STORAGE_DB_DEFAULT_TABLE; - - // build and store the PEAR DB URL - $this->_url = $database_type.':'.'//'.$user.':'.$password.'@'.$hostname.':'.$port.'/'.$database; - - // XXX should use setURL and setTable - phpCAS::traceEnd(); - } - - // ######################################################################## - // INITIALIZATION - // ######################################################################## - - /** - * This method is used to initialize the storage. Halts on error. - * - * @public - */ - function init() - { - phpCAS::traceBegin(); - // if the storage has already been initialized, return immediatly - if ( $this->isInitialized() ) - return; - // call the ancestor's method (mark as initialized) - parent::init(); - - //include phpDB library (the test was introduced in release 0.4.8 for - //the integration into Tikiwiki). - if (!class_exists('DB')) { - include_once('DB.php'); - } - - // try to connect to the database - $this->_link = DB::connect($this->getURL()); - if ( DB::isError($this->_link) ) { - phpCAS::error('could not connect to database ('.DB::errorMessage($this->_link).')'); - } - var_dump($this->_link); - phpCAS::traceBEnd(); - } - - /** @} */ -} - -?> \ No newline at end of file diff --git a/plugins/CasAuthentication/extlib/CAS/PGTStorage/pgt-file.php b/plugins/CasAuthentication/extlib/CAS/PGTStorage/pgt-file.php deleted file mode 100644 index 983e557c57..0000000000 --- a/plugins/CasAuthentication/extlib/CAS/PGTStorage/pgt-file.php +++ /dev/null @@ -1,276 +0,0 @@ - - * - * @ingroup internalPGTStorageFile - */ - -class PGTStorageFile extends PGTStorage -{ - /** - * @addtogroup internalPGTStorageFile - * @{ - */ - - /** - * a string telling where PGT's should be stored on the filesystem. Written by - * PGTStorageFile::PGTStorageFile(), read by getPath(). - * - * @private - */ - var $_path; - - /** - * This method returns the name of the directory where PGT's should be stored - * on the filesystem. - * - * @return the name of a directory (with leading and trailing '/') - * - * @private - */ - function getPath() - { - return $this->_path; - } - - /** - * a string telling the format to use to store PGT's (plain or xml). Written by - * PGTStorageFile::PGTStorageFile(), read by getFormat(). - * - * @private - */ - var $_format; - - /** - * This method returns the format to use when storing PGT's on the filesystem. - * - * @return a string corresponding to the format used (plain or xml). - * - * @private - */ - function getFormat() - { - return $this->_format; - } - - // ######################################################################## - // DEBUGGING - // ######################################################################## - - /** - * This method returns an informational string giving the type of storage - * used by the object (used for debugging purposes). - * - * @return an informational string. - * @public - */ - function getStorageType() - { - return "file"; - } - - /** - * This method returns an informational string giving informations on the - * parameters of the storage.(used for debugging purposes). - * - * @return an informational string. - * @public - */ - function getStorageInfo() - { - return 'path=`'.$this->getPath().'\', format=`'.$this->getFormat().'\''; - } - - // ######################################################################## - // CONSTRUCTOR - // ######################################################################## - - /** - * The class constructor, called by CASClient::SetPGTStorageFile(). - * - * @param $cas_parent the CASClient instance that creates the object. - * @param $format the format used to store the PGT's (`plain' and `xml' allowed). - * @param $path the path where the PGT's should be stored - * - * @public - */ - function PGTStorageFile($cas_parent,$format,$path) - { - phpCAS::traceBegin(); - // call the ancestor's constructor - $this->PGTStorage($cas_parent); - - if (empty($format) ) $format = CAS_PGT_STORAGE_FILE_DEFAULT_FORMAT; - if (empty($path) ) $path = CAS_PGT_STORAGE_FILE_DEFAULT_PATH; - - // check that the path is an absolute path - if (getenv("OS")=="Windows_NT"){ - - if (!preg_match('`^[a-zA-Z]:`', $path)) { - phpCAS::error('an absolute path is needed for PGT storage to file'); - } - - } - else - { - - if ( $path[0] != '/' ) { - phpCAS::error('an absolute path is needed for PGT storage to file'); - } - - // store the path (with a leading and trailing '/') - $path = preg_replace('|[/]*$|','/',$path); - $path = preg_replace('|^[/]*|','/',$path); - } - - $this->_path = $path; - // check the format and store it - switch ($format) { - case CAS_PGT_STORAGE_FILE_FORMAT_PLAIN: - case CAS_PGT_STORAGE_FILE_FORMAT_XML: - $this->_format = $format; - break; - default: - phpCAS::error('unknown PGT file storage format (`'.CAS_PGT_STORAGE_FILE_FORMAT_PLAIN.'\' and `'.CAS_PGT_STORAGE_FILE_FORMAT_XML.'\' allowed)'); - } - phpCAS::traceEnd(); - } - - // ######################################################################## - // INITIALIZATION - // ######################################################################## - - /** - * This method is used to initialize the storage. Halts on error. - * - * @public - */ - function init() - { - phpCAS::traceBegin(); - // if the storage has already been initialized, return immediatly - if ( $this->isInitialized() ) - return; - // call the ancestor's method (mark as initialized) - parent::init(); - phpCAS::traceEnd(); - } - - // ######################################################################## - // PGT I/O - // ######################################################################## - - /** - * This method returns the filename corresponding to a PGT Iou. - * - * @param $pgt_iou the PGT iou. - * - * @return a filename - * @private - */ - function getPGTIouFilename($pgt_iou) - { - phpCAS::traceBegin(); - $filename = $this->getPath().$pgt_iou.'.'.$this->getFormat(); - phpCAS::traceEnd($filename); - return $filename; - } - - /** - * This method stores a PGT and its corresponding PGT Iou into a file. Echoes a - * warning on error. - * - * @param $pgt the PGT - * @param $pgt_iou the PGT iou - * - * @public - */ - function write($pgt,$pgt_iou) - { - phpCAS::traceBegin(); - $fname = $this->getPGTIouFilename($pgt_iou); - if ( $f=fopen($fname,"w") ) { - if ( fputs($f,$pgt) === FALSE ) { - phpCAS::error('could not write PGT to `'.$fname.'\''); - } - fclose($f); - } else { - phpCAS::error('could not open `'.$fname.'\''); - } - phpCAS::traceEnd(); - } - - /** - * This method reads a PGT corresponding to a PGT Iou and deletes the - * corresponding file. - * - * @param $pgt_iou the PGT iou - * - * @return the corresponding PGT, or FALSE on error - * - * @public - */ - function read($pgt_iou) - { - phpCAS::traceBegin(); - $pgt = FALSE; - $fname = $this->getPGTIouFilename($pgt_iou); - if ( !($f=fopen($fname,"r")) ) { - phpCAS::trace('could not open `'.$fname.'\''); - } else { - if ( ($pgt=fgets($f)) === FALSE ) { - phpCAS::trace('could not read PGT from `'.$fname.'\''); - } - fclose($f); - } - - // delete the PGT file - @unlink($fname); - - phpCAS::traceEnd($pgt); - return $pgt; - } - - /** @} */ - -} - - -?> \ No newline at end of file diff --git a/plugins/CasAuthentication/extlib/CAS/PGTStorage/pgt-main.php b/plugins/CasAuthentication/extlib/CAS/PGTStorage/pgt-main.php deleted file mode 100644 index cf4c4ed0f2..0000000000 --- a/plugins/CasAuthentication/extlib/CAS/PGTStorage/pgt-main.php +++ /dev/null @@ -1,215 +0,0 @@ - - * - * @ingroup internalPGTStorage - */ - -class PGTStorage -{ - /** - * @addtogroup internalPGTStorage - * @{ - */ - - // ######################################################################## - // CONSTRUCTOR - // ######################################################################## - - /** - * The constructor of the class, should be called only by inherited classes. - * - * @param $cas_parent the CASclient instance that creates the current object. - * - * @protected - */ - function PGTStorage($cas_parent) - { - phpCAS::traceBegin(); - if ( !$cas_parent->isProxy() ) { - phpCAS::error('defining PGT storage makes no sense when not using a CAS proxy'); - } - phpCAS::traceEnd(); - } - - // ######################################################################## - // DEBUGGING - // ######################################################################## - - /** - * This virtual method returns an informational string giving the type of storage - * used by the object (used for debugging purposes). - * - * @public - */ - function getStorageType() - { - phpCAS::error(__CLASS__.'::'.__FUNCTION__.'() should never be called'); - } - - /** - * This virtual method returns an informational string giving informations on the - * parameters of the storage.(used for debugging purposes). - * - * @public - */ - function getStorageInfo() - { - phpCAS::error(__CLASS__.'::'.__FUNCTION__.'() should never be called'); - } - - // ######################################################################## - // ERROR HANDLING - // ######################################################################## - - /** - * string used to store an error message. Written by PGTStorage::setErrorMessage(), - * read by PGTStorage::getErrorMessage(). - * - * @hideinitializer - * @private - * @deprecated not used. - */ - var $_error_message=FALSE; - - /** - * This method sets en error message, which can be read later by - * PGTStorage::getErrorMessage(). - * - * @param $error_message an error message - * - * @protected - * @deprecated not used. - */ - function setErrorMessage($error_message) - { - $this->_error_message = $error_message; - } - - /** - * This method returns an error message set by PGTStorage::setErrorMessage(). - * - * @return an error message when set by PGTStorage::setErrorMessage(), FALSE - * otherwise. - * - * @public - * @deprecated not used. - */ - function getErrorMessage() - { - return $this->_error_message; - } - - // ######################################################################## - // INITIALIZATION - // ######################################################################## - - /** - * a boolean telling if the storage has already been initialized. Written by - * PGTStorage::init(), read by PGTStorage::isInitialized(). - * - * @hideinitializer - * @private - */ - var $_initialized = FALSE; - - /** - * This method tells if the storage has already been intialized. - * - * @return a boolean - * - * @protected - */ - function isInitialized() - { - return $this->_initialized; - } - - /** - * This virtual method initializes the object. - * - * @protected - */ - function init() - { - $this->_initialized = TRUE; - } - - // ######################################################################## - // PGT I/O - // ######################################################################## - - /** - * This virtual method stores a PGT and its corresponding PGT Iuo. - * @note Should never be called. - * - * @param $pgt the PGT - * @param $pgt_iou the PGT iou - * - * @protected - */ - function write($pgt,$pgt_iou) - { - phpCAS::error(__CLASS__.'::'.__FUNCTION__.'() should never be called'); - } - - /** - * This virtual method reads a PGT corresponding to a PGT Iou and deletes - * the corresponding storage entry. - * @note Should never be called. - * - * @param $pgt_iou the PGT iou - * - * @protected - */ - function read($pgt_iou) - { - phpCAS::error(__CLASS__.'::'.__FUNCTION__.'() should never be called'); - } - - /** @} */ - -} - -// include specific PGT storage classes -include_once(dirname(__FILE__).'/pgt-file.php'); -include_once(dirname(__FILE__).'/pgt-db.php'); - -?> \ No newline at end of file diff --git a/plugins/CasAuthentication/extlib/CAS/client.php b/plugins/CasAuthentication/extlib/CAS/client.php deleted file mode 100644 index d38c24d361..0000000000 --- a/plugins/CasAuthentication/extlib/CAS/client.php +++ /dev/null @@ -1,2744 +0,0 @@ - - */ - -class CASClient -{ - - // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX - // XX XX - // XX CONFIGURATION XX - // XX XX - // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX - - // ######################################################################## - // HTML OUTPUT - // ######################################################################## - /** - * @addtogroup internalOutput - * @{ - */ - - /** - * This method filters a string by replacing special tokens by appropriate values - * and prints it. The corresponding tokens are taken into account: - * - __CAS_VERSION__ - * - __PHPCAS_VERSION__ - * - __SERVER_BASE_URL__ - * - * Used by CASClient::PrintHTMLHeader() and CASClient::printHTMLFooter(). - * - * @param $str the string to filter and output - * - * @private - */ - function HTMLFilterOutput($str) - { - $str = str_replace('__CAS_VERSION__',$this->getServerVersion(),$str); - $str = str_replace('__PHPCAS_VERSION__',phpCAS::getVersion(),$str); - $str = str_replace('__SERVER_BASE_URL__',$this->getServerBaseURL(),$str); - echo $str; - } - - /** - * A string used to print the header of HTML pages. Written by CASClient::setHTMLHeader(), - * read by CASClient::printHTMLHeader(). - * - * @hideinitializer - * @private - * @see CASClient::setHTMLHeader, CASClient::printHTMLHeader() - */ - var $_output_header = ''; - - /** - * This method prints the header of the HTML output (after filtering). If - * CASClient::setHTMLHeader() was not used, a default header is output. - * - * @param $title the title of the page - * - * @see HTMLFilterOutput() - * @private - */ - function printHTMLHeader($title) - { - $this->HTMLFilterOutput(str_replace('__TITLE__', - $title, - (empty($this->_output_header) - ? '__TITLE__

__TITLE__

' - : $this->_output_header) - ) - ); - } - - /** - * A string used to print the footer of HTML pages. Written by CASClient::setHTMLFooter(), - * read by printHTMLFooter(). - * - * @hideinitializer - * @private - * @see CASClient::setHTMLFooter, CASClient::printHTMLFooter() - */ - var $_output_footer = ''; - - /** - * This method prints the footer of the HTML output (after filtering). If - * CASClient::setHTMLFooter() was not used, a default footer is output. - * - * @see HTMLFilterOutput() - * @private - */ - function printHTMLFooter() - { - $this->HTMLFilterOutput(empty($this->_output_footer) - ?('
phpCAS __PHPCAS_VERSION__ '.$this->getString(CAS_STR_USING_SERVER).' __SERVER_BASE_URL__ (CAS __CAS_VERSION__)
') - :$this->_output_footer); - } - - /** - * This method set the HTML header used for all outputs. - * - * @param $header the HTML header. - * - * @public - */ - function setHTMLHeader($header) - { - $this->_output_header = $header; - } - - /** - * This method set the HTML footer used for all outputs. - * - * @param $footer the HTML footer. - * - * @public - */ - function setHTMLFooter($footer) - { - $this->_output_footer = $footer; - } - - /** @} */ - // ######################################################################## - // INTERNATIONALIZATION - // ######################################################################## - /** - * @addtogroup internalLang - * @{ - */ - /** - * A string corresponding to the language used by phpCAS. Written by - * CASClient::setLang(), read by CASClient::getLang(). - - * @note debugging information is always in english (debug purposes only). - * - * @hideinitializer - * @private - * @sa CASClient::_strings, CASClient::getString() - */ - var $_lang = ''; - - /** - * This method returns the language used by phpCAS. - * - * @return a string representing the language - * - * @private - */ - function getLang() - { - if ( empty($this->_lang) ) - $this->setLang(PHPCAS_LANG_DEFAULT); - return $this->_lang; - } - - /** - * array containing the strings used by phpCAS. Written by CASClient::setLang(), read by - * CASClient::getString() and used by CASClient::setLang(). - * - * @note This array is filled by instructions in CAS/languages/<$this->_lang>.php - * - * @private - * @see CASClient::_lang, CASClient::getString(), CASClient::setLang(), CASClient::getLang() - */ - var $_strings; - - /** - * This method returns a string depending on the language. - * - * @param $str the index of the string in $_string. - * - * @return the string corresponding to $index in $string. - * - * @private - */ - function getString($str) - { - // call CASclient::getLang() to be sure the language is initialized - $this->getLang(); - - if ( !isset($this->_strings[$str]) ) { - trigger_error('string `'.$str.'\' not defined for language `'.$this->getLang().'\'',E_USER_ERROR); - } - return $this->_strings[$str]; - } - - /** - * This method is used to set the language used by phpCAS. - * @note Can be called only once. - * - * @param $lang a string representing the language. - * - * @public - * @sa CAS_LANG_FRENCH, CAS_LANG_ENGLISH - */ - function setLang($lang) - { - // include the corresponding language file - include_once(dirname(__FILE__).'/languages/'.$lang.'.php'); - - if ( !is_array($this->_strings) ) { - trigger_error('language `'.$lang.'\' is not implemented',E_USER_ERROR); - } - $this->_lang = $lang; - } - - /** @} */ - // ######################################################################## - // CAS SERVER CONFIG - // ######################################################################## - /** - * @addtogroup internalConfig - * @{ - */ - - /** - * a record to store information about the CAS server. - * - $_server["version"]: the version of the CAS server - * - $_server["hostname"]: the hostname of the CAS server - * - $_server["port"]: the port the CAS server is running on - * - $_server["uri"]: the base URI the CAS server is responding on - * - $_server["base_url"]: the base URL of the CAS server - * - $_server["login_url"]: the login URL of the CAS server - * - $_server["service_validate_url"]: the service validating URL of the CAS server - * - $_server["proxy_url"]: the proxy URL of the CAS server - * - $_server["proxy_validate_url"]: the proxy validating URL of the CAS server - * - $_server["logout_url"]: the logout URL of the CAS server - * - * $_server["version"], $_server["hostname"], $_server["port"] and $_server["uri"] - * are written by CASClient::CASClient(), read by CASClient::getServerVersion(), - * CASClient::getServerHostname(), CASClient::getServerPort() and CASClient::getServerURI(). - * - * The other fields are written and read by CASClient::getServerBaseURL(), - * CASClient::getServerLoginURL(), CASClient::getServerServiceValidateURL(), - * CASClient::getServerProxyValidateURL() and CASClient::getServerLogoutURL(). - * - * @hideinitializer - * @private - */ - var $_server = array( - 'version' => -1, - 'hostname' => 'none', - 'port' => -1, - 'uri' => 'none' - ); - - /** - * This method is used to retrieve the version of the CAS server. - * @return the version of the CAS server. - * @private - */ - function getServerVersion() - { - return $this->_server['version']; - } - - /** - * This method is used to retrieve the hostname of the CAS server. - * @return the hostname of the CAS server. - * @private - */ - function getServerHostname() - { return $this->_server['hostname']; } - - /** - * This method is used to retrieve the port of the CAS server. - * @return the port of the CAS server. - * @private - */ - function getServerPort() - { return $this->_server['port']; } - - /** - * This method is used to retrieve the URI of the CAS server. - * @return a URI. - * @private - */ - function getServerURI() - { return $this->_server['uri']; } - - /** - * This method is used to retrieve the base URL of the CAS server. - * @return a URL. - * @private - */ - function getServerBaseURL() - { - // the URL is build only when needed - if ( empty($this->_server['base_url']) ) { - $this->_server['base_url'] = 'https://' - .$this->getServerHostname() - .':' - .$this->getServerPort() - .$this->getServerURI(); - } - return $this->_server['base_url']; - } - - /** - * This method is used to retrieve the login URL of the CAS server. - * @param $gateway true to check authentication, false to force it - * @param $renew true to force the authentication with the CAS server - * NOTE : It is recommended that CAS implementations ignore the - "gateway" parameter if "renew" is set - * @return a URL. - * @private - */ - function getServerLoginURL($gateway=false,$renew=false) { - phpCAS::traceBegin(); - // the URL is build only when needed - if ( empty($this->_server['login_url']) ) { - $this->_server['login_url'] = $this->getServerBaseURL(); - $this->_server['login_url'] .= 'login?service='; - // $this->_server['login_url'] .= preg_replace('/&/','%26',$this->getURL()); - $this->_server['login_url'] .= urlencode($this->getURL()); - if($renew) { - // It is recommended that when the "renew" parameter is set, its value be "true" - $this->_server['login_url'] .= '&renew=true'; - } elseif ($gateway) { - // It is recommended that when the "gateway" parameter is set, its value be "true" - $this->_server['login_url'] .= '&gateway=true'; - } - } - phpCAS::traceEnd($this->_server['login_url']); - return $this->_server['login_url']; - } - - /** - * This method sets the login URL of the CAS server. - * @param $url the login URL - * @private - * @since 0.4.21 by Wyman Chan - */ - function setServerLoginURL($url) - { - return $this->_server['login_url'] = $url; - } - - - /** - * This method sets the serviceValidate URL of the CAS server. - * @param $url the serviceValidate URL - * @private - * @since 1.1.0 by Joachim Fritschi - */ - function setServerServiceValidateURL($url) - { - return $this->_server['service_validate_url'] = $url; - } - - - /** - * This method sets the proxyValidate URL of the CAS server. - * @param $url the proxyValidate URL - * @private - * @since 1.1.0 by Joachim Fritschi - */ - function setServerProxyValidateURL($url) - { - return $this->_server['proxy_validate_url'] = $url; - } - - - /** - * This method sets the samlValidate URL of the CAS server. - * @param $url the samlValidate URL - * @private - * @since 1.1.0 by Joachim Fritschi - */ - function setServerSamlValidateURL($url) - { - return $this->_server['saml_validate_url'] = $url; - } - - - /** - * This method is used to retrieve the service validating URL of the CAS server. - * @return a URL. - * @private - */ - function getServerServiceValidateURL() - { - // the URL is build only when needed - if ( empty($this->_server['service_validate_url']) ) { - switch ($this->getServerVersion()) { - case CAS_VERSION_1_0: - $this->_server['service_validate_url'] = $this->getServerBaseURL().'validate'; - break; - case CAS_VERSION_2_0: - $this->_server['service_validate_url'] = $this->getServerBaseURL().'serviceValidate'; - break; - } - } - // return $this->_server['service_validate_url'].'?service='.preg_replace('/&/','%26',$this->getURL()); - return $this->_server['service_validate_url'].'?service='.urlencode($this->getURL()); - } - /** - * This method is used to retrieve the SAML validating URL of the CAS server. - * @return a URL. - * @private - */ - function getServerSamlValidateURL() - { - phpCAS::traceBegin(); - // the URL is build only when needed - if ( empty($this->_server['saml_validate_url']) ) { - switch ($this->getServerVersion()) { - case SAML_VERSION_1_1: - $this->_server['saml_validate_url'] = $this->getServerBaseURL().'samlValidate'; - break; - } - } - phpCAS::traceEnd($this->_server['saml_validate_url'].'?TARGET='.urlencode($this->getURL())); - return $this->_server['saml_validate_url'].'?TARGET='.urlencode($this->getURL()); - } - /** - * This method is used to retrieve the proxy validating URL of the CAS server. - * @return a URL. - * @private - */ - function getServerProxyValidateURL() - { - // the URL is build only when needed - if ( empty($this->_server['proxy_validate_url']) ) { - switch ($this->getServerVersion()) { - case CAS_VERSION_1_0: - $this->_server['proxy_validate_url'] = ''; - break; - case CAS_VERSION_2_0: - $this->_server['proxy_validate_url'] = $this->getServerBaseURL().'proxyValidate'; - break; - } - } - // return $this->_server['proxy_validate_url'].'?service='.preg_replace('/&/','%26',$this->getURL()); - return $this->_server['proxy_validate_url'].'?service='.urlencode($this->getURL()); - } - - /** - * This method is used to retrieve the proxy URL of the CAS server. - * @return a URL. - * @private - */ - function getServerProxyURL() - { - // the URL is build only when needed - if ( empty($this->_server['proxy_url']) ) { - switch ($this->getServerVersion()) { - case CAS_VERSION_1_0: - $this->_server['proxy_url'] = ''; - break; - case CAS_VERSION_2_0: - $this->_server['proxy_url'] = $this->getServerBaseURL().'proxy'; - break; - } - } - return $this->_server['proxy_url']; - } - - /** - * This method is used to retrieve the logout URL of the CAS server. - * @return a URL. - * @private - */ - function getServerLogoutURL() - { - // the URL is build only when needed - if ( empty($this->_server['logout_url']) ) { - $this->_server['logout_url'] = $this->getServerBaseURL().'logout'; - } - return $this->_server['logout_url']; - } - - /** - * This method sets the logout URL of the CAS server. - * @param $url the logout URL - * @private - * @since 0.4.21 by Wyman Chan - */ - function setServerLogoutURL($url) - { - return $this->_server['logout_url'] = $url; - } - - /** - * An array to store extra curl options. - */ - var $_curl_options = array(); - - /** - * This method is used to set additional user curl options. - */ - function setExtraCurlOption($key, $value) - { - $this->_curl_options[$key] = $value; - } - - /** - * This method checks to see if the request is secured via HTTPS - * @return true if https, false otherwise - * @private - */ - function isHttps() { - //if ( isset($_SERVER['HTTPS']) && !empty($_SERVER['HTTPS']) ) { - //0.4.24 by Hinnack - if ( isset($_SERVER['HTTPS']) && !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') { - return true; - } else { - return false; - } - } - - // ######################################################################## - // CONSTRUCTOR - // ######################################################################## - /** - * CASClient constructor. - * - * @param $server_version the version of the CAS server - * @param $proxy TRUE if the CAS client is a CAS proxy, FALSE otherwise - * @param $server_hostname the hostname of the CAS server - * @param $server_port the port the CAS server is running on - * @param $server_uri the URI the CAS server is responding on - * @param $start_session Have phpCAS start PHP sessions (default true) - * - * @return a newly created CASClient object - * - * @public - */ - function CASClient( - $server_version, - $proxy, - $server_hostname, - $server_port, - $server_uri, - $start_session = true) { - - phpCAS::traceBegin(); - - // the redirect header() call and DOM parsing code from domxml-php4-php5.php won't work in PHP4 compatibility mode - if (version_compare(PHP_VERSION,'5','>=') && ini_get('zend.ze1_compatibility_mode')) { - phpCAS::error('phpCAS cannot support zend.ze1_compatibility_mode. Sorry.'); - } - $this->_start_session = $start_session; - - if ($this->_start_session && session_id()) - { - phpCAS :: error("Another session was started before phpcas. Either disable the session" . - " handling for phpcas in the client() call or modify your application to leave" . - " session handling to phpcas"); - } - // skip Session Handling for logout requests and if don't want it' - if ($start_session && !$this->isLogoutRequest()) - { - phpCAS :: trace("Starting a new session"); - session_start(); - } - - - // are we in proxy mode ? - $this->_proxy = $proxy; - - //check version - switch ($server_version) { - case CAS_VERSION_1_0: - if ( $this->isProxy() ) - phpCAS::error('CAS proxies are not supported in CAS ' - .$server_version); - break; - case CAS_VERSION_2_0: - break; - case SAML_VERSION_1_1: - break; - default: - phpCAS::error('this version of CAS (`' - .$server_version - .'\') is not supported by phpCAS ' - .phpCAS::getVersion()); - } - $this->_server['version'] = $server_version; - - // check hostname - if ( empty($server_hostname) - || !preg_match('/[\.\d\-abcdefghijklmnopqrstuvwxyz]*/',$server_hostname) ) { - phpCAS::error('bad CAS server hostname (`'.$server_hostname.'\')'); - } - $this->_server['hostname'] = $server_hostname; - - // check port - if ( $server_port == 0 - || !is_int($server_port) ) { - phpCAS::error('bad CAS server port (`'.$server_hostname.'\')'); - } - $this->_server['port'] = $server_port; - - // check URI - if ( !preg_match('/[\.\d\-_abcdefghijklmnopqrstuvwxyz\/]*/',$server_uri) ) { - phpCAS::error('bad CAS server URI (`'.$server_uri.'\')'); - } - // add leading and trailing `/' and remove doubles - $server_uri = preg_replace('/\/\//','/','/'.$server_uri.'/'); - $this->_server['uri'] = $server_uri; - - // set to callback mode if PgtIou and PgtId CGI GET parameters are provided - if ( $this->isProxy() ) { - $this->setCallbackMode(!empty($_GET['pgtIou'])&&!empty($_GET['pgtId'])); - } - - if ( $this->isCallbackMode() ) { - //callback mode: check that phpCAS is secured - if ( !$this->isHttps() ) { - phpCAS::error('CAS proxies must be secured to use phpCAS; PGT\'s will not be received from the CAS server'); - } - } else { - //normal mode: get ticket and remove it from CGI parameters for developpers - $ticket = (isset($_GET['ticket']) ? $_GET['ticket'] : null); - switch ($this->getServerVersion()) { - case CAS_VERSION_1_0: // check for a Service Ticket - if( preg_match('/^ST-/',$ticket) ) { - phpCAS::trace('ST \''.$ticket.'\' found'); - //ST present - $this->setST($ticket); - //ticket has been taken into account, unset it to hide it to applications - unset($_GET['ticket']); - } else if ( !empty($ticket) ) { - //ill-formed ticket, halt - phpCAS::error('ill-formed ticket found in the URL (ticket=`'.htmlentities($ticket).'\')'); - } - break; - case CAS_VERSION_2_0: // check for a Service or Proxy Ticket - if( preg_match('/^[SP]T-/',$ticket) ) { - phpCAS::trace('ST or PT \''.$ticket.'\' found'); - $this->setPT($ticket); - unset($_GET['ticket']); - } else if ( !empty($ticket) ) { - //ill-formed ticket, halt - phpCAS::error('ill-formed ticket found in the URL (ticket=`'.htmlentities($ticket).'\')'); - } - break; - case SAML_VERSION_1_1: // SAML just does Service Tickets - if( preg_match('/^[SP]T-/',$ticket) ) { - phpCAS::trace('SA \''.$ticket.'\' found'); - $this->setSA($ticket); - unset($_GET['ticket']); - } else if ( !empty($ticket) ) { - //ill-formed ticket, halt - phpCAS::error('ill-formed ticket found in the URL (ticket=`'.htmlentities($ticket).'\')'); - } - break; - } - } - phpCAS::traceEnd(); - } - - /** @} */ - - // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX - // XX XX - // XX Session Handling XX - // XX XX - // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX - - /** - * A variable to whether phpcas will use its own session handling. Default = true - * @hideinitializer - * @private - */ - var $_start_session = true; - - function setStartSession($session) - { - $this->_start_session = session; - } - - function getStartSession($session) - { - $this->_start_session = session; - } - - /** - * Renaming the session - */ - function renameSession($ticket) - { - phpCAS::traceBegin(); - if($this->_start_session){ - if (!empty ($this->_user)) - { - $old_session = $_SESSION; - session_destroy(); - // set up a new session, of name based on the ticket - $session_id = preg_replace('/[^\w]/', '', $ticket); - phpCAS :: trace("Session ID: ".$session_id); - session_id($session_id); - session_start(); - phpCAS :: trace("Restoring old session vars"); - $_SESSION = $old_session; - } else - { - phpCAS :: error('Session should only be renamed after successfull authentication'); - } - }else{ - phpCAS :: trace("Skipping session rename since phpCAS is not handling the session."); - } - phpCAS::traceEnd(); - } - - // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX - // XX XX - // XX AUTHENTICATION XX - // XX XX - // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX - - /** - * @addtogroup internalAuthentication - * @{ - */ - - /** - * The Authenticated user. Written by CASClient::setUser(), read by CASClient::getUser(). - * @attention client applications should use phpCAS::getUser(). - * - * @hideinitializer - * @private - */ - var $_user = ''; - - /** - * This method sets the CAS user's login name. - * - * @param $user the login name of the authenticated user. - * - * @private - */ - function setUser($user) - { - $this->_user = $user; - } - - /** - * This method returns the CAS user's login name. - * @warning should be called only after CASClient::forceAuthentication() or - * CASClient::isAuthenticated(), otherwise halt with an error. - * - * @return the login name of the authenticated user - */ - function getUser() - { - if ( empty($this->_user) ) { - phpCAS::error('this method should be used only after '.__CLASS__.'::forceAuthentication() or '.__CLASS__.'::isAuthenticated()'); - } - return $this->_user; - } - - - - /*********************************************************************************************************************** - * Atrributes section - * - * @author Matthias Crauwels , Ghent University, Belgium - * - ***********************************************************************************************************************/ - /** - * The Authenticated users attributes. Written by CASClient::setAttributes(), read by CASClient::getAttributes(). - * @attention client applications should use phpCAS::getAttributes(). - * - * @hideinitializer - * @private - */ - var $_attributes = array(); - - function setAttributes($attributes) - { $this->_attributes = $attributes; } - - function getAttributes() { - if ( empty($this->_user) ) { // if no user is set, there shouldn't be any attributes also... - phpCAS::error('this method should be used only after '.__CLASS__.'::forceAuthentication() or '.__CLASS__.'::isAuthenticated()'); - } - return $this->_attributes; - } - - function hasAttributes() - { return !empty($this->_attributes); } - - function hasAttribute($key) - { return (is_array($this->_attributes) && array_key_exists($key, $this->_attributes)); } - - function getAttribute($key) { - if($this->hasAttribute($key)) { - return $this->_attributes[$key]; - } - } - - /** - * This method is called to renew the authentication of the user - * If the user is authenticated, renew the connection - * If not, redirect to CAS - * @public - */ - function renewAuthentication(){ - phpCAS::traceBegin(); - // Either way, the user is authenticated by CAS - if( isset( $_SESSION['phpCAS']['auth_checked'] ) ) - unset($_SESSION['phpCAS']['auth_checked']); - if ( $this->isAuthenticated() ) { - phpCAS::trace('user already authenticated; renew'); - $this->redirectToCas(false,true); - } else { - $this->redirectToCas(); - } - phpCAS::traceEnd(); - } - - /** - * This method is called to be sure that the user is authenticated. When not - * authenticated, halt by redirecting to the CAS server; otherwise return TRUE. - * @return TRUE when the user is authenticated; otherwise halt. - * @public - */ - function forceAuthentication() - { - phpCAS::traceBegin(); - - if ( $this->isAuthenticated() ) { - // the user is authenticated, nothing to be done. - phpCAS::trace('no need to authenticate'); - $res = TRUE; - } else { - // the user is not authenticated, redirect to the CAS server - if (isset($_SESSION['phpCAS']['auth_checked'])) { - unset($_SESSION['phpCAS']['auth_checked']); - } - $this->redirectToCas(FALSE/* no gateway */); - // never reached - $res = FALSE; - } - phpCAS::traceEnd($res); - return $res; - } - - /** - * An integer that gives the number of times authentication will be cached before rechecked. - * - * @hideinitializer - * @private - */ - var $_cache_times_for_auth_recheck = 0; - - /** - * Set the number of times authentication will be cached before rechecked. - * - * @param $n an integer. - * - * @public - */ - function setCacheTimesForAuthRecheck($n) - { - $this->_cache_times_for_auth_recheck = $n; - } - - /** - * This method is called to check whether the user is authenticated or not. - * @return TRUE when the user is authenticated, FALSE otherwise. - * @public - */ - function checkAuthentication() - { - phpCAS::traceBegin(); - - if ( $this->isAuthenticated() ) { - phpCAS::trace('user is authenticated'); - $res = TRUE; - } else if (isset($_SESSION['phpCAS']['auth_checked'])) { - // the previous request has redirected the client to the CAS server with gateway=true - unset($_SESSION['phpCAS']['auth_checked']); - $res = FALSE; - } else { - // $_SESSION['phpCAS']['auth_checked'] = true; - // $this->redirectToCas(TRUE/* gateway */); - // // never reached - // $res = FALSE; - // avoid a check against CAS on every request - if (! isset($_SESSION['phpCAS']['unauth_count']) ) - $_SESSION['phpCAS']['unauth_count'] = -2; // uninitialized - - if (($_SESSION['phpCAS']['unauth_count'] != -2 && $this->_cache_times_for_auth_recheck == -1) - || ($_SESSION['phpCAS']['unauth_count'] >= 0 && $_SESSION['phpCAS']['unauth_count'] < $this->_cache_times_for_auth_recheck)) - { - $res = FALSE; - - if ($this->_cache_times_for_auth_recheck != -1) - { - $_SESSION['phpCAS']['unauth_count']++; - phpCAS::trace('user is not authenticated (cached for '.$_SESSION['phpCAS']['unauth_count'].' times of '.$this->_cache_times_for_auth_recheck.')'); - } - else - { - phpCAS::trace('user is not authenticated (cached for until login pressed)'); - } - } - else - { - $_SESSION['phpCAS']['unauth_count'] = 0; - $_SESSION['phpCAS']['auth_checked'] = true; - phpCAS::trace('user is not authenticated (cache reset)'); - $this->redirectToCas(TRUE/* gateway */); - // never reached - $res = FALSE; - } - } - phpCAS::traceEnd($res); - return $res; - } - - /** - * This method is called to check if the user is authenticated (previously or by - * tickets given in the URL). - * - * @return TRUE when the user is authenticated. Also may redirect to the same URL without the ticket. - * - * @public - */ - function isAuthenticated() - { - phpCAS::traceBegin(); - $res = FALSE; - $validate_url = ''; - - if ( $this->wasPreviouslyAuthenticated() ) { - if($this->hasST() || $this->hasPT() || $this->hasSA()){ - // User has a additional ticket but was already authenticated - phpCAS::trace('ticket was present and will be discarded, use renewAuthenticate()'); - header('Location: '.$this->getURL()); - phpCAS::log( "Prepare redirect to remove ticket: ".$this->getURL() ); - }else{ - // the user has already (previously during the session) been - // authenticated, nothing to be done. - phpCAS::trace('user was already authenticated, no need to look for tickets'); - } - $res = TRUE; - } - else { - if ( $this->hasST() ) { - // if a Service Ticket was given, validate it - phpCAS::trace('ST `'.$this->getST().'\' is present'); - $this->validateST($validate_url,$text_response,$tree_response); // if it fails, it halts - phpCAS::trace('ST `'.$this->getST().'\' was validated'); - if ( $this->isProxy() ) { - $this->validatePGT($validate_url,$text_response,$tree_response); // idem - phpCAS::trace('PGT `'.$this->getPGT().'\' was validated'); - $_SESSION['phpCAS']['pgt'] = $this->getPGT(); - } - $_SESSION['phpCAS']['user'] = $this->getUser(); - $res = TRUE; - } - elseif ( $this->hasPT() ) { - // if a Proxy Ticket was given, validate it - phpCAS::trace('PT `'.$this->getPT().'\' is present'); - $this->validatePT($validate_url,$text_response,$tree_response); // note: if it fails, it halts - phpCAS::trace('PT `'.$this->getPT().'\' was validated'); - if ( $this->isProxy() ) { - $this->validatePGT($validate_url,$text_response,$tree_response); // idem - phpCAS::trace('PGT `'.$this->getPGT().'\' was validated'); - $_SESSION['phpCAS']['pgt'] = $this->getPGT(); - } - $_SESSION['phpCAS']['user'] = $this->getUser(); - $res = TRUE; - } - elseif ( $this->hasSA() ) { - // if we have a SAML ticket, validate it. - phpCAS::trace('SA `'.$this->getSA().'\' is present'); - $this->validateSA($validate_url,$text_response,$tree_response); // if it fails, it halts - phpCAS::trace('SA `'.$this->getSA().'\' was validated'); - $_SESSION['phpCAS']['user'] = $this->getUser(); - $_SESSION['phpCAS']['attributes'] = $this->getAttributes(); - $res = TRUE; - } - else { - // no ticket given, not authenticated - phpCAS::trace('no ticket found'); - } - if ($res) { - // if called with a ticket parameter, we need to redirect to the app without the ticket so that CAS-ification is transparent to the browser (for later POSTS) - // most of the checks and errors should have been made now, so we're safe for redirect without masking error messages. - header('Location: '.$this->getURL()); - phpCAS::log( "Prepare redirect to : ".$this->getURL() ); - } - } - - phpCAS::traceEnd($res); - return $res; - } - - /** - * This method tells if the current session is authenticated. - * @return true if authenticated based soley on $_SESSION variable - * @since 0.4.22 by Brendan Arnold - */ - function isSessionAuthenticated () - { - return !empty($_SESSION['phpCAS']['user']); - } - - /** - * This method tells if the user has already been (previously) authenticated - * by looking into the session variables. - * - * @note This function switches to callback mode when needed. - * - * @return TRUE when the user has already been authenticated; FALSE otherwise. - * - * @private - */ - function wasPreviouslyAuthenticated() - { - phpCAS::traceBegin(); - - if ( $this->isCallbackMode() ) { - $this->callback(); - } - - $auth = FALSE; - - if ( $this->isProxy() ) { - // CAS proxy: username and PGT must be present - if ( $this->isSessionAuthenticated() && !empty($_SESSION['phpCAS']['pgt']) ) { - // authentication already done - $this->setUser($_SESSION['phpCAS']['user']); - $this->setPGT($_SESSION['phpCAS']['pgt']); - phpCAS::trace('user = `'.$_SESSION['phpCAS']['user'].'\', PGT = `'.$_SESSION['phpCAS']['pgt'].'\''); - $auth = TRUE; - } elseif ( $this->isSessionAuthenticated() && empty($_SESSION['phpCAS']['pgt']) ) { - // these two variables should be empty or not empty at the same time - phpCAS::trace('username found (`'.$_SESSION['phpCAS']['user'].'\') but PGT is empty'); - // unset all tickets to enforce authentication - unset($_SESSION['phpCAS']); - $this->setST(''); - $this->setPT(''); - } elseif ( !$this->isSessionAuthenticated() && !empty($_SESSION['phpCAS']['pgt']) ) { - // these two variables should be empty or not empty at the same time - phpCAS::trace('PGT found (`'.$_SESSION['phpCAS']['pgt'].'\') but username is empty'); - // unset all tickets to enforce authentication - unset($_SESSION['phpCAS']); - $this->setST(''); - $this->setPT(''); - } else { - phpCAS::trace('neither user not PGT found'); - } - } else { - // `simple' CAS client (not a proxy): username must be present - if ( $this->isSessionAuthenticated() ) { - // authentication already done - $this->setUser($_SESSION['phpCAS']['user']); - if(isset($_SESSION['phpCAS']['attributes'])){ - $this->setAttributes($_SESSION['phpCAS']['attributes']); - } - phpCAS::trace('user = `'.$_SESSION['phpCAS']['user'].'\''); - $auth = TRUE; - } else { - phpCAS::trace('no user found'); - } - } - - phpCAS::traceEnd($auth); - return $auth; - } - - /** - * This method is used to redirect the client to the CAS server. - * It is used by CASClient::forceAuthentication() and CASClient::checkAuthentication(). - * @param $gateway true to check authentication, false to force it - * @param $renew true to force the authentication with the CAS server - * @public - */ - function redirectToCas($gateway=false,$renew=false){ - phpCAS::traceBegin(); - $cas_url = $this->getServerLoginURL($gateway,$renew); - header('Location: '.$cas_url); - phpCAS::log( "Redirect to : ".$cas_url ); - - $this->printHTMLHeader($this->getString(CAS_STR_AUTHENTICATION_WANTED)); - - printf('

'.$this->getString(CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED).'

',$cas_url); - $this->printHTMLFooter(); - - phpCAS::traceExit(); - exit(); - } - - - /** - * This method is used to logout from CAS. - * @params $params an array that contains the optional url and service parameters that will be passed to the CAS server - * @public - */ - function logout($params) { - phpCAS::traceBegin(); - $cas_url = $this->getServerLogoutURL(); - $paramSeparator = '?'; - if (isset($params['url'])) { - $cas_url = $cas_url . $paramSeparator . "url=" . urlencode($params['url']); - $paramSeparator = '&'; - } - if (isset($params['service'])) { - $cas_url = $cas_url . $paramSeparator . "service=" . urlencode($params['service']); - } - header('Location: '.$cas_url); - phpCAS::log( "Prepare redirect to : ".$cas_url ); - - session_unset(); - session_destroy(); - - $this->printHTMLHeader($this->getString(CAS_STR_LOGOUT)); - printf('

'.$this->getString(CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED).'

',$cas_url); - $this->printHTMLFooter(); - - phpCAS::traceExit(); - exit(); - } - - /** - * @return true if the current request is a logout request. - * @private - */ - function isLogoutRequest() { - return !empty($_POST['logoutRequest']); - } - - /** - * @return true if a logout request is allowed. - * @private - */ - function isLogoutRequestAllowed() { - } - - /** - * This method handles logout requests. - * @param $check_client true to check the client bofore handling the request, - * false not to perform any access control. True by default. - * @param $allowed_clients an array of host names allowed to send logout requests. - * By default, only the CAs server (declared in the constructor) will be allowed. - * @public - */ - function handleLogoutRequests($check_client=true, $allowed_clients=false) { - phpCAS::traceBegin(); - if (!$this->isLogoutRequest()) { - phpCAS::log("Not a logout request"); - phpCAS::traceEnd(); - return; - } - if(!$this->_start_session){ - phpCAS::log("phpCAS can't handle logout requests if it does not manage the session."); - } - phpCAS::log("Logout requested"); - phpCAS::log("SAML REQUEST: ".$_POST['logoutRequest']); - if ($check_client) { - if (!$allowed_clients) { - $allowed_clients = array( $this->getServerHostname() ); - } - $client_ip = $_SERVER['REMOTE_ADDR']; - $client = gethostbyaddr($client_ip); - phpCAS::log("Client: ".$client."/".$client_ip); - $allowed = false; - foreach ($allowed_clients as $allowed_client) { - if (($client == $allowed_client) or ($client_ip == $allowed_client)) { - phpCAS::log("Allowed client '".$allowed_client."' matches, logout request is allowed"); - $allowed = true; - break; - } else { - phpCAS::log("Allowed client '".$allowed_client."' does not match"); - } - } - if (!$allowed) { - phpCAS::error("Unauthorized logout request from client '".$client."'"); - printf("Unauthorized!"); - phpCAS::traceExit(); - exit(); - } - } else { - phpCAS::log("No access control set"); - } - // Extract the ticket from the SAML Request - preg_match("|(.*)|", $_POST['logoutRequest'], $tick, PREG_OFFSET_CAPTURE, 3); - $wrappedSamlSessionIndex = preg_replace('||','',$tick[0][0]); - $ticket2logout = preg_replace('||','',$wrappedSamlSessionIndex); - phpCAS::log("Ticket to logout: ".$ticket2logout); - $session_id = preg_replace('/[^\w]/','',$ticket2logout); - phpCAS::log("Session id: ".$session_id); - - // destroy a possible application session created before phpcas - if(session_id()){ - session_unset(); - session_destroy(); - } - // fix session ID - session_id($session_id); - $_COOKIE[session_name()]=$session_id; - $_GET[session_name()]=$session_id; - - // Overwrite session - session_start(); - session_unset(); - session_destroy(); - printf("Disconnected!"); - phpCAS::traceExit(); - exit(); - } - - /** @} */ - - // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX - // XX XX - // XX BASIC CLIENT FEATURES (CAS 1.0) XX - // XX XX - // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX - - // ######################################################################## - // ST - // ######################################################################## - /** - * @addtogroup internalBasic - * @{ - */ - - /** - * the Service Ticket provided in the URL of the request if present - * (empty otherwise). Written by CASClient::CASClient(), read by - * CASClient::getST() and CASClient::hasPGT(). - * - * @hideinitializer - * @private - */ - var $_st = ''; - - /** - * This method returns the Service Ticket provided in the URL of the request. - * @return The service ticket. - * @private - */ - function getST() - { return $this->_st; } - - /** - * This method stores the Service Ticket. - * @param $st The Service Ticket. - * @private - */ - function setST($st) - { $this->_st = $st; } - - /** - * This method tells if a Service Ticket was stored. - * @return TRUE if a Service Ticket has been stored. - * @private - */ - function hasST() - { return !empty($this->_st); } - - /** @} */ - - // ######################################################################## - // ST VALIDATION - // ######################################################################## - /** - * @addtogroup internalBasic - * @{ - */ - - /** - * the certificate of the CAS server. - * - * @hideinitializer - * @private - */ - var $_cas_server_cert = ''; - - /** - * the certificate of the CAS server CA. - * - * @hideinitializer - * @private - */ - var $_cas_server_ca_cert = ''; - - /** - * Set to true not to validate the CAS server. - * - * @hideinitializer - * @private - */ - var $_no_cas_server_validation = false; - - /** - * Set the certificate of the CAS server. - * - * @param $cert the PEM certificate - */ - function setCasServerCert($cert) - { - $this->_cas_server_cert = $cert; - } - - /** - * Set the CA certificate of the CAS server. - * - * @param $cert the PEM certificate of the CA that emited the cert of the server - */ - function setCasServerCACert($cert) - { - $this->_cas_server_ca_cert = $cert; - } - - /** - * Set no SSL validation for the CAS server. - */ - function setNoCasServerValidation() - { - $this->_no_cas_server_validation = true; - } - - /** - * This method is used to validate a ST; halt on failure, and sets $validate_url, - * $text_reponse and $tree_response on success. These parameters are used later - * by CASClient::validatePGT() for CAS proxies. - * Used for all CAS 1.0 validations - * @param $validate_url the URL of the request to the CAS server. - * @param $text_response the response of the CAS server, as is (XML text). - * @param $tree_response the response of the CAS server, as a DOM XML tree. - * - * @return bool TRUE when successfull, halt otherwise by calling CASClient::authError(). - * - * @private - */ - function validateST($validate_url,&$text_response,&$tree_response) - { - phpCAS::traceBegin(); - // build the URL to validate the ticket - $validate_url = $this->getServerServiceValidateURL().'&ticket='.$this->getST(); - if ( $this->isProxy() ) { - // pass the callback url for CAS proxies - $validate_url .= '&pgtUrl='.urlencode($this->getCallbackURL()); - } - - // open and read the URL - if ( !$this->readURL($validate_url,''/*cookies*/,$headers,$text_response,$err_msg) ) { - phpCAS::trace('could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')'); - $this->authError('ST not validated', - $validate_url, - TRUE/*$no_response*/); - } - - // analyze the result depending on the version - switch ($this->getServerVersion()) { - case CAS_VERSION_1_0: - if (preg_match('/^no\n/',$text_response)) { - phpCAS::trace('ST has not been validated'); - $this->authError('ST not validated', - $validate_url, - FALSE/*$no_response*/, - FALSE/*$bad_response*/, - $text_response); - } - if (!preg_match('/^yes\n/',$text_response)) { - phpCAS::trace('ill-formed response'); - $this->authError('ST not validated', - $validate_url, - FALSE/*$no_response*/, - TRUE/*$bad_response*/, - $text_response); - } - // ST has been validated, extract the user name - $arr = preg_split('/\n/',$text_response); - $this->setUser(trim($arr[1])); - break; - case CAS_VERSION_2_0: - // read the response of the CAS server into a DOM object - if ( !($dom = domxml_open_mem($text_response))) { - phpCAS::trace('domxml_open_mem() failed'); - $this->authError('ST not validated', - $validate_url, - FALSE/*$no_response*/, - TRUE/*$bad_response*/, - $text_response); - } - // read the root node of the XML tree - if ( !($tree_response = $dom->document_element()) ) { - phpCAS::trace('document_element() failed'); - $this->authError('ST not validated', - $validate_url, - FALSE/*$no_response*/, - TRUE/*$bad_response*/, - $text_response); - } - // insure that tag name is 'serviceResponse' - if ( $tree_response->node_name() != 'serviceResponse' ) { - phpCAS::trace('bad XML root node (should be `serviceResponse\' instead of `'.$tree_response->node_name().'\''); - $this->authError('ST not validated', - $validate_url, - FALSE/*$no_response*/, - TRUE/*$bad_response*/, - $text_response); - } - if ( sizeof($success_elements = $tree_response->get_elements_by_tagname("authenticationSuccess")) != 0) { - // authentication succeded, extract the user name - if ( sizeof($user_elements = $success_elements[0]->get_elements_by_tagname("user")) == 0) { - phpCAS::trace(' found, but no '); - $this->authError('ST not validated', - $validate_url, - FALSE/*$no_response*/, - TRUE/*$bad_response*/, - $text_response); - } - $user = trim($user_elements[0]->get_content()); - phpCAS::trace('user = `'.$user); - $this->setUser($user); - - } else if ( sizeof($failure_elements = $tree_response->get_elements_by_tagname("authenticationFailure")) != 0) { - phpCAS::trace(' found'); - // authentication failed, extract the error code and message - $this->authError('ST not validated', - $validate_url, - FALSE/*$no_response*/, - FALSE/*$bad_response*/, - $text_response, - $failure_elements[0]->get_attribute('code')/*$err_code*/, - trim($failure_elements[0]->get_content())/*$err_msg*/); - } else { - phpCAS::trace('neither nor found'); - $this->authError('ST not validated', - $validate_url, - FALSE/*$no_response*/, - TRUE/*$bad_response*/, - $text_response); - } - break; - } - $this->renameSession($this->getST()); - // at this step, ST has been validated and $this->_user has been set, - phpCAS::traceEnd(TRUE); - return TRUE; - } - - // ######################################################################## - // SAML VALIDATION - // ######################################################################## - /** - * @addtogroup internalBasic - * @{ - */ - - /** - * This method is used to validate a SAML TICKET; halt on failure, and sets $validate_url, - * $text_reponse and $tree_response on success. These parameters are used later - * by CASClient::validatePGT() for CAS proxies. - * - * @param $validate_url the URL of the request to the CAS server. - * @param $text_response the response of the CAS server, as is (XML text). - * @param $tree_response the response of the CAS server, as a DOM XML tree. - * - * @return bool TRUE when successfull, halt otherwise by calling CASClient::authError(). - * - * @private - */ - function validateSA($validate_url,&$text_response,&$tree_response) - { - phpCAS::traceBegin(); - - // build the URL to validate the ticket - $validate_url = $this->getServerSamlValidateURL(); - - // open and read the URL - if ( !$this->readURL($validate_url,''/*cookies*/,$headers,$text_response,$err_msg) ) { - phpCAS::trace('could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')'); - $this->authError('SA not validated', $validate_url, TRUE/*$no_response*/); - } - - phpCAS::trace('server version: '.$this->getServerVersion()); - - // analyze the result depending on the version - switch ($this->getServerVersion()) { - case SAML_VERSION_1_1: - - // read the response of the CAS server into a DOM object - if ( !($dom = domxml_open_mem($text_response))) { - phpCAS::trace('domxml_open_mem() failed'); - $this->authError('SA not validated', - $validate_url, - FALSE/*$no_response*/, - TRUE/*$bad_response*/, - $text_response); - } - // read the root node of the XML tree - if ( !($tree_response = $dom->document_element()) ) { - phpCAS::trace('document_element() failed'); - $this->authError('SA not validated', - $validate_url, - FALSE/*$no_response*/, - TRUE/*$bad_response*/, - $text_response); - } - // insure that tag name is 'Envelope' - if ( $tree_response->node_name() != 'Envelope' ) { - phpCAS::trace('bad XML root node (should be `Envelope\' instead of `'.$tree_response->node_name().'\''); - $this->authError('SA not validated', - $validate_url, - FALSE/*$no_response*/, - TRUE/*$bad_response*/, - $text_response); - } - // check for the NameIdentifier tag in the SAML response - if ( sizeof($success_elements = $tree_response->get_elements_by_tagname("NameIdentifier")) != 0) { - phpCAS::trace('NameIdentifier found'); - $user = trim($success_elements[0]->get_content()); - phpCAS::trace('user = `'.$user.'`'); - $this->setUser($user); - $this->setSessionAttributes($text_response); - } else { - phpCAS::trace('no tag found in SAML payload'); - $this->authError('SA not validated', - $validate_url, - FALSE/*$no_response*/, - TRUE/*$bad_response*/, - $text_response); - } - break; - } - $this->renameSession($this->getSA()); - // at this step, ST has been validated and $this->_user has been set, - phpCAS::traceEnd(TRUE); - return TRUE; - } - - /** - * This method will parse the DOM and pull out the attributes from the SAML - * payload and put them into an array, then put the array into the session. - * - * @param $text_response the SAML payload. - * @return bool TRUE when successfull and FALSE if no attributes a found - * - * @private - */ - function setSessionAttributes($text_response) - { - phpCAS::traceBegin(); - - $result = FALSE; - - if (isset($_SESSION[SAML_ATTRIBUTES])) { - phpCAS::trace("session attrs already set."); //testbml - do we care? - } - - $attr_array = array(); - - if (($dom = domxml_open_mem($text_response))) { - $xPath = $dom->xpath_new_context(); - $xPath->xpath_register_ns('samlp', 'urn:oasis:names:tc:SAML:1.0:protocol'); - $xPath->xpath_register_ns('saml', 'urn:oasis:names:tc:SAML:1.0:assertion'); - $nodelist = $xPath->xpath_eval("//saml:Attribute"); - if($nodelist){ - $attrs = $nodelist->nodeset; - foreach($attrs as $attr){ - $xres = $xPath->xpath_eval("saml:AttributeValue", $attr); - $name = $attr->get_attribute("AttributeName"); - $value_array = array(); - foreach($xres->nodeset as $node){ - $value_array[] = $node->get_content(); - } - $attr_array[$name] = $value_array; - } - $_SESSION[SAML_ATTRIBUTES] = $attr_array; - // UGent addition... - foreach($attr_array as $attr_key => $attr_value) { - if(count($attr_value) > 1) { - $this->_attributes[$attr_key] = $attr_value; - phpCAS::trace("* " . $attr_key . "=" . $attr_value); - } - else { - $this->_attributes[$attr_key] = $attr_value[0]; - phpCAS::trace("* " . $attr_key . "=" . $attr_value[0]); - } - } - $result = TRUE; - }else{ - phpCAS::trace("SAML Attributes are empty"); - $result = FALSE; - } - } - phpCAS::traceEnd($result); - return $result; - } - - /** @} */ - - // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX - // XX XX - // XX PROXY FEATURES (CAS 2.0) XX - // XX XX - // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX - - // ######################################################################## - // PROXYING - // ######################################################################## - /** - * @addtogroup internalProxy - * @{ - */ - - /** - * A boolean telling if the client is a CAS proxy or not. Written by CASClient::CASClient(), - * read by CASClient::isProxy(). - * - * @private - */ - var $_proxy; - - /** - * Tells if a CAS client is a CAS proxy or not - * - * @return TRUE when the CAS client is a CAs proxy, FALSE otherwise - * - * @private - */ - function isProxy() - { - return $this->_proxy; - } - - /** @} */ - // ######################################################################## - // PGT - // ######################################################################## - /** - * @addtogroup internalProxy - * @{ - */ - - /** - * the Proxy Grnting Ticket given by the CAS server (empty otherwise). - * Written by CASClient::setPGT(), read by CASClient::getPGT() and CASClient::hasPGT(). - * - * @hideinitializer - * @private - */ - var $_pgt = ''; - - /** - * This method returns the Proxy Granting Ticket given by the CAS server. - * @return The Proxy Granting Ticket. - * @private - */ - function getPGT() - { return $this->_pgt; } - - /** - * This method stores the Proxy Granting Ticket. - * @param $pgt The Proxy Granting Ticket. - * @private - */ - function setPGT($pgt) - { $this->_pgt = $pgt; } - - /** - * This method tells if a Proxy Granting Ticket was stored. - * @return TRUE if a Proxy Granting Ticket has been stored. - * @private - */ - function hasPGT() - { return !empty($this->_pgt); } - - /** @} */ - - // ######################################################################## - // CALLBACK MODE - // ######################################################################## - /** - * @addtogroup internalCallback - * @{ - */ - /** - * each PHP script using phpCAS in proxy mode is its own callback to get the - * PGT back from the CAS server. callback_mode is detected by the constructor - * thanks to the GET parameters. - */ - - /** - * a boolean to know if the CAS client is running in callback mode. Written by - * CASClient::setCallBackMode(), read by CASClient::isCallbackMode(). - * - * @hideinitializer - * @private - */ - var $_callback_mode = FALSE; - - /** - * This method sets/unsets callback mode. - * - * @param $callback_mode TRUE to set callback mode, FALSE otherwise. - * - * @private - */ - function setCallbackMode($callback_mode) - { - $this->_callback_mode = $callback_mode; - } - - /** - * This method returns TRUE when the CAs client is running i callback mode, - * FALSE otherwise. - * - * @return A boolean. - * - * @private - */ - function isCallbackMode() - { - return $this->_callback_mode; - } - - /** - * the URL that should be used for the PGT callback (in fact the URL of the - * current request without any CGI parameter). Written and read by - * CASClient::getCallbackURL(). - * - * @hideinitializer - * @private - */ - var $_callback_url = ''; - - /** - * This method returns the URL that should be used for the PGT callback (in - * fact the URL of the current request without any CGI parameter, except if - * phpCAS::setFixedCallbackURL() was used). - * - * @return The callback URL - * - * @private - */ - function getCallbackURL() - { - // the URL is built when needed only - if ( empty($this->_callback_url) ) { - $final_uri = ''; - // remove the ticket if present in the URL - $final_uri = 'https://'; - /* replaced by Julien Marchal - v0.4.6 - * $this->uri .= $_SERVER['SERVER_NAME']; - */ - if(empty($_SERVER['HTTP_X_FORWARDED_SERVER'])){ - /* replaced by teedog - v0.4.12 - * $final_uri .= $_SERVER['SERVER_NAME']; - */ - if (empty($_SERVER['SERVER_NAME'])) { - $final_uri .= $_SERVER['HTTP_HOST']; - } else { - $final_uri .= $_SERVER['SERVER_NAME']; - } - } else { - $final_uri .= $_SERVER['HTTP_X_FORWARDED_SERVER']; - } - if ( ($this->isHttps() && $_SERVER['SERVER_PORT']!=443) - || (!$this->isHttps() && $_SERVER['SERVER_PORT']!=80) ) { - $final_uri .= ':'; - $final_uri .= $_SERVER['SERVER_PORT']; - } - $request_uri = $_SERVER['REQUEST_URI']; - $request_uri = preg_replace('/\?.*$/','',$request_uri); - $final_uri .= $request_uri; - $this->setCallbackURL($final_uri); - } - return $this->_callback_url; - } - - /** - * This method sets the callback url. - * - * @param $callback_url url to set callback - * - * @private - */ - function setCallbackURL($url) - { - return $this->_callback_url = $url; - } - - /** - * This method is called by CASClient::CASClient() when running in callback - * mode. It stores the PGT and its PGT Iou, prints its output and halts. - * - * @private - */ - function callback() - { - phpCAS::traceBegin(); - $this->printHTMLHeader('phpCAS callback'); - $pgt_iou = $_GET['pgtIou']; - $pgt = $_GET['pgtId']; - phpCAS::trace('Storing PGT `'.$pgt.'\' (id=`'.$pgt_iou.'\')'); - echo '

Storing PGT `'.$pgt.'\' (id=`'.$pgt_iou.'\').

'; - $this->storePGT($pgt,$pgt_iou); - $this->printHTMLFooter(); - phpCAS::traceExit(); - exit(); - } - - /** @} */ - - // ######################################################################## - // PGT STORAGE - // ######################################################################## - /** - * @addtogroup internalPGTStorage - * @{ - */ - - /** - * an instance of a class inheriting of PGTStorage, used to deal with PGT - * storage. Created by CASClient::setPGTStorageFile() or CASClient::setPGTStorageDB(), used - * by CASClient::setPGTStorageFile(), CASClient::setPGTStorageDB() and CASClient::initPGTStorage(). - * - * @hideinitializer - * @private - */ - var $_pgt_storage = null; - - /** - * This method is used to initialize the storage of PGT's. - * Halts on error. - * - * @private - */ - function initPGTStorage() - { - // if no SetPGTStorageXxx() has been used, default to file - if ( !is_object($this->_pgt_storage) ) { - $this->setPGTStorageFile(); - } - - // initializes the storage - $this->_pgt_storage->init(); - } - - /** - * This method stores a PGT. Halts on error. - * - * @param $pgt the PGT to store - * @param $pgt_iou its corresponding Iou - * - * @private - */ - function storePGT($pgt,$pgt_iou) - { - // ensure that storage is initialized - $this->initPGTStorage(); - // writes the PGT - $this->_pgt_storage->write($pgt,$pgt_iou); - } - - /** - * This method reads a PGT from its Iou and deletes the corresponding storage entry. - * - * @param $pgt_iou the PGT Iou - * - * @return The PGT corresponding to the Iou, FALSE when not found. - * - * @private - */ - function loadPGT($pgt_iou) - { - // ensure that storage is initialized - $this->initPGTStorage(); - // read the PGT - return $this->_pgt_storage->read($pgt_iou); - } - - /** - * This method is used to tell phpCAS to store the response of the - * CAS server to PGT requests onto the filesystem. - * - * @param $format the format used to store the PGT's (`plain' and `xml' allowed) - * @param $path the path where the PGT's should be stored - * - * @public - */ - function setPGTStorageFile($format='', - $path='') - { - // check that the storage has not already been set - if ( is_object($this->_pgt_storage) ) { - phpCAS::error('PGT storage already defined'); - } - - // create the storage object - $this->_pgt_storage = new PGTStorageFile($this,$format,$path); - } - - /** - * This method is used to tell phpCAS to store the response of the - * CAS server to PGT requests into a database. - * @note The connection to the database is done only when needed. - * As a consequence, bad parameters are detected only when - * initializing PGT storage. - * - * @param $user the user to access the data with - * @param $password the user's password - * @param $database_type the type of the database hosting the data - * @param $hostname the server hosting the database - * @param $port the port the server is listening on - * @param $database the name of the database - * @param $table the name of the table storing the data - * - * @public - */ - function setPGTStorageDB($user, - $password, - $database_type, - $hostname, - $port, - $database, - $table) - { - // check that the storage has not already been set - if ( is_object($this->_pgt_storage) ) { - phpCAS::error('PGT storage already defined'); - } - - // warn the user that he should use file storage... - trigger_error('PGT storage into database is an experimental feature, use at your own risk',E_USER_WARNING); - - // create the storage object - $this->_pgt_storage = new PGTStorageDB($this,$user,$password,$database_type,$hostname,$port,$database,$table); - } - - // ######################################################################## - // PGT VALIDATION - // ######################################################################## - /** - * This method is used to validate a PGT; halt on failure. - * - * @param $validate_url the URL of the request to the CAS server. - * @param $text_response the response of the CAS server, as is (XML text); result - * of CASClient::validateST() or CASClient::validatePT(). - * @param $tree_response the response of the CAS server, as a DOM XML tree; result - * of CASClient::validateST() or CASClient::validatePT(). - * - * @return bool TRUE when successfull, halt otherwise by calling CASClient::authError(). - * - * @private - */ - function validatePGT(&$validate_url,$text_response,$tree_response) - { - // here cannot use phpCAS::traceBegin(); alongside domxml-php4-to-php5.php - phpCAS::log('start validatePGT()'); - if ( sizeof($arr = $tree_response->get_elements_by_tagname("proxyGrantingTicket")) == 0) { - phpCAS::trace(' not found'); - // authentication succeded, but no PGT Iou was transmitted - $this->authError('Ticket validated but no PGT Iou transmitted', - $validate_url, - FALSE/*$no_response*/, - FALSE/*$bad_response*/, - $text_response); - } else { - // PGT Iou transmitted, extract it - $pgt_iou = trim($arr[0]->get_content()); - $pgt = $this->loadPGT($pgt_iou); - if ( $pgt == FALSE ) { - phpCAS::trace('could not load PGT'); - $this->authError('PGT Iou was transmitted but PGT could not be retrieved', - $validate_url, - FALSE/*$no_response*/, - FALSE/*$bad_response*/, - $text_response); - } - $this->setPGT($pgt); - } - // here, cannot use phpCAS::traceEnd(TRUE); alongside domxml-php4-to-php5.php - phpCAS::log('end validatePGT()'); - return TRUE; - } - - // ######################################################################## - // PGT VALIDATION - // ######################################################################## - - /** - * This method is used to retrieve PT's from the CAS server thanks to a PGT. - * - * @param $target_service the service to ask for with the PT. - * @param $err_code an error code (PHPCAS_SERVICE_OK on success). - * @param $err_msg an error message (empty on success). - * - * @return a Proxy Ticket, or FALSE on error. - * - * @private - */ - function retrievePT($target_service,&$err_code,&$err_msg) - { - phpCAS::traceBegin(); - - // by default, $err_msg is set empty and $pt to TRUE. On error, $pt is - // set to false and $err_msg to an error message. At the end, if $pt is FALSE - // and $error_msg is still empty, it is set to 'invalid response' (the most - // commonly encountered error). - $err_msg = ''; - - // build the URL to retrieve the PT - // $cas_url = $this->getServerProxyURL().'?targetService='.preg_replace('/&/','%26',$target_service).'&pgt='.$this->getPGT(); - $cas_url = $this->getServerProxyURL().'?targetService='.urlencode($target_service).'&pgt='.$this->getPGT(); - - // open and read the URL - if ( !$this->readURL($cas_url,''/*cookies*/,$headers,$cas_response,$err_msg) ) { - phpCAS::trace('could not open URL \''.$cas_url.'\' to validate ('.$err_msg.')'); - $err_code = PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE; - $err_msg = 'could not retrieve PT (no response from the CAS server)'; - phpCAS::traceEnd(FALSE); - return FALSE; - } - - $bad_response = FALSE; - - if ( !$bad_response ) { - // read the response of the CAS server into a DOM object - if ( !($dom = @domxml_open_mem($cas_response))) { - phpCAS::trace('domxml_open_mem() failed'); - // read failed - $bad_response = TRUE; - } - } - - if ( !$bad_response ) { - // read the root node of the XML tree - if ( !($root = $dom->document_element()) ) { - phpCAS::trace('document_element() failed'); - // read failed - $bad_response = TRUE; - } - } - - if ( !$bad_response ) { - // insure that tag name is 'serviceResponse' - if ( $root->node_name() != 'serviceResponse' ) { - phpCAS::trace('node_name() failed'); - // bad root node - $bad_response = TRUE; - } - } - - if ( !$bad_response ) { - // look for a proxySuccess tag - if ( sizeof($arr = $root->get_elements_by_tagname("proxySuccess")) != 0) { - // authentication succeded, look for a proxyTicket tag - if ( sizeof($arr = $root->get_elements_by_tagname("proxyTicket")) != 0) { - $err_code = PHPCAS_SERVICE_OK; - $err_msg = ''; - phpCAS::trace('original PT: '.trim($arr[0]->get_content())); - $pt = trim($arr[0]->get_content()); - phpCAS::traceEnd($pt); - return $pt; - } else { - phpCAS::trace(' was found, but not '); - } - } - // look for a proxyFailure tag - else if ( sizeof($arr = $root->get_elements_by_tagname("proxyFailure")) != 0) { - // authentication failed, extract the error - $err_code = PHPCAS_SERVICE_PT_FAILURE; - $err_msg = 'PT retrieving failed (code=`' - .$arr[0]->get_attribute('code') - .'\', message=`' - .trim($arr[0]->get_content()) - .'\')'; - phpCAS::traceEnd(FALSE); - return FALSE; - } else { - phpCAS::trace('neither nor found'); - } - } - - // at this step, we are sure that the response of the CAS server was ill-formed - $err_code = PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE; - $err_msg = 'Invalid response from the CAS server (response=`'.$cas_response.'\')'; - - phpCAS::traceEnd(FALSE); - return FALSE; - } - - // ######################################################################## - // ACCESS TO EXTERNAL SERVICES - // ######################################################################## - - /** - * This method is used to acces a remote URL. - * - * @param $url the URL to access. - * @param $cookies an array containing cookies strings such as 'name=val' - * @param $headers an array containing the HTTP header lines of the response - * (an empty array on failure). - * @param $body the body of the response, as a string (empty on failure). - * @param $err_msg an error message, filled on failure. - * - * @return TRUE on success, FALSE otherwise (in this later case, $err_msg - * contains an error message). - * - * @private - */ - function readURL($url,$cookies,&$headers,&$body,&$err_msg) - { - phpCAS::traceBegin(); - $headers = ''; - $body = ''; - $err_msg = ''; - - $res = TRUE; - - // initialize the CURL session - $ch = curl_init($url); - - if (version_compare(PHP_VERSION,'5.1.3','>=')) { - //only avaible in php5 - curl_setopt_array($ch, $this->_curl_options); - } else { - foreach ($this->_curl_options as $key => $value) { - curl_setopt($ch, $key, $value); - } - } - - if ($this->_cas_server_cert == '' && $this->_cas_server_ca_cert == '' && !$this->_no_cas_server_validation) { - phpCAS::error('one of the methods phpCAS::setCasServerCert(), phpCAS::setCasServerCACert() or phpCAS::setNoCasServerValidation() must be called.'); - } - if ($this->_cas_server_cert != '' && $this->_cas_server_ca_cert != '') { - // This branch added by IDMS. Seems phpCAS implementor got a bit confused about the curl options CURLOPT_SSLCERT and CURLOPT_CAINFO - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1); - curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1); - curl_setopt($ch, CURLOPT_SSLCERT, $this->_cas_server_cert); - curl_setopt($ch, CURLOPT_CAINFO, $this->_cas_server_ca_cert); - curl_setopt($ch, CURLOPT_VERBOSE, '1'); - phpCAS::trace('CURL: Set all required opts for mutual authentication ------'); - } else if ($this->_cas_server_cert != '' ) { - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1); - curl_setopt($ch, CURLOPT_SSLCERT, $this->_cas_server_cert); - } else if ($this->_cas_server_ca_cert != '') { - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1); - curl_setopt($ch, CURLOPT_CAINFO, $this->_cas_server_ca_cert); - } else { - curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1); - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); - } - - // return the CURL output into a variable - curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); - // get the HTTP header with a callback - $this->_curl_headers = array(); // empty the headers array - curl_setopt($ch, CURLOPT_HEADERFUNCTION, array($this, '_curl_read_headers')); - // add cookies headers - if ( is_array($cookies) ) { - curl_setopt($ch,CURLOPT_COOKIE,implode(';',$cookies)); - } - // add extra stuff if SAML - if ($this->hasSA()) { - $more_headers = array ("soapaction: http://www.oasis-open.org/committees/security", - "cache-control: no-cache", - "pragma: no-cache", - "accept: text/xml", - "connection: keep-alive", - "content-type: text/xml"); - - curl_setopt($ch, CURLOPT_HTTPHEADER, $more_headers); - curl_setopt($ch, CURLOPT_POST, 1); - $data = $this->buildSAMLPayload(); - //phpCAS::trace('SAML Payload: '.print_r($data, TRUE)); - curl_setopt($ch, CURLOPT_POSTFIELDS, $data); - } - // perform the query - $buf = curl_exec ($ch); - //phpCAS::trace('CURL: Call completed. Response body is: \''.$buf.'\''); - if ( $buf === FALSE ) { - phpCAS::trace('curl_exec() failed'); - $err_msg = 'CURL error #'.curl_errno($ch).': '.curl_error($ch); - //phpCAS::trace('curl error: '.$err_msg); - // close the CURL session - curl_close ($ch); - $res = FALSE; - } else { - // close the CURL session - curl_close ($ch); - - $headers = $this->_curl_headers; - $body = $buf; - } - - phpCAS::traceEnd($res); - return $res; - } - - /** - * This method is used to build the SAML POST body sent to /samlValidate URL. - * - * @return the SOAP-encased SAMLP artifact (the ticket). - * - * @private - */ - function buildSAMLPayload() - { - phpCAS::traceBegin(); - - //get the ticket - $sa = $this->getSA(); - //phpCAS::trace("SA: ".$sa); - - $body=SAML_SOAP_ENV.SAML_SOAP_BODY.SAMLP_REQUEST.SAML_ASSERTION_ARTIFACT.$sa.SAML_ASSERTION_ARTIFACT_CLOSE.SAMLP_REQUEST_CLOSE.SAML_SOAP_BODY_CLOSE.SAML_SOAP_ENV_CLOSE; - - phpCAS::traceEnd($body); - return ($body); - } - - /** - * This method is the callback used by readURL method to request HTTP headers. - */ - var $_curl_headers = array(); - function _curl_read_headers($ch, $header) - { - $this->_curl_headers[] = $header; - return strlen($header); - } - - /** - * This method is used to access an HTTP[S] service. - * - * @param $url the service to access. - * @param $err_code an error code Possible values are PHPCAS_SERVICE_OK (on - * success), PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE, PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE, - * PHPCAS_SERVICE_PT_FAILURE, PHPCAS_SERVICE_NOT AVAILABLE. - * @param $output the output of the service (also used to give an error - * message on failure). - * - * @return TRUE on success, FALSE otherwise (in this later case, $err_code - * gives the reason why it failed and $output contains an error message). - * - * @public - */ - function serviceWeb($url,&$err_code,&$output) - { - phpCAS::traceBegin(); - $cookies = array(); - // at first retrieve a PT - $pt = $this->retrievePT($url,$err_code,$output); - - $res = TRUE; - - // test if PT was retrieved correctly - if ( !$pt ) { - // note: $err_code and $err_msg are filled by CASClient::retrievePT() - phpCAS::trace('PT was not retrieved correctly'); - $res = FALSE; - } else { - // add cookies if necessary - if ( isset($_SESSION['phpCAS']['services'][$url]['cookies']) && - is_array($_SESSION['phpCAS']['services'][$url]['cookies']) ) { - foreach ( $_SESSION['phpCAS']['services'][$url]['cookies'] as $name => $val ) { - $cookies[] = $name.'='.$val; - } - } - - // build the URL including the PT - if ( strstr($url,'?') === FALSE ) { - $service_url = $url.'?ticket='.$pt; - } else { - $service_url = $url.'&ticket='.$pt; - } - - phpCAS::trace('reading URL`'.$service_url.'\''); - if ( !$this->readURL($service_url,$cookies,$headers,$output,$err_msg) ) { - phpCAS::trace('could not read URL`'.$service_url.'\''); - $err_code = PHPCAS_SERVICE_NOT_AVAILABLE; - // give an error message - $output = sprintf($this->getString(CAS_STR_SERVICE_UNAVAILABLE), - $service_url, - $err_msg); - $res = FALSE; - } else { - // URL has been fetched, extract the cookies - phpCAS::trace('URL`'.$service_url.'\' has been read, storing cookies:'); - foreach ( $headers as $header ) { - // test if the header is a cookie - if ( preg_match('/^Set-Cookie:/',$header) ) { - // the header is a cookie, remove the beginning - $header_val = preg_replace('/^Set-Cookie: */','',$header); - // extract interesting information - $name_val = strtok($header_val,'; '); - // extract the name and the value of the cookie - $cookie_name = strtok($name_val,'='); - $cookie_val = strtok('='); - // store the cookie - $_SESSION['phpCAS']['services'][$url]['cookies'][$cookie_name] = $cookie_val; - phpCAS::trace($cookie_name.' -> '.$cookie_val); - } - } - } - } - - phpCAS::traceEnd($res); - return $res; - } - - /** - * This method is used to access an IMAP/POP3/NNTP service. - * - * @param $url a string giving the URL of the service, including the mailing box - * for IMAP URLs, as accepted by imap_open(). - * @param $service a string giving for CAS retrieve Proxy ticket - * @param $flags options given to imap_open(). - * @param $err_code an error code Possible values are PHPCAS_SERVICE_OK (on - * success), PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE, PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE, - * PHPCAS_SERVICE_PT_FAILURE, PHPCAS_SERVICE_NOT AVAILABLE. - * @param $err_msg an error message on failure - * @param $pt the Proxy Ticket (PT) retrieved from the CAS server to access the URL - * on success, FALSE on error). - * - * @return an IMAP stream on success, FALSE otherwise (in this later case, $err_code - * gives the reason why it failed and $err_msg contains an error message). - * - * @public - */ - function serviceMail($url,$service,$flags,&$err_code,&$err_msg,&$pt) - { - phpCAS::traceBegin(); - // at first retrieve a PT - $pt = $this->retrievePT($service,$err_code,$output); - - $stream = FALSE; - - // test if PT was retrieved correctly - if ( !$pt ) { - // note: $err_code and $err_msg are filled by CASClient::retrievePT() - phpCAS::trace('PT was not retrieved correctly'); - } else { - phpCAS::trace('opening IMAP URL `'.$url.'\'...'); - $stream = @imap_open($url,$this->getUser(),$pt,$flags); - if ( !$stream ) { - phpCAS::trace('could not open URL'); - $err_code = PHPCAS_SERVICE_NOT_AVAILABLE; - // give an error message - $err_msg = sprintf($this->getString(CAS_STR_SERVICE_UNAVAILABLE), - $service_url, - var_export(imap_errors(),TRUE)); - $pt = FALSE; - $stream = FALSE; - } else { - phpCAS::trace('ok'); - } - } - - phpCAS::traceEnd($stream); - return $stream; - } - - /** @} */ - - // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX - // XX XX - // XX PROXIED CLIENT FEATURES (CAS 2.0) XX - // XX XX - // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX - - // ######################################################################## - // PT - // ######################################################################## - /** - * @addtogroup internalProxied - * @{ - */ - - /** - * the Proxy Ticket provided in the URL of the request if present - * (empty otherwise). Written by CASClient::CASClient(), read by - * CASClient::getPT() and CASClient::hasPGT(). - * - * @hideinitializer - * @private - */ - var $_pt = ''; - - /** - * This method returns the Proxy Ticket provided in the URL of the request. - * @return The proxy ticket. - * @private - */ - function getPT() - { - // return 'ST'.substr($this->_pt, 2); - return $this->_pt; - } - - /** - * This method stores the Proxy Ticket. - * @param $pt The Proxy Ticket. - * @private - */ - function setPT($pt) - { $this->_pt = $pt; } - - /** - * This method tells if a Proxy Ticket was stored. - * @return TRUE if a Proxy Ticket has been stored. - * @private - */ - function hasPT() - { return !empty($this->_pt); } - /** - * This method returns the SAML Ticket provided in the URL of the request. - * @return The SAML ticket. - * @private - */ - function getSA() - { return 'ST'.substr($this->_sa, 2); } - - /** - * This method stores the SAML Ticket. - * @param $sa The SAML Ticket. - * @private - */ - function setSA($sa) - { $this->_sa = $sa; } - - /** - * This method tells if a SAML Ticket was stored. - * @return TRUE if a SAML Ticket has been stored. - * @private - */ - function hasSA() - { return !empty($this->_sa); } - - /** @} */ - // ######################################################################## - // PT VALIDATION - // ######################################################################## - /** - * @addtogroup internalProxied - * @{ - */ - - /** - * This method is used to validate a ST or PT; halt on failure - * Used for all CAS 2.0 validations - * @return bool TRUE when successfull, halt otherwise by calling CASClient::authError(). - * - * @private - */ - function validatePT(&$validate_url,&$text_response,&$tree_response) - { - phpCAS::traceBegin(); - // build the URL to validate the ticket - $validate_url = $this->getServerProxyValidateURL().'&ticket='.$this->getPT(); - - if ( $this->isProxy() ) { - // pass the callback url for CAS proxies - $validate_url .= '&pgtUrl='.urlencode($this->getCallbackURL()); - } - - // open and read the URL - if ( !$this->readURL($validate_url,''/*cookies*/,$headers,$text_response,$err_msg) ) { - phpCAS::trace('could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')'); - $this->authError('PT not validated', - $validate_url, - TRUE/*$no_response*/); - } - - // read the response of the CAS server into a DOM object - if ( !($dom = domxml_open_mem($text_response))) { - // read failed - $this->authError('PT not validated', - $validate_url, - FALSE/*$no_response*/, - TRUE/*$bad_response*/, - $text_response); - } - // read the root node of the XML tree - if ( !($tree_response = $dom->document_element()) ) { - // read failed - $this->authError('PT not validated', - $validate_url, - FALSE/*$no_response*/, - TRUE/*$bad_response*/, - $text_response); - } - // insure that tag name is 'serviceResponse' - if ( $tree_response->node_name() != 'serviceResponse' ) { - // bad root node - $this->authError('PT not validated', - $validate_url, - FALSE/*$no_response*/, - TRUE/*$bad_response*/, - $text_response); - } - if ( sizeof($arr = $tree_response->get_elements_by_tagname("authenticationSuccess")) != 0) { - // authentication succeded, extract the user name - if ( sizeof($arr = $tree_response->get_elements_by_tagname("user")) == 0) { - // no user specified => error - $this->authError('PT not validated', - $validate_url, - FALSE/*$no_response*/, - TRUE/*$bad_response*/, - $text_response); - } - $this->setUser(trim($arr[0]->get_content())); - - } else if ( sizeof($arr = $tree_response->get_elements_by_tagname("authenticationFailure")) != 0) { - // authentication succeded, extract the error code and message - $this->authError('PT not validated', - $validate_url, - FALSE/*$no_response*/, - FALSE/*$bad_response*/, - $text_response, - $arr[0]->get_attribute('code')/*$err_code*/, - trim($arr[0]->get_content())/*$err_msg*/); - } else { - $this->authError('PT not validated', - $validate_url, - FALSE/*$no_response*/, - TRUE/*$bad_response*/, - $text_response); - } - - $this->renameSession($this->getPT()); - // at this step, PT has been validated and $this->_user has been set, - - phpCAS::traceEnd(TRUE); - return TRUE; - } - - /** @} */ - - // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX - // XX XX - // XX MISC XX - // XX XX - // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX - - /** - * @addtogroup internalMisc - * @{ - */ - - // ######################################################################## - // URL - // ######################################################################## - /** - * the URL of the current request (without any ticket CGI parameter). Written - * and read by CASClient::getURL(). - * - * @hideinitializer - * @private - */ - var $_url = ''; - - /** - * This method returns the URL of the current request (without any ticket - * CGI parameter). - * - * @return The URL - * - * @private - */ - function getURL() - { - phpCAS::traceBegin(); - // the URL is built when needed only - if ( empty($this->_url) ) { - $final_uri = ''; - // remove the ticket if present in the URL - $final_uri = ($this->isHttps()) ? 'https' : 'http'; - $final_uri .= '://'; - /* replaced by Julien Marchal - v0.4.6 - * $this->_url .= $_SERVER['SERVER_NAME']; - */ - if(empty($_SERVER['HTTP_X_FORWARDED_SERVER'])){ - /* replaced by teedog - v0.4.12 - * $this->_url .= $_SERVER['SERVER_NAME']; - */ - if (empty($_SERVER['SERVER_NAME'])) { - $server_name = $_SERVER['HTTP_HOST']; - } else { - $server_name = $_SERVER['SERVER_NAME']; - } - } else { - $server_name = $_SERVER['HTTP_X_FORWARDED_SERVER']; - } - $final_uri .= $server_name; - if (!strpos($server_name, ':')) { - if ( ($this->isHttps() && $_SERVER['SERVER_PORT']!=443) - || (!$this->isHttps() && $_SERVER['SERVER_PORT']!=80) ) { - $final_uri .= ':'; - $final_uri .= $_SERVER['SERVER_PORT']; - } - } - - $request_uri = explode('?', $_SERVER['REQUEST_URI'], 2); - $final_uri .= $request_uri[0]; - - if (isset($request_uri[1]) && $request_uri[1]) - { - $query_string = $this->removeParameterFromQueryString('ticket', $request_uri[1]); - - // If the query string still has anything left, append it to the final URI - if ($query_string !== '') - $final_uri .= "?$query_string"; - - } - - phpCAS::trace("Final URI: $final_uri"); - $this->setURL($final_uri); - } - phpCAS::traceEnd($this->_url); - return $this->_url; - } - - - - /** - * Removes a parameter from a query string - * - * @param string $parameterName - * @param string $queryString - * @return string - * - * @link http://stackoverflow.com/questions/1842681/regular-expression-to-remove-one-parameter-from-query-string - */ - function removeParameterFromQueryString($parameterName, $queryString) - { - $parameterName = preg_quote($parameterName); - return preg_replace("/&$parameterName(=[^&]*)?|^$parameterName(=[^&]*)?&?/", '', $queryString); - } - - - /** - * This method sets the URL of the current request - * - * @param $url url to set for service - * - * @private - */ - function setURL($url) - { - $this->_url = $url; - } - - // ######################################################################## - // AUTHENTICATION ERROR HANDLING - // ######################################################################## - /** - * This method is used to print the HTML output when the user was not authenticated. - * - * @param $failure the failure that occured - * @param $cas_url the URL the CAS server was asked for - * @param $no_response the response from the CAS server (other - * parameters are ignored if TRUE) - * @param $bad_response bad response from the CAS server ($err_code - * and $err_msg ignored if TRUE) - * @param $cas_response the response of the CAS server - * @param $err_code the error code given by the CAS server - * @param $err_msg the error message given by the CAS server - * - * @private - */ - function authError($failure,$cas_url,$no_response,$bad_response='',$cas_response='',$err_code='',$err_msg='') - { - phpCAS::traceBegin(); - - $this->printHTMLHeader($this->getString(CAS_STR_AUTHENTICATION_FAILED)); - printf($this->getString(CAS_STR_YOU_WERE_NOT_AUTHENTICATED),htmlentities($this->getURL()),$_SERVER['SERVER_ADMIN']); - phpCAS::trace('CAS URL: '.$cas_url); - phpCAS::trace('Authentication failure: '.$failure); - if ( $no_response ) { - phpCAS::trace('Reason: no response from the CAS server'); - } else { - if ( $bad_response ) { - phpCAS::trace('Reason: bad response from the CAS server'); - } else { - switch ($this->getServerVersion()) { - case CAS_VERSION_1_0: - phpCAS::trace('Reason: CAS error'); - break; - case CAS_VERSION_2_0: - if ( empty($err_code) ) - phpCAS::trace('Reason: no CAS error'); - else - phpCAS::trace('Reason: ['.$err_code.'] CAS error: '.$err_msg); - break; - } - } - phpCAS::trace('CAS response: '.$cas_response); - } - $this->printHTMLFooter(); - phpCAS::traceExit(); - exit(); - } - - /** @} */ -} - -?> diff --git a/plugins/CasAuthentication/extlib/CAS/domxml-php4-to-php5.php b/plugins/CasAuthentication/extlib/CAS/domxml-php4-to-php5.php deleted file mode 100644 index 1dc4e4b97b..0000000000 --- a/plugins/CasAuthentication/extlib/CAS/domxml-php4-to-php5.php +++ /dev/null @@ -1,499 +0,0 @@ -=5.1 for XPath evaluation functions, and PHP>=5.1/libxml for DOMXML error reports) - - Typical use: - { - if (PHP_VERSION>='5') - require_once('domxml-php4-to-php5.php'); - } - - Version 1.21, 2008-12-05, http://alexandre.alapetite.net/doc-alex/domxml-php4-php5/ - - ------------------------------------------------------------------ - Written by Alexandre Alapetite, http://alexandre.alapetite.net/cv/ - - Copyright 2004-2008, GNU Lesser General Public License, - http://www.gnu.org/licenses/lgpl.html - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see - - == Rights and obligations == - - Attribution: You must give the original author credit. - - Share Alike: If you alter or transform this library, - you may distribute the resulting library only under the same license GNU/LGPL. - - In case of jurisdiction dispute, the French law is authoritative. - - Any of these conditions can be waived if you get permission from Alexandre Alapetite. - - Not required, but please send to Alexandre Alapetite the modifications you make, - in order to improve this file for the benefit of everybody. - - If you want to distribute this code, please do it as a link to: - http://alexandre.alapetite.net/doc-alex/domxml-php4-php5/ -*/ - -define('DOMXML_LOAD_PARSING',0); -define('DOMXML_LOAD_VALIDATING',1); -define('DOMXML_LOAD_RECOVERING',2); -define('DOMXML_LOAD_SUBSTITUTE_ENTITIES',4); -//define('DOMXML_LOAD_COMPLETE_ATTRS',8); -define('DOMXML_LOAD_DONT_KEEP_BLANKS',16); - -function domxml_new_doc($version) {return new php4DOMDocument();} -function domxml_new_xmldoc($version) {return new php4DOMDocument();} -function domxml_open_file($filename,$mode=DOMXML_LOAD_PARSING,&$error=null) -{ - $dom=new php4DOMDocument($mode); - $errorMode=(func_num_args()>2)&&defined('LIBXML_VERSION'); - if ($errorMode) libxml_use_internal_errors(true); - if (!$dom->myDOMNode->load($filename)) $dom=null; - if ($errorMode) - { - $error=array_map('_error_report',libxml_get_errors()); - libxml_clear_errors(); - } - return $dom; -} -function domxml_open_mem($str,$mode=DOMXML_LOAD_PARSING,&$error=null) -{ - $dom=new php4DOMDocument($mode); - $errorMode=(func_num_args()>2)&&defined('LIBXML_VERSION'); - if ($errorMode) libxml_use_internal_errors(true); - if (!$dom->myDOMNode->loadXML($str)) $dom=null; - if ($errorMode) - { - $error=array_map('_error_report',libxml_get_errors()); - libxml_clear_errors(); - } - return $dom; -} -function html_doc($html_doc,$from_file=false) -{ - $dom=new php4DOMDocument(); - if ($from_file) $result=$dom->myDOMNode->loadHTMLFile($html_doc); - else $result=$dom->myDOMNode->loadHTML($html_doc); - return $result ? $dom : null; -} -function html_doc_file($filename) {return html_doc($filename,true);} -function xmldoc($str) {return domxml_open_mem($str);} -function xmldocfile($filename) {return domxml_open_file($filename);} -function xpath_eval($xpath_context,$eval_str,$contextnode=null) {return $xpath_context->xpath_eval($eval_str,$contextnode);} -function xpath_new_context($dom_document) {return new php4DOMXPath($dom_document);} -function xpath_register_ns($xpath_context,$prefix,$namespaceURI) {return $xpath_context->myDOMXPath->registerNamespace($prefix,$namespaceURI);} -function _entityDecode($text) {return html_entity_decode(strtr($text,array('''=>'\'')),ENT_QUOTES,'UTF-8');} -function _error_report($error) {return array('errormessage'=>$error->message,'nodename'=>'','line'=>$error->line,'col'=>$error->column)+($error->file==''?array():array('directory'=>dirname($error->file),'file'=>basename($error->file)));} - -class php4DOMAttr extends php4DOMNode -{ - function __get($name) - { - if ($name==='name') return $this->myDOMNode->name; - else return parent::__get($name); - } - function name() {return $this->myDOMNode->name;} - function set_content($text) {} - //function set_value($content) {return $this->myDOMNode->value=htmlspecialchars($content,ENT_QUOTES);} - function specified() {return $this->myDOMNode->specified;} - function value() {return $this->myDOMNode->value;} -} - -class php4DOMDocument extends php4DOMNode -{ - function php4DOMDocument($mode=DOMXML_LOAD_PARSING) - { - $this->myDOMNode=new DOMDocument(); - $this->myOwnerDocument=$this; - if ($mode & DOMXML_LOAD_VALIDATING) $this->myDOMNode->validateOnParse=true; - if ($mode & DOMXML_LOAD_RECOVERING) $this->myDOMNode->recover=true; - if ($mode & DOMXML_LOAD_SUBSTITUTE_ENTITIES) $this->myDOMNode->substituteEntities=true; - if ($mode & DOMXML_LOAD_DONT_KEEP_BLANKS) $this->myDOMNode->preserveWhiteSpace=false; - } - function add_root($name) - { - if ($this->myDOMNode->hasChildNodes()) $this->myDOMNode->removeChild($this->myDOMNode->firstChild); - return new php4DOMElement($this->myDOMNode->appendChild($this->myDOMNode->createElement($name)),$this->myOwnerDocument); - } - function create_attribute($name,$value) - { - $myAttr=$this->myDOMNode->createAttribute($name); - $myAttr->value=htmlspecialchars($value,ENT_QUOTES); - return new php4DOMAttr($myAttr,$this); - } - function create_cdata_section($content) {return new php4DOMNode($this->myDOMNode->createCDATASection($content),$this);} - function create_comment($data) {return new php4DOMNode($this->myDOMNode->createComment($data),$this);} - function create_element($name) {return new php4DOMElement($this->myDOMNode->createElement($name),$this);} - function create_element_ns($uri,$name,$prefix=null) - { - if ($prefix==null) $prefix=$this->myDOMNode->lookupPrefix($uri); - if (($prefix==null)&&(($this->myDOMNode->documentElement==null)||(!$this->myDOMNode->documentElement->isDefaultNamespace($uri)))) $prefix='a'.sprintf('%u',crc32($uri)); - return new php4DOMElement($this->myDOMNode->createElementNS($uri,$prefix==null ? $name : $prefix.':'.$name),$this); - } - function create_entity_reference($content) {return new php4DOMNode($this->myDOMNode->createEntityReference($content),$this);} //By Walter Ebert 2007-01-22 - function create_processing_instruction($target,$data=''){return new php4DomProcessingInstruction($this->myDOMNode->createProcessingInstruction($target,$data),$this);} - function create_text_node($content) {return new php4DOMText($this->myDOMNode->createTextNode($content),$this);} - function document_element() {return parent::_newDOMElement($this->myDOMNode->documentElement,$this);} - function dump_file($filename,$compressionmode=false,$format=false) - { - $format0=$this->myDOMNode->formatOutput; - $this->myDOMNode->formatOutput=$format; - $res=$this->myDOMNode->save($filename); - $this->myDOMNode->formatOutput=$format0; - return $res; - } - function dump_mem($format=false,$encoding=false) - { - $format0=$this->myDOMNode->formatOutput; - $this->myDOMNode->formatOutput=$format; - $encoding0=$this->myDOMNode->encoding; - if ($encoding) $this->myDOMNode->encoding=$encoding; - $dump=$this->myDOMNode->saveXML(); - $this->myDOMNode->formatOutput=$format0; - if ($encoding) $this->myDOMNode->encoding= $encoding0=='' ? 'UTF-8' : $encoding0; //UTF-8 is XML default encoding - return $dump; - } - function free() - { - if ($this->myDOMNode->hasChildNodes()) $this->myDOMNode->removeChild($this->myDOMNode->firstChild); - $this->myDOMNode=null; - $this->myOwnerDocument=null; - } - function get_element_by_id($id) {return parent::_newDOMElement($this->myDOMNode->getElementById($id),$this);} - function get_elements_by_tagname($name) - { - $myDOMNodeList=$this->myDOMNode->getElementsByTagName($name); - $nodeSet=array(); - $i=0; - if (isset($myDOMNodeList)) - while ($node=$myDOMNodeList->item($i++)) $nodeSet[]=new php4DOMElement($node,$this); - return $nodeSet; - } - function html_dump_mem() {return $this->myDOMNode->saveHTML();} - function root() {return parent::_newDOMElement($this->myDOMNode->documentElement,$this);} - function xinclude() {return $this->myDOMNode->xinclude();} - function xpath_new_context() {return new php4DOMXPath($this);} -} - -class php4DOMElement extends php4DOMNode -{ - function add_namespace($uri,$prefix) - { - if ($this->myDOMNode->hasAttributeNS('http://www.w3.org/2000/xmlns/',$prefix)) return false; - else - { - $this->myDOMNode->setAttributeNS('http://www.w3.org/2000/xmlns/','xmlns:'.$prefix,$uri); //By Daniel Walker 2006-09-08 - return true; - } - } - function get_attribute($name) {return $this->myDOMNode->getAttribute($name);} - function get_attribute_node($name) {return parent::_newDOMElement($this->myDOMNode->getAttributeNode($name),$this->myOwnerDocument);} - function get_elements_by_tagname($name) - { - $myDOMNodeList=$this->myDOMNode->getElementsByTagName($name); - $nodeSet=array(); - $i=0; - if (isset($myDOMNodeList)) - while ($node=$myDOMNodeList->item($i++)) $nodeSet[]=new php4DOMElement($node,$this->myOwnerDocument); - return $nodeSet; - } - function has_attribute($name) {return $this->myDOMNode->hasAttribute($name);} - function remove_attribute($name) {return $this->myDOMNode->removeAttribute($name);} - function set_attribute($name,$value) - { - //return $this->myDOMNode->setAttribute($name,$value); //Does not return a DomAttr - $myAttr=$this->myDOMNode->ownerDocument->createAttribute($name); - $myAttr->value=htmlspecialchars($value,ENT_QUOTES); //Entity problem reported by AL-DesignWorks 2007-09-07 - $this->myDOMNode->setAttributeNode($myAttr); - return new php4DOMAttr($myAttr,$this->myOwnerDocument); - } - /*function set_attribute_node($attr) - { - $this->myDOMNode->setAttributeNode($this->_importNode($attr)); - return $attr; - }*/ - function set_name($name) - { - if ($this->myDOMNode->prefix=='') $newNode=$this->myDOMNode->ownerDocument->createElement($name); - else $newNode=$this->myDOMNode->ownerDocument->createElementNS($this->myDOMNode->namespaceURI,$this->myDOMNode->prefix.':'.$name); - $myDOMNodeList=$this->myDOMNode->attributes; - $i=0; - if (isset($myDOMNodeList)) - while ($node=$myDOMNodeList->item($i++)) - if ($node->namespaceURI=='') $newNode->setAttribute($node->name,$node->value); - else $newNode->setAttributeNS($node->namespaceURI,$node->nodeName,$node->value); - $myDOMNodeList=$this->myDOMNode->childNodes; - if (isset($myDOMNodeList)) - while ($node=$myDOMNodeList->item(0)) $newNode->appendChild($node); - $this->myDOMNode->parentNode->replaceChild($newNode,$this->myDOMNode); - $this->myDOMNode=$newNode; - return true; - } - function tagname() {return $this->tagname;} -} - -class php4DOMNode -{ - public $myDOMNode; - public $myOwnerDocument; - function php4DOMNode($aDomNode,$aOwnerDocument) - { - $this->myDOMNode=$aDomNode; - $this->myOwnerDocument=$aOwnerDocument; - } - function __get($name) - { - switch ($name) - { - case 'type': return $this->myDOMNode->nodeType; - case 'tagname': return ($this->myDOMNode->nodeType===XML_ELEMENT_NODE) ? $this->myDOMNode->localName : $this->myDOMNode->tagName; //Avoid namespace prefix for DOMElement - case 'content': return $this->myDOMNode->textContent; - case 'value': return $this->myDOMNode->value; - default: - $myErrors=debug_backtrace(); - trigger_error('Undefined property: '.get_class($this).'::$'.$name.' ['.$myErrors[0]['file'].':'.$myErrors[0]['line'].']',E_USER_NOTICE); - return false; - } - } - function add_child($newnode) {return append_child($newnode);} - function add_namespace($uri,$prefix) {return false;} - function append_child($newnode) {return self::_newDOMElement($this->myDOMNode->appendChild($this->_importNode($newnode)),$this->myOwnerDocument);} - function append_sibling($newnode) {return self::_newDOMElement($this->myDOMNode->parentNode->appendChild($this->_importNode($newnode)),$this->myOwnerDocument);} - function attributes() - { - $myDOMNodeList=$this->myDOMNode->attributes; - if (!(isset($myDOMNodeList)&&$this->myDOMNode->hasAttributes())) return null; - $nodeSet=array(); - $i=0; - while ($node=$myDOMNodeList->item($i++)) $nodeSet[]=new php4DOMAttr($node,$this->myOwnerDocument); - return $nodeSet; - } - function child_nodes() - { - $myDOMNodeList=$this->myDOMNode->childNodes; - $nodeSet=array(); - $i=0; - if (isset($myDOMNodeList)) - while ($node=$myDOMNodeList->item($i++)) $nodeSet[]=self::_newDOMElement($node,$this->myOwnerDocument); - return $nodeSet; - } - function children() {return $this->child_nodes();} - function clone_node($deep=false) {return self::_newDOMElement($this->myDOMNode->cloneNode($deep),$this->myOwnerDocument);} - //dump_node($node) should only be called on php4DOMDocument - function dump_node($node=null) {return $node==null ? $this->myOwnerDocument->myDOMNode->saveXML($this->myDOMNode) : $this->myOwnerDocument->myDOMNode->saveXML($node->myDOMNode);} - function first_child() {return self::_newDOMElement($this->myDOMNode->firstChild,$this->myOwnerDocument);} - function get_content() {return $this->myDOMNode->textContent;} - function has_attributes() {return $this->myDOMNode->hasAttributes();} - function has_child_nodes() {return $this->myDOMNode->hasChildNodes();} - function insert_before($newnode,$refnode) {return self::_newDOMElement($this->myDOMNode->insertBefore($this->_importNode($newnode),$refnode==null?null:$refnode->myDOMNode),$this->myOwnerDocument);} - function is_blank_node() {return ($this->myDOMNode->nodeType===XML_TEXT_NODE)&&preg_match('%^\s*$%',$this->myDOMNode->nodeValue);} - function last_child() {return self::_newDOMElement($this->myDOMNode->lastChild,$this->myOwnerDocument);} - function new_child($name,$content) - { - $mySubNode=$this->myDOMNode->ownerDocument->createElement($name); - $mySubNode->appendChild($this->myDOMNode->ownerDocument->createTextNode(_entityDecode($content))); - $this->myDOMNode->appendChild($mySubNode); - return new php4DOMElement($mySubNode,$this->myOwnerDocument); - } - function next_sibling() {return self::_newDOMElement($this->myDOMNode->nextSibling,$this->myOwnerDocument);} - function node_name() {return ($this->myDOMNode->nodeType===XML_ELEMENT_NODE) ? $this->myDOMNode->localName : $this->myDOMNode->nodeName;} //Avoid namespace prefix for DOMElement - function node_type() {return $this->myDOMNode->nodeType;} - function node_value() {return $this->myDOMNode->nodeValue;} - function owner_document() {return $this->myOwnerDocument;} - function parent_node() {return self::_newDOMElement($this->myDOMNode->parentNode,$this->myOwnerDocument);} - function prefix() {return $this->myDOMNode->prefix;} - function previous_sibling() {return self::_newDOMElement($this->myDOMNode->previousSibling,$this->myOwnerDocument);} - function remove_child($oldchild) {return self::_newDOMElement($this->myDOMNode->removeChild($oldchild->myDOMNode),$this->myOwnerDocument);} - function replace_child($newnode,$oldnode) {return self::_newDOMElement($this->myDOMNode->replaceChild($this->_importNode($newnode),$oldnode->myDOMNode),$this->myOwnerDocument);} - function replace_node($newnode) {return self::_newDOMElement($this->myDOMNode->parentNode->replaceChild($this->_importNode($newnode),$this->myDOMNode),$this->myOwnerDocument);} - function set_content($text) {return $this->myDOMNode->appendChild($this->myDOMNode->ownerDocument->createTextNode(_entityDecode($text)));} //Entity problem reported by AL-DesignWorks 2007-09-07 - //function set_name($name) {return $this->myOwnerDocument->renameNode($this->myDOMNode,$this->myDOMNode->namespaceURI,$name);} - function set_namespace($uri,$prefix=null) - {//Contributions by Daniel Walker 2006-09-08 - $nsprefix=$this->myDOMNode->lookupPrefix($uri); - if ($nsprefix==null) - { - $nsprefix= $prefix==null ? $nsprefix='a'.sprintf('%u',crc32($uri)) : $prefix; - if ($this->myDOMNode->nodeType===XML_ATTRIBUTE_NODE) - { - if (($prefix!=null)&&$this->myDOMNode->ownerElement->hasAttributeNS('http://www.w3.org/2000/xmlns/',$nsprefix)&& - ($this->myDOMNode->ownerElement->getAttributeNS('http://www.w3.org/2000/xmlns/',$nsprefix)!=$uri)) - {//Remove namespace - $parent=$this->myDOMNode->ownerElement; - $parent->removeAttributeNode($this->myDOMNode); - $parent->setAttribute($this->myDOMNode->localName,$this->myDOMNode->nodeValue); - $this->myDOMNode=$parent->getAttributeNode($this->myDOMNode->localName); - return; - } - $this->myDOMNode->ownerElement->setAttributeNS('http://www.w3.org/2000/xmlns/','xmlns:'.$nsprefix,$uri); - } - } - if ($this->myDOMNode->nodeType===XML_ATTRIBUTE_NODE) - { - $parent=$this->myDOMNode->ownerElement; - $parent->removeAttributeNode($this->myDOMNode); - $parent->setAttributeNS($uri,$nsprefix.':'.$this->myDOMNode->localName,$this->myDOMNode->nodeValue); - $this->myDOMNode=$parent->getAttributeNodeNS($uri,$this->myDOMNode->localName); - } - elseif ($this->myDOMNode->nodeType===XML_ELEMENT_NODE) - { - $NewNode=$this->myDOMNode->ownerDocument->createElementNS($uri,$nsprefix.':'.$this->myDOMNode->localName); - foreach ($this->myDOMNode->attributes as $n) $NewNode->appendChild($n->cloneNode(true)); - foreach ($this->myDOMNode->childNodes as $n) $NewNode->appendChild($n->cloneNode(true)); - $xpath=new DOMXPath($this->myDOMNode->ownerDocument); - $myDOMNodeList=$xpath->query('namespace::*[name()!="xml"]',$this->myDOMNode); //Add old namespaces - foreach ($myDOMNodeList as $n) $NewNode->setAttributeNS('http://www.w3.org/2000/xmlns/',$n->nodeName,$n->nodeValue); - $this->myDOMNode->parentNode->replaceChild($NewNode,$this->myDOMNode); - $this->myDOMNode=$NewNode; - } - } - function unlink_node() - { - if ($this->myDOMNode->parentNode!=null) - { - if ($this->myDOMNode->nodeType===XML_ATTRIBUTE_NODE) $this->myDOMNode->parentNode->removeAttributeNode($this->myDOMNode); - else $this->myDOMNode->parentNode->removeChild($this->myDOMNode); - } - } - protected function _importNode($newnode) {return $this->myOwnerDocument===$newnode->myOwnerDocument ? $newnode->myDOMNode : $this->myOwnerDocument->myDOMNode->importNode($newnode->myDOMNode,true);} //To import DOMNode from another DOMDocument - static function _newDOMElement($aDOMNode,$aOwnerDocument) - {//Check the PHP5 DOMNode before creating a new associated PHP4 DOMNode wrapper - if ($aDOMNode==null) return null; - switch ($aDOMNode->nodeType) - { - case XML_ELEMENT_NODE: return new php4DOMElement($aDOMNode,$aOwnerDocument); - case XML_TEXT_NODE: return new php4DOMText($aDOMNode,$aOwnerDocument); - case XML_ATTRIBUTE_NODE: return new php4DOMAttr($aDOMNode,$aOwnerDocument); - case XML_PI_NODE: return new php4DomProcessingInstruction($aDOMNode,$aOwnerDocument); - default: return new php4DOMNode($aDOMNode,$aOwnerDocument); - } - } -} - -class php4DomProcessingInstruction extends php4DOMNode -{ - function data() {return $this->myDOMNode->data;} - function target() {return $this->myDOMNode->target;} -} - -class php4DOMText extends php4DOMNode -{ - function __get($name) - { - if ($name==='tagname') return '#text'; - else return parent::__get($name); - } - function tagname() {return '#text';} - function set_content($text) {$this->myDOMNode->nodeValue=$text; return true;} -} - -if (!defined('XPATH_NODESET')) -{ - define('XPATH_UNDEFINED',0); - define('XPATH_NODESET',1); - define('XPATH_BOOLEAN',2); - define('XPATH_NUMBER',3); - define('XPATH_STRING',4); - /*define('XPATH_POINT',5); - define('XPATH_RANGE',6); - define('XPATH_LOCATIONSET',7); - define('XPATH_USERS',8); - define('XPATH_XSLT_TREE',9);*/ -} - -class php4DOMNodelist -{ - private $myDOMNodelist; - public $nodeset; - public $type=XPATH_UNDEFINED; - public $value; - function php4DOMNodelist($aDOMNodelist,$aOwnerDocument) - { - if (!isset($aDOMNodelist)) return; - elseif (is_object($aDOMNodelist)||is_array($aDOMNodelist)) - { - if ($aDOMNodelist->length>0) - { - $this->myDOMNodelist=$aDOMNodelist; - $this->nodeset=array(); - $this->type=XPATH_NODESET; - $i=0; - while ($node=$this->myDOMNodelist->item($i++)) $this->nodeset[]=php4DOMNode::_newDOMElement($node,$aOwnerDocument); - } - } - elseif (is_int($aDOMNodelist)||is_float($aDOMNodelist)) - { - $this->type=XPATH_NUMBER; - $this->value=$aDOMNodelist; - } - elseif (is_bool($aDOMNodelist)) - { - $this->type=XPATH_BOOLEAN; - $this->value=$aDOMNodelist; - } - elseif (is_string($aDOMNodelist)) - { - $this->type=XPATH_STRING; - $this->value=$aDOMNodelist; - } - } -} - -class php4DOMXPath -{ - public $myDOMXPath; - private $myOwnerDocument; - function php4DOMXPath($dom_document) - { - //TODO: If $dom_document is a DomElement, make that default $contextnode and modify XPath. Ex: '/test' - $this->myOwnerDocument=$dom_document->myOwnerDocument; - $this->myDOMXPath=new DOMXPath($this->myOwnerDocument->myDOMNode); - } - function xpath_eval($eval_str,$contextnode=null) - { - if (method_exists($this->myDOMXPath,'evaluate')) $xp=isset($contextnode) ? $this->myDOMXPath->evaluate($eval_str,$contextnode->myDOMNode) : $this->myDOMXPath->evaluate($eval_str); - else $xp=isset($contextnode) ? $this->myDOMXPath->query($eval_str,$contextnode->myDOMNode) : $this->myDOMXPath->query($eval_str); - $xp=new php4DOMNodelist($xp,$this->myOwnerDocument); - return ($xp->type===XPATH_UNDEFINED) ? false : $xp; - } - function xpath_register_ns($prefix,$namespaceURI) {return $this->myDOMXPath->registerNamespace($prefix,$namespaceURI);} -} - -if (extension_loaded('xsl')) -{//See also: http://alexandre.alapetite.net/doc-alex/xslt-php4-php5/ - function domxml_xslt_stylesheet($xslstring) {return new php4DomXsltStylesheet(DOMDocument::loadXML($xslstring));} - function domxml_xslt_stylesheet_doc($dom_document) {return new php4DomXsltStylesheet($dom_document);} - function domxml_xslt_stylesheet_file($xslfile) {return new php4DomXsltStylesheet(DOMDocument::load($xslfile));} - class php4DomXsltStylesheet - { - private $myxsltProcessor; - function php4DomXsltStylesheet($dom_document) - { - $this->myxsltProcessor=new xsltProcessor(); - $this->myxsltProcessor->importStyleSheet($dom_document); - } - function process($dom_document,$xslt_parameters=array(),$param_is_xpath=false) - { - foreach ($xslt_parameters as $param=>$value) $this->myxsltProcessor->setParameter('',$param,$value); - $myphp4DOMDocument=new php4DOMDocument(); - $myphp4DOMDocument->myDOMNode=$this->myxsltProcessor->transformToDoc($dom_document->myDOMNode); - return $myphp4DOMDocument; - } - function result_dump_file($dom_document,$filename) - { - $html=$dom_document->myDOMNode->saveHTML(); - file_put_contents($filename,$html); - return $html; - } - function result_dump_mem($dom_document) {return $dom_document->myDOMNode->saveHTML();} - } -} -?> diff --git a/plugins/CasAuthentication/extlib/CAS/languages/catalan.php b/plugins/CasAuthentication/extlib/CAS/languages/catalan.php deleted file mode 100644 index 3d67473d98..0000000000 --- a/plugins/CasAuthentication/extlib/CAS/languages/catalan.php +++ /dev/null @@ -1,27 +0,0 @@ - - * @sa @link internalLang Internationalization @endlink - * @ingroup internalLang - */ - -$this->_strings = array( - CAS_STR_USING_SERVER - => 'usant servidor', - CAS_STR_AUTHENTICATION_WANTED - => 'Autentificació CAS necessària!', - CAS_STR_LOGOUT - => 'Sortida de CAS necessària!', - CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED - => 'Ja hauria d\ haver estat redireccionat al servidor CAS. Feu click aquí per a continuar.', - CAS_STR_AUTHENTICATION_FAILED - => 'Autentificació CAS fallida!', - CAS_STR_YOU_WERE_NOT_AUTHENTICATED - => '

No estàs autentificat.

Pots tornar a intentar-ho fent click aquí.

Si el problema persisteix hauría de contactar amb l\'administrador d\'aquest llocc.

', - CAS_STR_SERVICE_UNAVAILABLE - => 'El servei `%s\' no està disponible (%s).' -); - -?> diff --git a/plugins/CasAuthentication/extlib/CAS/languages/english.php b/plugins/CasAuthentication/extlib/CAS/languages/english.php deleted file mode 100644 index c143450314..0000000000 --- a/plugins/CasAuthentication/extlib/CAS/languages/english.php +++ /dev/null @@ -1,27 +0,0 @@ - - * @sa @link internalLang Internationalization @endlink - * @ingroup internalLang - */ - -$this->_strings = array( - CAS_STR_USING_SERVER - => 'using server', - CAS_STR_AUTHENTICATION_WANTED - => 'CAS Authentication wanted!', - CAS_STR_LOGOUT - => 'CAS logout wanted!', - CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED - => 'You should already have been redirected to the CAS server. Click here to continue.', - CAS_STR_AUTHENTICATION_FAILED - => 'CAS Authentication failed!', - CAS_STR_YOU_WERE_NOT_AUTHENTICATED - => '

You were not authenticated.

You may submit your request again by clicking here.

If the problem persists, you may contact the administrator of this site.

', - CAS_STR_SERVICE_UNAVAILABLE - => 'The service `%s\' is not available (%s).' -); - -?> \ No newline at end of file diff --git a/plugins/CasAuthentication/extlib/CAS/languages/french.php b/plugins/CasAuthentication/extlib/CAS/languages/french.php deleted file mode 100644 index b077ec02e9..0000000000 --- a/plugins/CasAuthentication/extlib/CAS/languages/french.php +++ /dev/null @@ -1,28 +0,0 @@ - - * @sa @link internalLang Internationalization @endlink - * @ingroup internalLang - */ - -$this->_strings = array( - CAS_STR_USING_SERVER - => 'utilisant le serveur', - CAS_STR_AUTHENTICATION_WANTED - => 'Authentication CAS n�cessaire !', - CAS_STR_LOGOUT - => 'D�connexion demand�e !', - CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED - => 'Vous auriez du etre redirig�(e) vers le serveur CAS. Cliquez ici pour continuer.', - CAS_STR_AUTHENTICATION_FAILED - => 'Authentification CAS infructueuse !', - CAS_STR_YOU_WERE_NOT_AUTHENTICATED - => '

Vous n\'avez pas �t� authentifi�(e).

Vous pouvez soumettre votre requete � nouveau en cliquant ici.

Si le probl�me persiste, vous pouvez contacter l\'administrateur de ce site.

', - CAS_STR_SERVICE_UNAVAILABLE - => 'Le service `%s\' est indisponible (%s)' - -); - -?> \ No newline at end of file diff --git a/plugins/CasAuthentication/extlib/CAS/languages/german.php b/plugins/CasAuthentication/extlib/CAS/languages/german.php deleted file mode 100644 index 29daeb35dd..0000000000 --- a/plugins/CasAuthentication/extlib/CAS/languages/german.php +++ /dev/null @@ -1,27 +0,0 @@ - - * @sa @link internalLang Internationalization @endlink - * @ingroup internalLang - */ - -$this->_strings = array( - CAS_STR_USING_SERVER - => 'via Server', - CAS_STR_AUTHENTICATION_WANTED - => 'CAS Authentifizierung erforderlich!', - CAS_STR_LOGOUT - => 'CAS Abmeldung!', - CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED - => 'eigentlich häten Sie zum CAS Server weitergeleitet werden sollen. Drücken Sie hier um fortzufahren.', - CAS_STR_AUTHENTICATION_FAILED - => 'CAS Anmeldung fehlgeschlagen!', - CAS_STR_YOU_WERE_NOT_AUTHENTICATED - => '

Sie wurden nicht angemeldet.

Um es erneut zu versuchen klicken Sie hier.

Wenn das Problem bestehen bleibt, kontkatieren Sie den Administrator dieser Seite.

', - CAS_STR_SERVICE_UNAVAILABLE - => 'Der Dienst `%s\' ist nicht verfügbar (%s).' -); - -?> \ No newline at end of file diff --git a/plugins/CasAuthentication/extlib/CAS/languages/greek.php b/plugins/CasAuthentication/extlib/CAS/languages/greek.php deleted file mode 100644 index fdff77e4e5..0000000000 --- a/plugins/CasAuthentication/extlib/CAS/languages/greek.php +++ /dev/null @@ -1,27 +0,0 @@ - - * @sa @link internalLang Internationalization @endlink - * @ingroup internalLang - */ - -$this->_strings = array( - CAS_STR_USING_SERVER - => '��������������� � ������������', - CAS_STR_AUTHENTICATION_WANTED - => '���������� � ����������� CAS!', - CAS_STR_LOGOUT - => '���������� � ���������� ��� CAS!', - CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED - => '�� ������ �� ������ �������������� ���� ����������� CAS. ����� ���� ��� ��� �� ����������.', - CAS_STR_AUTHENTICATION_FAILED - => '� ����������� CAS �������!', - CAS_STR_YOU_WERE_NOT_AUTHENTICATED - => '

��� ���������������.

�������� �� ����������������, �������� ���� ���.

��� �� �������� ���������, ����� �� ����� �� ��� �����������.

', - CAS_STR_SERVICE_UNAVAILABLE - => '� �������� `%s\' ��� ����� ��������� (%s).' -); - -?> \ No newline at end of file diff --git a/plugins/CasAuthentication/extlib/CAS/languages/japanese.php b/plugins/CasAuthentication/extlib/CAS/languages/japanese.php deleted file mode 100644 index 76ebe77bcf..0000000000 --- a/plugins/CasAuthentication/extlib/CAS/languages/japanese.php +++ /dev/null @@ -1,27 +0,0 @@ -_strings = array( - CAS_STR_USING_SERVER - => 'using server', - CAS_STR_AUTHENTICATION_WANTED - => 'CAS�ˤ��ǧ�ڤ�Ԥ��ޤ�', - CAS_STR_LOGOUT - => 'CAS����?�����Ȥ��ޤ�!', - CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED - => 'CAS�����Ф˹Ԥ�ɬ�פ�����ޤ�����ưŪ��ž������ʤ����� ������ �򥯥�å�����³�Ԥ��ޤ���', - CAS_STR_AUTHENTICATION_FAILED - => 'CAS�ˤ��ǧ�ڤ˼��Ԥ��ޤ���', - CAS_STR_YOU_WERE_NOT_AUTHENTICATED - => '

ǧ�ڤǤ��ޤ���Ǥ���.

�⤦���٥ꥯ�����Ȥ�������������������򥯥�å�.

���꤬��褷�ʤ����� ���Υ����Ȥδ�������䤤��碌�Ƥ�������.

', - CAS_STR_SERVICE_UNAVAILABLE - => '�����ӥ� `%s\' �����ѤǤ��ޤ��� (%s).' -); - -?> \ No newline at end of file diff --git a/plugins/CasAuthentication/extlib/CAS/languages/languages.php b/plugins/CasAuthentication/extlib/CAS/languages/languages.php deleted file mode 100644 index 2c6f8bb3b3..0000000000 --- a/plugins/CasAuthentication/extlib/CAS/languages/languages.php +++ /dev/null @@ -1,24 +0,0 @@ - - * @sa @link internalLang Internationalization @endlink - * @ingroup internalLang - */ - -//@{ -/** - * a phpCAS string index - */ -define("CAS_STR_USING_SERVER", 1); -define("CAS_STR_AUTHENTICATION_WANTED", 2); -define("CAS_STR_LOGOUT", 3); -define("CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED", 4); -define("CAS_STR_AUTHENTICATION_FAILED", 5); -define("CAS_STR_YOU_WERE_NOT_AUTHENTICATED", 6); -define("CAS_STR_SERVICE_UNAVAILABLE", 7); -//@} - -?> \ No newline at end of file diff --git a/plugins/CasAuthentication/extlib/CAS/languages/spanish.php b/plugins/CasAuthentication/extlib/CAS/languages/spanish.php deleted file mode 100644 index 3a8ffc2535..0000000000 --- a/plugins/CasAuthentication/extlib/CAS/languages/spanish.php +++ /dev/null @@ -1,27 +0,0 @@ - - * @sa @link internalLang Internationalization @endlink - * @ingroup internalLang - */ - -$this->_strings = array( - CAS_STR_USING_SERVER - => 'usando servidor', - CAS_STR_AUTHENTICATION_WANTED - => '¡Autentificación CAS necesaria!', - CAS_STR_LOGOUT - => '¡Salida CAS necesaria!', - CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED - => 'Ya debería haber sido redireccionado al servidor CAS. Haga click aquí para continuar.', - CAS_STR_AUTHENTICATION_FAILED - => '¡Autentificación CAS fallida!', - CAS_STR_YOU_WERE_NOT_AUTHENTICATED - => '

No estás autentificado.

Puedes volver a intentarlo haciendo click aquí.

Si el problema persiste debería contactar con el administrador de este sitio.

', - CAS_STR_SERVICE_UNAVAILABLE - => 'El servicio `%s\' no está disponible (%s).' -); - -?> diff --git a/plugins/Xmpp/extlib/XMPPHP/BOSH.php b/plugins/Xmpp/extlib/XMPPHP/BOSH.php deleted file mode 100644 index 140ff7c823..0000000000 --- a/plugins/Xmpp/extlib/XMPPHP/BOSH.php +++ /dev/null @@ -1,409 +0,0 @@ - - * @author Stephan Wentz - * @author Michael Garvin - * @author Alexander Birkner (https://github.com/BirknerAlex) - * @author zorn-v (https://github.com/zorn-v/xmpphp/) - * @author GNU social - * @copyright 2008 Nathanael C. Fritz - */ - -namespace XMPPHP; - -use SimpleXMLElement; - -/** XMPPHP_XMLStream */ -require_once __DIR__ . "/XMPP.php"; - -/** - * XMPPHP BOSH - * - * @property int lat - * @package XMPPHP - * @author Nathanael C. Fritz - * @author Stephan Wentz - * @author Michael Garvin - * @copyright 2008 Nathanael C. Fritz - * @version $Id$ - */ -class BOSH extends XMPP -{ - /** - * @var integer - */ - protected $rid; - - /** - * @var string - */ - protected $sid; - - /** - * @var string - */ - protected $http_server; - - /** - * @var array - */ - protected $http_buffer = array(); - - /** - * @var string - */ - protected $session = false; - - /** - * @var integer - */ - protected $inactivity; - - /** - * Connect - * - * @param $server - * @param $wait - * @param $session - * @throws Exception - * @throws Exception - */ - public function connect($server = null, $wait = '1', $session = false) - { - - if (is_null($server)) { - - // If we aren't given the server http url, try and guess it - $port_string = ($this->port AND $this->port != 80) ? ':' . $this->port : ''; - $this->http_server = 'http://' . $this->host . $port_string . '/http-bind/'; - } else { - $this->http_server = $server; - } - - $this->use_encryption = false; - $this->session = $session; - $this->rid = 3001; - $this->sid = null; - $this->inactivity = 0; - - if ($session) { - $this->loadSession(); - } - - if (!$this->sid) { - - $body = $this->__buildBody(); - $body->addAttribute('hold', '1'); - $body->addAttribute('to', $this->server); - $body->addAttribute('route', 'xmpp:' . $this->host . ':' . $this->port); - $body->addAttribute('secure', 'true'); - $body->addAttribute('xmpp:version', '1.0', 'urn:xmpp:xbosh'); - $body->addAttribute('wait', strval($wait)); - $body->addAttribute('ack', '1'); - $body->addAttribute('xmlns:xmpp', 'urn:xmpp:xbosh'); - $buff = ''; - xml_parse($this->parser, $buff, false); - $response = $this->__sendBody($body); - $rxml = new SimpleXMLElement($response); - $this->sid = $rxml['sid']; - $this->inactivity = $rxml['inactivity']; - } else { - $buff = ''; - xml_parse($this->parser, $buff, false); - } - } - - /** - * Load session - * - */ - public function loadSession() - { - - if ($this->session == 'ON_FILE') { - - // Session not started so use session_file - $session_file = $this->getSessionFile(); - - // manage multiple accesses - if (!file_exists($session_file)) { - file_put_contents($session_file, ''); - } - $session_file_fp = fopen($session_file, 'r'); - flock($session_file_fp, LOCK_EX); - $session_serialized = file_get_contents($session_file, null, null, 6); - flock($session_file_fp, LOCK_UN); - fclose($session_file_fp); - - $this->log->log('SESSION: reading ' . $session_serialized . ' from ' . $session_file, Log::LEVEL_VERBOSE); - if ($session_serialized != '') { - $_SESSION['XMPPHP_BOSH'] = unserialize($session_serialized); - } - } - - if (isset($_SESSION['XMPPHP_BOSH']['inactivity'])) { - $this->inactivity = $_SESSION['XMPPHP_BOSH']['inactivity']; - } - - $this->lat = (time() - (isset($_SESSION['XMPPHP_BOSH']['lat']))) ? $_SESSION['XMPPHP_BOSH']['lat'] : 0; - - if ($this->lat < $this->inactivity) { - - if (isset($_SESSION['XMPPHP_BOSH']['RID'])) { - $this->rid = $_SESSION['XMPPHP_BOSH']['RID']; - } - if (isset($_SESSION['XMPPHP_BOSH']['SID'])) { - $this->sid = $_SESSION['XMPPHP_BOSH']['SID']; - } - if (isset($_SESSION['XMPPHP_BOSH']['authed'])) { - $this->authed = $_SESSION['XMPPHP_BOSH']['authed']; - } - if (isset($_SESSION['XMPPHP_BOSH']['basejid'])) { - $this->basejid = $_SESSION['XMPPHP_BOSH']['basejid']; - } - if (isset($_SESSION['XMPPHP_BOSH']['fulljid'])) { - $this->fulljid = $_SESSION['XMPPHP_BOSH']['fulljid']; - } - } - } - - /** - * Get the session file - * - */ - public function getSessionFile() - { - return sys_get_temp_dir() . '/' . $this->user . '_' . $this->server . '_session'; - } - - /** - * Build body - * - * @param $sub - * @return SimpleXMLElement|string - */ - public function __buildBody($sub = null) - { - - $xml = ''; - $xml = new SimpleXMLElement($xml); - $xml->addAttribute('content', 'text/xml; charset=utf-8'); - $xml->addAttribute('rid', $this->rid); - $this->rid++; - if ($this->sid) { - $xml->addAttribute('sid', $this->sid); - } - - $xml->addAttribute('xml:lang', 'en'); - - if ($sub !== null) { - - // Ok, so simplexml is lame - $parent = dom_import_simplexml($xml); - $content = dom_import_simplexml($sub); - $child = $parent->ownerDocument->importNode($content, true); - $parent->appendChild($child); - $xml = simplexml_import_dom($parent); - } - - return $xml; - } - - /** - * Send body - * - * @param $body - * @param $recv - * @return bool|string - * @throws Exception - * @throws Exception - */ - public function __sendBody($body = null, $recv = true) - { - - if (!$body) { - $body = $this->__buildBody(); - } - - $output = ''; - $header = array('Accept-Encoding: gzip, deflate', 'Content-Type: text/xml; charset=utf-8'); - $ch = curl_init(); - - curl_setopt($ch, CURLOPT_URL, $this->http_server); - curl_setopt($ch, CURLOPT_HEADER, 0); - curl_setopt($ch, CURLOPT_POST, 1); - curl_setopt($ch, CURLOPT_POSTFIELDS, $body->asXML()); - curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); - curl_setopt($ch, CURLOPT_HTTPHEADER, $header); - curl_setopt($ch, CURLOPT_VERBOSE, 0); - - if ($recv) { - curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); - $output = curl_exec($ch); - if (curl_getinfo($ch, CURLINFO_HTTP_CODE) != '200') { - throw new Exception('Wrong response from server!'); - } - - $this->http_buffer[] = $output; - } - curl_close($ch); - - return $output; - } - - /** - * Process - * - * @param $null1 - * @param $null2 - * - * null params are not used and just to statify Strict Function Declaration - * @return bool - * @throws Exception - * @throws Exception - */ - public function __process($null1 = null, $null2 = null) - { - - if ($this->http_buffer) { - $this->__parseBuffer(); - } else { - $this->__sendBody(); - $this->__parseBuffer(); - } - - $this->saveSession(); - - return true; - } - - public function __parseBuffer() - { - - while ($this->http_buffer) { - - $idx = key($this->http_buffer); - $buffer = $this->http_buffer[$idx]; - unset($this->http_buffer[$idx]); - - if ($buffer) { - - $xml = new SimpleXMLElement($buffer); - $children = $xml->xpath('child::node()'); - - foreach ($children as $child) { - $buff = $child->asXML(); - $this->log->log('RECV: ' . $buff, Log::LEVEL_VERBOSE); - xml_parse($this->parser, $buff, false); - } - } - } - } - - /** - * Save session - * - */ - public function saveSession() - { - - $_SESSION['XMPPHP_BOSH']['RID'] = (string)$this->rid; - $_SESSION['XMPPHP_BOSH']['SID'] = (string)$this->sid; - $_SESSION['XMPPHP_BOSH']['authed'] = (boolean)$this->authed; - $_SESSION['XMPPHP_BOSH']['basejid'] = (string)$this->basejid; - $_SESSION['XMPPHP_BOSH']['fulljid'] = (string)$this->fulljid; - $_SESSION['XMPPHP_BOSH']['inactivity'] = (string)$this->inactivity; - $_SESSION['XMPPHP_BOSH']['lat'] = (string)time(); - - if ($this->session == 'ON_FILE') { - - $session_file = $this->getSessionFile(); - $session_file_fp = fopen($session_file, 'r'); - flock($session_file_fp, LOCK_EX); - // log->log('SEND: ' . $msg, Log::LEVEL_VERBOSE); - $msg = new SimpleXMLElement($msg); - $this->__sendBody($this->__buildBody($msg), true); - } - - /** - * Reset - * - * @throws Exception - */ - public function reset() - { - - $this->xml_depth = 0; - unset($this->xmlobj); - $this->xmlobj = array(); - $this->setupParser(); - $body = $this->__buildBody(); - $body->addAttribute('to', $this->host); - $body->addAttribute('xmpp:restart', 'true', 'urn:xmpp:xbosh'); - $buff = ''; - $response = $this->__sendBody($body); - $this->been_reset = true; - xml_parse($this->parser, $buff, false); - } - - /** - * Disconnect - * - * @throws Exception - */ - public function disconnect() - { - - parent::disconnect(); - - if ($this->session == 'ON_FILE') { - unlink($this->getSessionFile()); - } else { - $keys = array('RID', 'SID', 'authed', 'basejid', 'fulljid', 'inactivity', 'lat'); - foreach ($keys as $key) { - unset($_SESSION['XMPPHP_BOSH'][$key]); - } - } - } -} diff --git a/plugins/Xmpp/extlib/XMPPHP/Exception.php b/plugins/Xmpp/extlib/XMPPHP/Exception.php deleted file mode 100644 index 525bdd962a..0000000000 --- a/plugins/Xmpp/extlib/XMPPHP/Exception.php +++ /dev/null @@ -1,49 +0,0 @@ - - * @author Stephan Wentz - * @author Michael Garvin - * @author Alexander Birkner (https://github.com/BirknerAlex) - * @author zorn-v (https://github.com/zorn-v/xmpphp/) - * @author GNU social - * @copyright 2008 Nathanael C. Fritz - */ - -namespace XMPPHP; - -use Exception as ObjectException; - -/** - * XMPPHP Exception - * - * @package XMPPHP - * @author Nathanael C. Fritz - * @author Stephan Wentz - * @author Michael Garvin - * @copyright 2008 Nathanael C. Fritz - * @version $Id$ - */ -class Exception extends ObjectException -{ -} diff --git a/plugins/Xmpp/extlib/XMPPHP/Log.php b/plugins/Xmpp/extlib/XMPPHP/Log.php deleted file mode 100644 index 7b511d5014..0000000000 --- a/plugins/Xmpp/extlib/XMPPHP/Log.php +++ /dev/null @@ -1,129 +0,0 @@ - - * @author Stephan Wentz - * @author Michael Garvin - * @author Alexander Birkner (https://github.com/BirknerAlex) - * @author zorn-v (https://github.com/zorn-v/xmpphp/) - * @author GNU social - * @copyright 2008 Nathanael C. Fritz - */ - -namespace XMPPHP; - -/** - * XMPPHP Log - * - * @package XMPPHP - * @author Nathanael C. Fritz - * @author Stephan Wentz - * @author Michael Garvin - * @copyright 2008 Nathanael C. Fritz - * @version $Id$ - */ -class Log -{ - const LEVEL_ERROR = 0; - const LEVEL_WARNING = 1; - const LEVEL_INFO = 2; - const LEVEL_DEBUG = 3; - const LEVEL_VERBOSE = 4; - - /** - * @var array - */ - protected $data = array(); - - /** - * @var array - */ - protected $names = array('ERROR', 'WARNING', 'INFO', 'DEBUG', 'VERBOSE'); - - /** - * @var integer - */ - protected $runlevel; - - /** - * @var boolean - */ - protected $printout; - - /** - * Constructor - * - * @param boolean $printout - * @param int $runlevel - */ - public function __construct($printout = false, $runlevel = self::LEVEL_INFO) - { - $this->printout = (boolean)$printout; - $this->runlevel = (int)$runlevel; - } - - /** - * Add a message to the log data array - * If printout in this instance is set to true, directly output the message - * - * @param string $msg - * @param integer $runlevel - */ - public function log($msg, $runlevel = self::LEVEL_INFO) - { - $time = time(); - #$this->data[] = array($this->runlevel, $msg, $time); - if ($this->printout and $runlevel <= $this->runlevel) { - $this->writeLine($msg, $runlevel, $time); - } - } - - protected function writeLine($msg, $runlevel, $time) - { - //echo date('Y-m-d H:i:s', $time)." [".$this->names[$runlevel]."]: ".$msg."\n"; - echo $time . " [" . $this->names[$runlevel] . "]: " . $msg . "\n"; - flush(); - } - - /** - * Output the complete log. - * Log will be cleared if $clear = true - * - * @param boolean $clear - * @param integer $runlevel - */ - public function printout($clear = true, $runlevel = null) - { - if ($runlevel === null) { - $runlevel = $this->runlevel; - } - foreach ($this->data as $data) { - if ($runlevel <= $data[0]) { - $this->writeLine($data[1], $runlevel, $data[2]); - } - } - if ($clear) { - $this->data = array(); - } - } -} diff --git a/plugins/Xmpp/extlib/XMPPHP/Roster.php b/plugins/Xmpp/extlib/XMPPHP/Roster.php deleted file mode 100644 index 799c549140..0000000000 --- a/plugins/Xmpp/extlib/XMPPHP/Roster.php +++ /dev/null @@ -1,183 +0,0 @@ - - * @author Stephan Wentz - * @author Michael Garvin - * @author Alexander Birkner (https://github.com/BirknerAlex) - * @author zorn-v (https://github.com/zorn-v/xmpphp/) - * @author GNU social - * @copyright 2008 Nathanael C. Fritz - */ - -namespace XMPPHP; - -/** - * XMPPHP Roster - * - * @package XMPPHP - * @author Nathanael C. Fritz - * @author Stephan Wentz - * @author Michael Garvin - * @copyright 2008 Nathanael C. Fritz - * @version $Id$ - */ -class Roster -{ - /** - * Roster array, handles contacts and presence. Indexed by jid. - * Contains array with potentially two indexes 'contact' and 'presence' - * @var array - */ - protected $roster_array = array(); - - /** - * Constructor - * @param array $roster_array - */ - public function __construct($roster_array = array()) - { - if ($this->verifyRoster($roster_array)) { - $this->roster_array = $roster_array; //Allow for pre-population with existing roster - } else { - $this->roster_array = array(); - } - } - - /** - * - * Check that a given roster array is of a valid structure (empty is still valid) - * - * @param array $roster_array - * @return bool - */ - protected function verifyRoster($roster_array) - { - #TODO once we know *what* a valid roster array looks like - return true; - } - - /** - * - * Retrieve contact via jid - * - * @param string $jid - * @return mixed - */ - public function getContact($jid) - { - if ($this->isContact($jid)) { - return $this->roster_array[$jid]['contact']; - } - } - - /** - * - * Discover if a contact exists in the roster via jid - * - * @param string $jid - * @return bool - */ - public function isContact($jid) - { - return (array_key_exists($jid, $this->roster_array)); - } - - /** - * - * Set presence - * - * @param string $presence - * @param integer $priority - * @param string $show - * @param string $status - */ - public function setPresence($presence, $priority, $show, $status) - { - $presence = explode('/', $presence, 2); - $jid = $presence[0]; - $resource = isset($presence[1]) ? $presence[1] : ''; - if ($show != 'unavailable') { - if (!$this->isContact($jid)) { - $this->addContact($jid, 'not-in-roster'); - } - $this->roster_array[$jid]['presence'][$resource] = array('priority' => $priority, 'show' => $show, 'status' => $status); - } else { //Nuke unavailable resources to save memory - unset($this->roster_array[$jid]['resource'][$resource]); - unset($this->roster_array[$jid]['presence'][$resource]); - } - } - - /** - * - * Add given contact to roster - * - * @param string $jid - * @param string $subscription - * @param string $name - * @param array $groups - */ - public function addContact($jid, $subscription, $name = '', $groups = array()) - { - $contact = array('jid' => $jid, 'subscription' => $subscription, 'name' => $name, 'groups' => $groups); - if ($this->isContact($jid)) { - $this->roster_array[$jid]['contact'] = $contact; - } else { - $this->roster_array[$jid] = array('contact' => $contact); - } - } - - /* - * - * Return best presence for jid - * - * @param string $jid - */ - - public function getPresence($jid) - { - $split = explode('/', $jid, 2); - $jid = $split[0]; - if ($this->isContact($jid)) { - $current = array('resource' => '', 'active' => '', 'priority' => -129, 'show' => '', 'status' => ''); //Priorities can only be -128 = 127 - foreach ($this->roster_array[$jid]['presence'] as $resource => $presence) { - //Highest available priority or just highest priority - if ($presence['priority'] > $current['priority'] and (($presence['show'] == "chat" or $presence['show'] == "available") or ($current['show'] != "chat" or $current['show'] != "available"))) { - $current = $presence; - $current['resource'] = $resource; - } - } - return $current; - } - } - - /** - * - * Get roster - * - */ - public function getRoster() - { - return $this->roster_array; - } -} diff --git a/plugins/Xmpp/extlib/XMPPHP/XMLObj.php b/plugins/Xmpp/extlib/XMPPHP/XMLObj.php deleted file mode 100644 index de359ae96a..0000000000 --- a/plugins/Xmpp/extlib/XMPPHP/XMLObj.php +++ /dev/null @@ -1,174 +0,0 @@ - - * @author Stephan Wentz - * @author Michael Garvin - * @author Alexander Birkner (https://github.com/BirknerAlex) - * @author zorn-v (https://github.com/zorn-v/xmpphp/) - * @author GNU social - * @copyright 2008 Nathanael C. Fritz - */ - -namespace XMPPHP; - -/** - * XMPPHP XMLObject - * - * @package XMPPHP - * @author Nathanael C. Fritz - * @author Stephan Wentz - * @author Michael Garvin - * @copyright 2008 Nathanael C. Fritz - * @version $Id$ - */ -class XMLObj -{ - /** - * Tag name - * - * @var string - */ - public $name; - - /** - * Namespace - * - * @var string - */ - public $ns; - - /** - * Attributes - * - * @var array - */ - public $attrs = array(); - - /** - * Subs? - * - * @var array - */ - public $subs = array(); - - /** - * Node data - * - * @var string - */ - public $data = ''; - - /** - * Constructor - * - * @param string $name - * @param string $ns - * @param array $attrs - * @param string $data - */ - public function __construct($name, $ns = '', $attrs = array(), $data = '') - { - $this->name = strtolower($name); - $this->ns = $ns; - if (is_array($attrs) && count($attrs)) { - foreach ($attrs as $key => $value) { - $this->attrs[strtolower($key)] = $value; - } - } - $this->data = $data; - } - - /** - * Dump this XML Object to output. - * - * @param integer $depth - */ - public function printObj($depth = 0) - { - print str_repeat("\t", $depth) . $this->name . " " . $this->ns . ' ' . $this->data; - print "\n"; - foreach ($this->subs as $sub) { - $sub->printObj($depth + 1); - } - } - - /** - * Return this XML Object in xml notation - * - * @param string $str - * @return string - */ - public function toString($str = '') - { - $str .= "<{$this->name} xmlns='{$this->ns}' "; - foreach ($this->attrs as $key => $value) { - if ($key != 'xmlns') { - $value = htmlspecialchars($value); - $str .= "$key='$value' "; - } - } - $str .= ">"; - foreach ($this->subs as $sub) { - $str .= $sub->toString(); - } - $body = htmlspecialchars($this->data); - $str .= "$bodyname}>"; - return $str; - } - - /** - * Has this XML Object the given sub? - * - * @param string $name - * @param null $ns - * @return boolean - */ - public function hasSub($name, $ns = null) - { - foreach ($this->subs as $sub) { - if (($name == "*" or $sub->name == $name) and ($ns == null or $sub->ns == $ns)) { - return true; - } - } - return false; - } - - /** - * Return a sub - * - * @param string $name - * @param string $attrs - * @param string $ns - * @return mixed - */ - public function sub($name, $attrs = null, $ns = null) - { - #TODO attrs is ignored - foreach ($this->subs as $sub) { - if ($sub->name == $name and ($ns == null or $sub->ns == $ns)) { - return $sub; - } - } - } -} diff --git a/plugins/Xmpp/extlib/XMPPHP/XMLStream.php b/plugins/Xmpp/extlib/XMPPHP/XMLStream.php deleted file mode 100644 index 615e7ca12d..0000000000 --- a/plugins/Xmpp/extlib/XMPPHP/XMLStream.php +++ /dev/null @@ -1,804 +0,0 @@ - - * @author Stephan Wentz - * @author Michael Garvin - * @author Alexander Birkner (https://github.com/BirknerAlex) - * @author zorn-v (https://github.com/zorn-v/xmpphp/) - * @author GNU social - * @copyright 2008 Nathanael C. Fritz - */ - -namespace XMPPHP; - -/** Exception */ -require_once __DIR__ . DIRECTORY_SEPARATOR . 'Exception.php'; - -/** XMLObj */ -require_once __DIR__ . DIRECTORY_SEPARATOR . 'XMLObj.php'; - -/** Log */ -require_once __DIR__ . DIRECTORY_SEPARATOR . 'Log.php'; - - -/** - * XMPPHP XMLStream - * - * @package XMPPHP - * @author Nathanael C. Fritz - * @author Stephan Wentz - * @author Michael Garvin - * @copyright 2008 Nathanael C. Fritz - * @version $Id$ - */ -class XMLStream -{ - /** - * @var resource - */ - protected $socket; - /** - * @var resource - */ - protected $parser; - /** - * @var string - */ - protected $buffer; - /** - * @var integer - */ - protected $xml_depth = 0; - /** - * @var string - */ - protected $host; - /** - * @var integer - */ - protected $port; - /** - * @var string - */ - protected $stream_start = ''; - /** - * @var string - */ - protected $stream_end = ''; - /** - * @var boolean - */ - protected $disconnected = false; - /** - * @var boolean - */ - protected $sent_disconnect = false; - /** - * @var array - */ - protected $ns_map = array(); - /** - * @var array - */ - protected $current_ns = array(); - /** - * @var array - */ - protected $xmlobj = null; - /** - * @var array - */ - protected $nshandlers = array(); - /** - * @var array - */ - protected $xpathhandlers = array(); - /** - * @var array - */ - protected $idhandlers = array(); - /** - * @var array - */ - protected $eventhandlers = array(); - /** - * @var integer - */ - protected $lastid = 0; - /** - * @var string - */ - protected $default_ns; - /** - * @var string[] - */ - protected $until = []; - /** - * @var int[] - */ - protected $until_count = []; - /** - * @var array - */ - protected $until_happened = false; - /** - * @var array - */ - protected $until_payload = array(); - /** - * @var Log - */ - protected $log; - /** - * @var boolean - */ - protected $reconnect = true; - /** - * @var boolean - */ - protected $been_reset = false; - /** - * @var boolean - */ - protected $is_server; - /** - * @var float - */ - protected $last_send = 0; - /** - * @var boolean - */ - protected $use_ssl = false; - /** - * @var integer - */ - protected $reconnectTimeout = 30; - - /** - * Constructor - * - * @param string $host - * @param string $port - * @param boolean $printlog - * @param string $loglevel - * @param boolean $is_server - */ - public function __construct($host = null, $port = null, $printlog = false, $loglevel = null, $is_server = false) - { - $this->reconnect = !$is_server; - $this->is_server = $is_server; - $this->host = $host; - $this->port = $port; - $this->setupParser(); - $this->log = new Log($printlog, $loglevel); - } - - /** - * Setup the XML parser - */ - public function setupParser() - { - $this->parser = xml_parser_create('UTF-8'); - xml_parser_set_option($this->parser, XML_OPTION_SKIP_WHITE, 1); - xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, 'UTF-8'); - xml_set_object($this->parser, $this); - xml_set_element_handler($this->parser, 'startXML', 'endXML'); - xml_set_character_data_handler($this->parser, 'charXML'); - } - - /** - * Destructor - * Cleanup connection - */ - public function __destruct() - { - if (!$this->disconnected && $this->socket) { - $this->disconnect(); - } - } - - /** - * Disconnect from XMPP Host - */ - public function disconnect() - { - $this->log->log("Disconnecting...", Log::LEVEL_VERBOSE); - if (false == (bool)$this->socket) { - return; - } - $this->reconnect = false; - $this->send($this->stream_end); - $this->sent_disconnect = true; - $this->processUntil('end_stream', 5); - $this->disconnected = true; - } - - /** - * Send to socket - * - * @param string $msg - * @param null $timeout - * @return bool|int - * @throws Exception - */ - public function send($msg, $timeout = NULL) - { - - if (is_null($timeout)) { - $secs = NULL; - $usecs = NULL; - } else if ($timeout == 0) { - $secs = 0; - $usecs = 0; - } else { - $maximum = $timeout * 1000000; - $usecs = $maximum % 1000000; - $secs = floor(($maximum - $usecs) / 1000000); - } - - $read = array(); - $write = array($this->socket); - $except = array(); - - $select = @stream_select($read, $write, $except, $secs, $usecs); - - if ($select === False) { - $this->log->log("ERROR sending message; reconnecting."); - $this->doReconnect(); - # TODO: retry send here - return false; - } elseif ($select > 0) { - $this->log->log("Socket is ready; send it.", Log::LEVEL_VERBOSE); - } else { - $this->log->log("Socket is not ready; break.", Log::LEVEL_ERROR); - return false; - } - - $sentbytes = @fwrite($this->socket, $msg); - $this->log->log("SENT: " . mb_substr($msg, 0, $sentbytes, '8bit'), Log::LEVEL_VERBOSE); - if ($sentbytes === FALSE) { - $this->log->log("ERROR sending message; reconnecting.", Log::LEVEL_ERROR); - $this->doReconnect(); - return false; - } - $this->log->log("Successfully sent $sentbytes bytes.", Log::LEVEL_VERBOSE); - return $sentbytes; - } - - /** - * Reconnect XMPP Host - * @throws Exception - */ - public function doReconnect() - { - if (!$this->is_server) { - $this->log->log("Reconnecting ($this->reconnectTimeout)...", Log::LEVEL_WARNING); - $this->connect($this->reconnectTimeout, false, false); - $this->reset(); - $this->event('reconnect'); - } - } - - /** - * Connect to XMPP Host - * - * @param integer $timeout - * @param boolean $persistent - * @param boolean $sendinit - * @throws Exception - * @throws Exception - */ - public function connect($timeout = 30, $persistent = false, $sendinit = true) - { - $this->sent_disconnect = false; - $starttime = time(); - - do { - $this->disconnected = false; - $this->sent_disconnect = false; - if ($persistent) { - $conflag = STREAM_CLIENT_CONNECT | STREAM_CLIENT_PERSISTENT; - } else { - $conflag = STREAM_CLIENT_CONNECT; - } - $conntype = 'tcp'; - if ($this->use_ssl) $conntype = 'ssl'; - $this->log->log("Connecting to $conntype://{$this->host}:{$this->port}"); - $this->socket = @stream_socket_client("$conntype://{$this->host}:{$this->port}", $errno, $errstr, $timeout, $conflag); - if (!$this->socket) { - $this->log->log("Could not connect.", Log::LEVEL_ERROR); - $this->disconnected = true; - # Take it easy for a few seconds - sleep(min($timeout, 5)); - } - } while (!$this->socket && (time() - $starttime) < $timeout); - - if ($this->socket) { - stream_set_blocking($this->socket, 1); - if ($sendinit) $this->send($this->stream_start); - } else { - throw new Exception("Could not connect before timeout."); - } - } - - /** - * Reset connection - */ - public function reset() - { - $this->xml_depth = 0; - unset($this->xmlobj); - $this->xmlobj = array(); - $this->setupParser(); - if (!$this->is_server) { - $this->send($this->stream_start); - } - $this->been_reset = true; - } - - /** - * Event? - * - * @param string $name - * @param string $payload - */ - public function event($name, $payload = null) - { - $this->log->log("EVENT: $name", Log::LEVEL_DEBUG); - foreach ($this->eventhandlers as $handler) { - if ($name == $handler[0]) { - if ($handler[2] === null) { - $handler[2] = $this; - } - $handler[2]->{$handler[1]}($payload); - } - } - foreach ($this->until as $key => $until) { - if (is_array($until)) { - if (in_array($name, $until)) { - $this->until_payload[$key][] = array($name, $payload); - if (!isset($this->until_count[$key])) { - $this->until_count[$key] = 0; - } - $this->until_count[$key] += 1; - #$this->until[$key] = false; - } - } - } - } - - /** - * Process until a specified event or a timeout occurs - * - * @param string|array $event - * @param integer $timeout - * @return string - * @throws Exception - */ - public function processUntil($event, $timeout = -1) - { - $start = time(); - if (!is_array($event)) $event = array($event); - $this->until[] = $event; - end($this->until); - $event_key = key($this->until); - reset($this->until); - $this->until_count[$event_key] = 0; - while (!$this->disconnected and $this->until_count[$event_key] < 1 and (time() - $start < $timeout or $timeout == -1)) { - $this->__process(); - } - if (array_key_exists($event_key, $this->until_payload)) { - $payload = $this->until_payload[$event_key]; - unset($this->until_payload[$event_key]); - unset($this->until_count[$event_key]); - unset($this->until[$event_key]); - } else { - $payload = array(); - } - return $payload; - } - - /** - * Core reading tool - * 0 -> only read if data is immediately ready - * NULL -> wait forever and ever - * integer -> process for this amount of time - * @param int $maximum - * @return bool - * @throws Exception - */ - - private function __process($maximum = 5) - { - - $remaining = $maximum; - - do { - $starttime = (microtime(true) * 1000000); - $read = array($this->socket); - $write = array(); - $except = array(); - if (is_null($maximum)) { - $secs = NULL; - $usecs = NULL; - } else if ($maximum == 0) { - $secs = 0; - $usecs = 0; - } else { - $usecs = $remaining % 1000000; - $secs = floor(($remaining - $usecs) / 1000000); - } - $updated = @stream_select($read, $write, $except, $secs, $usecs); - if ($updated === false) { - $this->log->log("Error on stream_select()", Log::LEVEL_VERBOSE); - if ($this->reconnect) { - $this->doReconnect(); - } else { - fclose($this->socket); - $this->socket = NULL; - return false; - } - } else if ($updated > 0) { - # XXX: Is this big enough? - $buff = @fread($this->socket, 4096); - if (!$buff) { - if ($this->reconnect) { - $this->doReconnect(); - } else { - fclose($this->socket); - $this->socket = NULL; - return false; - } - } - $this->log->log("RECV: $buff", Log::LEVEL_VERBOSE); - xml_parse($this->parser, $buff, false); - } // Otherwise, - // $updated == 0 means no changes during timeout. - - $endtime = (microtime(true) * 1000000); - $time_past = $endtime - $starttime; - $remaining = $remaining - $time_past; - } while (is_null($maximum) || $remaining > 0); - return true; - } - - /** - * Return the log instance - * - * @return Log - */ - public function getLog() - { - return $this->log; - } - - /** - * Get next ID - * - * @return integer - */ - public function getId() - { - $this->lastid++; - return $this->lastid; - } - - /** - * Set SSL - * @param bool $use - */ - public function useSSL($use = true) - { - $this->use_ssl = $use; - } - - /** - * Add ID Handler - * - * @param integer $id - * @param string $pointer - * @param string $obj - */ - public function addIdHandler($id, $pointer, $obj = null) - { - $this->idhandlers[$id] = array($pointer, $obj); - } - - /** - * Add Handler - * - * @param string $name - * @param string $ns - * @param string $pointer - * @param string $obj - * @param integer $depth - */ - public function addHandler($name, $ns, $pointer, $obj = null, $depth = 1) - { - #TODO deprication warning - $this->nshandlers[] = array($name, $ns, $pointer, $obj, $depth); - } - - /** - * Add XPath Handler - * - * @param string $xpath - * @param string $pointer - * @param - */ - public function addXPathHandler($xpath, $pointer, $obj = null) - { - if (preg_match_all("/\(?{[^\}]+}\)?(\/?)[^\/]+/", $xpath, $regs)) { - $ns_tags = $regs[0]; - } else { - $ns_tags = array($xpath); - } - foreach ($ns_tags as $ns_tag) { - list($l, $r) = explode("}", $ns_tag); - if ($r != null) { - $xpart = array(substr($l, 1), $r); - } else { - $xpart = array(null, $l); - } - $xpath_array[] = $xpart; - } - $this->xpathhandlers[] = array($xpath_array, $pointer, $obj); - } - - /** - * Add Event Handler - * - * @param $name - * @param string $pointer - * @param string $obj - */ - public function addEventHandler($name, $pointer, $obj) - { - $this->eventhandlers[] = array($name, $pointer, $obj); - } - - public function setReconnectTimeout($timeout) - { - $this->reconnectTimeout = $timeout; - } - - /** - * Are we are disconnected? - * - * @return boolean - */ - public function isDisconnected() - { - return $this->disconnected; - } - - /** - * Process - * - */ - public function process() - { - $this->__process(NULL); - } - - /** - * Process until a timeout occurs - * - * @param integer $timeout - * @return string - * @throws Exception - */ - public function processTime($timeout = NULL) - { - if (is_null($timeout)) { - return $this->__process(NULL); - } else { - return $this->__process($timeout * 1000000); - } - } - - /** - * Obsolete? - * @param $socket - */ - public function Xapply_socket($socket) - { - $this->socket = $socket; - } - - /** - * XML start callback - * - * @param resource $parser - * @param string $name - * @param $attr - * @see xml_set_element_handler - */ - public function startXML($parser, $name, $attr) - { - if ($this->been_reset) { - $this->been_reset = false; - $this->xml_depth = 0; - } - $this->xml_depth++; - if (array_key_exists('XMLNS', $attr)) { - $this->current_ns[$this->xml_depth] = $attr['XMLNS']; - } else { - $this->current_ns[$this->xml_depth] = $this->current_ns[$this->xml_depth - 1]; - if (!$this->current_ns[$this->xml_depth]) $this->current_ns[$this->xml_depth] = $this->default_ns; - } - $ns = $this->current_ns[$this->xml_depth]; - foreach ($attr as $key => $value) { - if (strstr($key, ":")) { - $key = explode(':', $key); - $key = $key[1]; - $this->ns_map[$key] = $value; - } - } - if (!strstr($name, ":") === false) { - $name = explode(':', $name); - $ns = $this->ns_map[$name[0]]; - $name = $name[1]; - } - $obj = new XMLObj($name, $ns, $attr); - if ($this->xml_depth > 1) { - $this->xmlobj[$this->xml_depth - 1]->subs[] = $obj; - } - $this->xmlobj[$this->xml_depth] = $obj; - } - - /** - * XML end callback - * - * @param resource $parser - * @param string $name - * @throws Exception - * @see xml_set_element_handler - * - */ - public function endXML($parser, $name) - { - #$this->log->log("Ending $name", Log::LEVEL_DEBUG); - #print "$name\n"; - if ($this->been_reset) { - $this->been_reset = false; - $this->xml_depth = 0; - } - $this->xml_depth--; - if ($this->xml_depth == 1) { - #clean-up old objects - #$found = false; #FIXME This didn't appear to be in use --Gar - foreach ($this->xpathhandlers as $handler) { - if (is_array($this->xmlobj) && array_key_exists(2, $this->xmlobj)) { - $searchxml = $this->xmlobj[2]; - $nstag = array_shift($handler[0]); - if (($nstag[0] == null or $searchxml->ns == $nstag[0]) and ($nstag[1] == "*" or $nstag[1] == $searchxml->name)) { - foreach ($handler[0] as $nstag) { - if ($searchxml !== null and $searchxml->hasSub($nstag[1], $ns = $nstag[0])) { - $searchxml = $searchxml->sub($nstag[1], $ns = $nstag[0]); - } else { - $searchxml = null; - break; - } - } - if ($searchxml !== null) { - if ($handler[2] === null) $handler[2] = $this; - $this->log->log("Calling {$handler[1]}", Log::LEVEL_DEBUG); - $handler[2]->{$handler[1]}($this->xmlobj[2]); - } - } - } - } - foreach ($this->nshandlers as $handler) { - if ($handler[4] != 1 and array_key_exists(2, $this->xmlobj) and $this->xmlobj[2]->hasSub($handler[0])) { - $searchxml = $this->xmlobj[2]->sub($handler[0]); - } elseif (is_array($this->xmlobj) and array_key_exists(2, $this->xmlobj)) { - $searchxml = $this->xmlobj[2]; - } - if ($searchxml !== null and $searchxml->name == $handler[0] and ($searchxml->ns == $handler[1] or (!$handler[1] and $searchxml->ns == $this->default_ns))) { - if ($handler[3] === null) $handler[3] = $this; - $this->log->log("Calling {$handler[2]}", Log::LEVEL_DEBUG); - $handler[3]->{$handler[2]}($this->xmlobj[2]); - } - } - foreach ($this->idhandlers as $id => $handler) { - if (array_key_exists('id', $this->xmlobj[2]->attrs) and $this->xmlobj[2]->attrs['id'] == $id) { - if ($handler[1] === null) $handler[1] = $this; - $handler[1]->{$handler[0]}($this->xmlobj[2]); - #id handlers are only used once - unset($this->idhandlers[$id]); - break; - } - } - if (is_array($this->xmlobj)) { - $this->xmlobj = array_slice($this->xmlobj, 0, 1); - if (isset($this->xmlobj[0]) && $this->xmlobj[0] instanceof XMLObj) { - $this->xmlobj[0]->subs = null; - } - } - unset($this->xmlobj[2]); - } - if ($this->xml_depth == 0 and !$this->been_reset) { - if (!$this->disconnected) { - if (!$this->sent_disconnect) { - $this->send($this->stream_end); - } - $this->disconnected = true; - $this->sent_disconnect = true; - fclose($this->socket); - if ($this->reconnect) { - $this->doReconnect(); - } - } - $this->event('end_stream'); - } - } - - /** - * XML character callback - * @param resource $parser - * @param string $data - * @see xml_set_character_data_handler - * - */ - public function charXML($parser, $data) - { - if (array_key_exists($this->xml_depth, $this->xmlobj)) { - $this->xmlobj[$this->xml_depth]->data .= $data; - } - } - - /** - * Read from socket - */ - public function read() - { - $buff = @fread($this->socket, 1024); - if (!$buff) { - if ($this->reconnect) { - $this->doReconnect(); - } else { - fclose($this->socket); - return false; - } - } - $this->log->log("RECV: $buff", Log::LEVEL_VERBOSE); - xml_parse($this->parser, $buff, false); - } - - public function time() - { - list($usec, $sec) = explode(" ", microtime()); - return (float)$sec + (float)$usec; - } - - public function readyToProcess() - { - $read = array($this->socket); - $write = array(); - $except = array(); - $updated = @stream_select($read, $write, $except, 0); - return (($updated !== false) && ($updated > 0)); - } -} diff --git a/plugins/Xmpp/extlib/XMPPHP/XMPP.php b/plugins/Xmpp/extlib/XMPPHP/XMPP.php deleted file mode 100644 index 55b58db0fd..0000000000 --- a/plugins/Xmpp/extlib/XMPPHP/XMPP.php +++ /dev/null @@ -1,477 +0,0 @@ - - * @author Stephan Wentz - * @author Michael Garvin - * @author Alexander Birkner (https://github.com/BirknerAlex) - * @author zorn-v (https://github.com/zorn-v/xmpphp/) - * @author GNU social - * @copyright 2008 Nathanael C. Fritz - */ - -namespace XMPPHP; - -/** XMPPHP_XMLStream */ -require_once __DIR__ . DIRECTORY_SEPARATOR . 'XMLStream.php'; -require_once __DIR__ . DIRECTORY_SEPARATOR . 'Roster.php'; - - -/** - * XMPPHP XMPP - * - * @package XMPPHP - * @author Nathanael C. Fritz - * @author Stephan Wentz - * @author Michael Garvin - * @copyright 2008 Nathanael C. Fritz - * @version $Id$ - */ -class XMPP extends XMLStream -{ - /** - * @var string - */ - public $server; - - /** - * @var string - */ - public $user; - /** - * @var boolean - */ - public $track_presence = true; - /** - * @var object - */ - public $roster; - /** - * @var string - */ - protected $password; - /** - * @var string - */ - protected $resource; - /** - * @var string - */ - protected $fulljid; - /** - * @var string - */ - protected $basejid; - /** - * @var boolean - */ - protected $authed = false; - protected $session_started = false; - /** - * @var boolean - */ - protected $auto_subscribe = false; - /** - * @var boolean - */ - protected $use_encryption = true; - - /** - * Constructor - * - * @param string $host - * @param integer $port - * @param string $user - * @param string $password - * @param string $resource - * @param string $server - * @param boolean $printlog - * @param string $loglevel - */ - public function __construct($host, $port, $user, $password, $resource, $server = null, $printlog = false, $loglevel = null) - { - parent::__construct($host, $port, $printlog, $loglevel); - - $this->user = $user; - $this->password = $password; - $this->resource = $resource; - if (!$server) { - $server = $host; - } - $this->server = $server; - $this->basejid = $this->user . '@' . $this->host; - - $this->roster = new Roster(); - $this->track_presence = true; - - $this->stream_start = ''; - $this->stream_end = ''; - $this->default_ns = 'jabber:client'; - - $this->addXPathHandler('{http://etherx.jabber.org/streams}features', 'features_handler'); - $this->addXPathHandler('{urn:ietf:params:xml:ns:xmpp-sasl}success', 'sasl_success_handler'); - $this->addXPathHandler('{urn:ietf:params:xml:ns:xmpp-sasl}failure', 'sasl_failure_handler'); - $this->addXPathHandler('{urn:ietf:params:xml:ns:xmpp-tls}proceed', 'tls_proceed_handler'); - $this->addXPathHandler('{jabber:client}message', 'message_handler'); - $this->addXPathHandler('{jabber:client}presence', 'presence_handler'); - $this->addXPathHandler('iq/{jabber:iq:roster}query', 'roster_iq_handler'); - } - - /** - * Turn encryption on/ff - * - * @param boolean $useEncryption - */ - public function useEncryption($useEncryption = true) - { - $this->use_encryption = $useEncryption; - } - - /** - * Turn on auto-authorization of subscription requests. - * - * @param boolean $autoSubscribe - */ - public function autoSubscribe($autoSubscribe = true) - { - $this->auto_subscribe = $autoSubscribe; - } - - /** - * Send XMPP Message - * - * @param string $to - * @param string $body - * @param string $type - * @param string $subject - * @param null $payload - * @throws Exception - */ - public function message($to, $body, $type = 'chat', $subject = null, $payload = null) - { - if ($this->disconnected) { - throw new Exception('You need to connect first'); - } - - if (empty($type)) { - $type = 'chat'; - } - - $to = htmlspecialchars($to); - $body = htmlspecialchars($body); - $subject = htmlspecialchars($subject); - $subject = ($subject) ? '' . $subject . '' : ''; - $payload = ($payload) ? $payload : ''; - $sprintf = '%s%s%s'; - $output = sprintf($sprintf, $this->fulljid, $to, $type, $subject, $body, $payload); - $this->send($output); - } - - /** - * Set Presence - * - * @param string $status - * @param string $show - * @param string $to - * @param string $type - * @param null $priority - * @throws Exception - */ - public function presence($status = null, $show = 'available', $to = null, $type = 'available', $priority = null) - { - if ($this->disconnected) { - throw new Exception('You need to connect first'); - } - - if ($type == 'available') { - $type = ''; - } - $to = htmlspecialchars($to); - $status = htmlspecialchars($status); - if ($show == 'unavailable') { - $type = 'unavailable'; - } - - $out = "send($out); - } - - /** - * Send Auth request - * - * @param string $jid - */ - public function subscribe($jid) - { - $this->send(""); - #$this->send(""); - } - - /** - * Message handler - * - * @param string $xml - */ - public function message_handler($xml) - { - if (isset($xml->attrs['type'])) { - $payload['type'] = $xml->attrs['type']; - } else { - $payload['type'] = 'chat'; - } - $body = $xml->sub('body'); - $payload['from'] = $xml->attrs['from']; - $payload['body'] = is_object($body) ? $body->data : false; // $xml->sub('body')->data; - $payload['xml'] = $xml; - $this->log->log("Message: {$payload['body']}", Log::LEVEL_DEBUG); - $this->event('message', $payload); - } - - /** - * Presence handler - * - * @param string $xml - */ - public function presence_handler($xml) - { - $payload['type'] = (isset($xml->attrs['type'])) ? $xml->attrs['type'] : 'available'; - $payload['show'] = (isset($xml->sub('show')->data)) ? $xml->sub('show')->data : $payload['type']; - $payload['from'] = $xml->attrs['from']; - $payload['status'] = (isset($xml->sub('status')->data)) ? $xml->sub('status')->data : ''; - $payload['priority'] = (isset($xml->sub('priority')->data)) ? intval($xml->sub('priority')->data) : 0; - $payload['xml'] = $xml; - if ($this->track_presence) { - $this->roster->setPresence($payload['from'], $payload['priority'], $payload['show'], $payload['status']); - } - $this->log->log("Presence: {$payload['from']} [{$payload['show']}] {$payload['status']}", Log::LEVEL_DEBUG); - if (array_key_exists('type', $xml->attrs) and $xml->attrs['type'] == 'subscribe') { - if ($this->auto_subscribe) { - $this->send(""); - $this->send(""); - } - $this->event('subscription_requested', $payload); - } elseif (array_key_exists('type', $xml->attrs) and $xml->attrs['type'] == 'subscribed') { - $this->event('subscription_accepted', $payload); - } else { - $this->event('presence', $payload); - } - } - - /** - * Retrieves the roster - * - */ - public function getRoster() - { - $id = $this->getID(); - $this->send(""); - } - - /** - * Retrieves the vcard - * @param null $jid - */ - public function getVCard($jid = null) - { - $id = $this->getID(); - $this->addIdHandler($id, 'vcard_get_handler'); - if ($jid) { - $this->send(""); - } else { - $this->send(""); - } - } - - /** - * Features handler - * - * @param string $xml - */ - protected function features_handler($xml) - { - if ($xml->hasSub('starttls') and $this->use_encryption) { - $this->send(""); - } elseif ($xml->hasSub('bind') and $this->authed) { - $id = $this->getId(); - $this->addIdHandler($id, 'resource_bind_handler'); - $this->send("{$this->resource}"); - } else { - $this->log->log("Attempting Auth..."); - if ($this->password) { - $this->send("" . base64_encode("\x00" . $this->user . "\x00" . $this->password) . ""); - } else { - $this->send(""); - } - } - } - - /** - * SASL success handler - * - * @param string $xml - */ - protected function sasl_success_handler($xml) - { - $this->log->log("Auth success!"); - $this->authed = true; - $this->reset(); - } - - /** - * SASL feature handler - * - * @param string $xml - * @throws Exception - */ - protected function sasl_failure_handler($xml) - { - $this->log->log("Auth failed!", Log::LEVEL_ERROR); - $this->disconnect(); - - throw new Exception('Auth failed!'); - } - - /** - * Resource bind handler - * - * @param string $xml - */ - protected function resource_bind_handler($xml) - { - if ($xml->attrs['type'] == 'result') { - $this->log->log("Bound to " . $xml->sub('bind')->sub('jid')->data); - $this->fulljid = $xml->sub('bind')->sub('jid')->data; - $jidarray = explode('/', $this->fulljid); - $this->jid = $jidarray[0]; - } - $id = $this->getId(); - $this->addIdHandler($id, 'session_start_handler'); - $this->send(""); - } - - /** - * Roster iq handler - * Gets all packets matching XPath "iq/{jabber:iq:roster}query' - * - * @param string $xml - */ - protected function roster_iq_handler($xml) - { - $status = "result"; - $xmlroster = $xml->sub('query'); - foreach ($xmlroster->subs as $item) { - $groups = array(); - if ($item->name == 'item') { - $jid = $item->attrs['jid']; //REQUIRED - $name = $item->attrs['name']; //MAY - $subscription = $item->attrs['subscription']; - foreach ($item->subs as $subitem) { - if ($subitem->name == 'group') { - $groups[] = $subitem->data; - } - } - $contacts[] = array($jid, $subscription, $name, $groups); //Store for action if no errors happen - } else { - $status = "error"; - } - } - if ($status == "result") { //No errors, add contacts - foreach ($contacts as $contact) { - $this->roster->addContact($contact[0], $contact[1], $contact[2], $contact[3]); - } - } - if ($xml->attrs['type'] == 'set') { - $this->send("attrs['id']}\" to=\"{$xml->attrs['from']}\" />"); - } - } - - /** - * Session start handler - * - * @param string $xml - */ - protected function session_start_handler($xml) - { - $this->log->log("Session started"); - $this->session_started = true; - $this->event('session_start'); - } - - /** - * TLS proceed handler - * - * @param string $xml - */ - protected function tls_proceed_handler($xml) - { - $this->log->log("Starting TLS encryption"); - stream_socket_enable_crypto($this->socket, true, STREAM_CRYPTO_METHOD_SSLv23_CLIENT); - $this->reset(); - } - - /** - * VCard retrieval handler - * - * @param XMLObj $xml - */ - protected function vcard_get_handler($xml) - { - $vcard_array = array(); - $vcard = $xml->sub('vcard'); - // go through all of the sub elements and add them to the vcard array - foreach ($vcard->subs as $sub) { - if ($sub->subs) { - $vcard_array[$sub->name] = array(); - foreach ($sub->subs as $sub_child) { - $vcard_array[$sub->name][$sub_child->name] = $sub_child->data; - } - } else { - $vcard_array[$sub->name] = $sub->data; - } - } - $vcard_array['from'] = $xml->attrs['from']; - $this->event('vcard', $vcard_array); - } -} diff --git a/vendor/apereo/phpcas/.gitattributes b/vendor/apereo/phpcas/.gitattributes new file mode 100644 index 0000000000..3e28f4e425 --- /dev/null +++ b/vendor/apereo/phpcas/.gitattributes @@ -0,0 +1,7 @@ +/docs/ export-ignore +/test/ export-ignore +/utils/ export-ignore +/.buildpath export-ignore +/.gitignore export-ignore +/.project export-ignore +/.travis.yml export-ignore diff --git a/vendor/apereo/phpcas/CAS.php b/vendor/apereo/phpcas/CAS.php new file mode 100644 index 0000000000..8cd549ea35 --- /dev/null +++ b/vendor/apereo/phpcas/CAS.php @@ -0,0 +1,30 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +require_once dirname(__FILE__).'/source/CAS.php'; \ No newline at end of file diff --git a/vendor/apereo/phpcas/LICENSE b/vendor/apereo/phpcas/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/vendor/apereo/phpcas/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/apereo/phpcas/NOTICE b/vendor/apereo/phpcas/NOTICE new file mode 100644 index 0000000000..70d9ffcd4c --- /dev/null +++ b/vendor/apereo/phpcas/NOTICE @@ -0,0 +1,81 @@ +Copyright 2007-2011, JA-SIG, Inc. +This project includes software developed by Jasig. +http://www.jasig.org/ + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this software except in compliance with the License. +You may obtain a copy of the License at: + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +=========================================================================== + +Copyright © 2003-2007, The ESUP-Portail consortium + +Requirements for sources originally licensed under the New BSD License: + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +- Neither the name of JA-SIG, Inc. nor the names of its contributors may be +used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +=========================================================================== + +Copyright (c) 2009, Regents of the University of Nebraska +All rights reserved. + +Requirements for CAS_Autloader originally licensed under the New BSD License: + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of the University of Nebraska nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/apereo/phpcas/README.md b/vendor/apereo/phpcas/README.md new file mode 100644 index 0000000000..f425edca84 --- /dev/null +++ b/vendor/apereo/phpcas/README.md @@ -0,0 +1,36 @@ +phpCAS +======= + +phpCAS is an authentication library that allows PHP applications to easily authenticate +users via a Central Authentication Service (CAS) server. + +Please see the wiki website for more information: + +https://wiki.jasig.org/display/CASC/phpCAS + +Api documentation can be found here: + +https://apereo.github.io/phpCAS/ + + +[![Build Status](https://travis-ci.org/apereo/phpCAS.png)](https://travis-ci.org/apereo/phpCAS) + + +LICENSE +------- + +Copyright 2007-2015, JA-SIG, Inc. +This project includes software developed by Jasig. +http://www.jasig.org/ + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this software except in compliance with the License. +You may obtain a copy of the License at: + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/apereo/phpcas/composer.json b/vendor/apereo/phpcas/composer.json new file mode 100644 index 0000000000..603595b276 --- /dev/null +++ b/vendor/apereo/phpcas/composer.json @@ -0,0 +1,29 @@ +{ + "name": "apereo/phpcas", + "description": "Provides a simple API for authenticating users against a CAS server", + "keywords": ["cas", "jasig", "apereo"], + "homepage": "https://wiki.jasig.org/display/CASC/phpCAS", + "type": "library", + "license": "Apache-2.0", + "authors": [ + {"name": "Joachim Fritschi", "homepage": "https://wiki.jasig.org/display/~fritschi"}, + {"name": "Adam Franco", "homepage": "https://wiki.jasig.org/display/~adamfranco"} + ], + "require": { + "php": ">=5.4.0", + "ext-curl": "*" + }, + "require-dev": { + "phpunit/phpunit": "~3.7.10" + }, + "autoload": { + "classmap": [ + "source/" + ] + }, + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + } +} diff --git a/vendor/apereo/phpcas/source/CAS.php b/vendor/apereo/phpcas/source/CAS.php new file mode 100644 index 0000000000..dd17a48e4e --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS.php @@ -0,0 +1,2034 @@ + + * @author Olivier Berger + * @author Brett Bieber + * @author Joachim Fritschi + * @author Adam Franco + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + * @ingroup public + */ + + +// +// hack by Vangelis Haniotakis to handle the absence of $_SERVER['REQUEST_URI'] +// in IIS +// +if (!isset($_SERVER['REQUEST_URI']) && isset($_SERVER['SCRIPT_NAME']) && isset($_SERVER['QUERY_STRING'])) { + $_SERVER['REQUEST_URI'] = $_SERVER['SCRIPT_NAME'] . '?' . $_SERVER['QUERY_STRING']; +} + +// Add a E_USER_DEPRECATED for php versions <= 5.2 +if (!defined('E_USER_DEPRECATED')) { + define('E_USER_DEPRECATED', E_USER_NOTICE); +} + + +// ######################################################################## +// CONSTANTS +// ######################################################################## + +// ------------------------------------------------------------------------ +// CAS VERSIONS +// ------------------------------------------------------------------------ + +/** + * phpCAS version. accessible for the user by phpCAS::getVersion(). + */ +define('PHPCAS_VERSION', '1.3.7'); + +/** + * @addtogroup public + * @{ + */ + +/** + * phpCAS supported protocols. accessible for the user by phpCAS::getSupportedProtocols(). + */ + +/** + * CAS version 1.0 + */ +define("CAS_VERSION_1_0", '1.0'); +/*! + * CAS version 2.0 +*/ +define("CAS_VERSION_2_0", '2.0'); +/** + * CAS version 3.0 + */ +define("CAS_VERSION_3_0", '3.0'); + +// ------------------------------------------------------------------------ +// SAML defines +// ------------------------------------------------------------------------ + +/** + * SAML protocol + */ +define("SAML_VERSION_1_1", 'S1'); + +/** + * XML header for SAML POST + */ +define("SAML_XML_HEADER", ''); + +/** + * SOAP envelope for SAML POST + */ +define("SAML_SOAP_ENV", ''); + +/** + * SOAP body for SAML POST + */ +define("SAML_SOAP_BODY", ''); + +/** + * SAMLP request + */ +define("SAMLP_REQUEST", ''); +define("SAMLP_REQUEST_CLOSE", ''); + +/** + * SAMLP artifact tag (for the ticket) + */ +define("SAML_ASSERTION_ARTIFACT", ''); + +/** + * SAMLP close + */ +define("SAML_ASSERTION_ARTIFACT_CLOSE", ''); + +/** + * SOAP body close + */ +define("SAML_SOAP_BODY_CLOSE", ''); + +/** + * SOAP envelope close + */ +define("SAML_SOAP_ENV_CLOSE", ''); + +/** + * SAML Attributes + */ +define("SAML_ATTRIBUTES", 'SAMLATTRIBS'); + +/** + * SAML Attributes + */ +define("DEFAULT_ERROR", 'Internal script failure'); + +/** @} */ +/** + * @addtogroup publicPGTStorage + * @{ + */ +// ------------------------------------------------------------------------ +// FILE PGT STORAGE +// ------------------------------------------------------------------------ +/** + * Default path used when storing PGT's to file + */ +define("CAS_PGT_STORAGE_FILE_DEFAULT_PATH", session_save_path()); +/** @} */ +// ------------------------------------------------------------------------ +// SERVICE ACCESS ERRORS +// ------------------------------------------------------------------------ +/** + * @addtogroup publicServices + * @{ + */ + +/** + * phpCAS::service() error code on success + */ +define("PHPCAS_SERVICE_OK", 0); +/** + * phpCAS::service() error code when the PT could not retrieve because + * the CAS server did not respond. + */ +define("PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE", 1); +/** + * phpCAS::service() error code when the PT could not retrieve because + * the response of the CAS server was ill-formed. + */ +define("PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE", 2); +/** + * phpCAS::service() error code when the PT could not retrieve because + * the CAS server did not want to. + */ +define("PHPCAS_SERVICE_PT_FAILURE", 3); +/** + * phpCAS::service() error code when the service was not available. + */ +define("PHPCAS_SERVICE_NOT_AVAILABLE", 4); + +// ------------------------------------------------------------------------ +// SERVICE TYPES +// ------------------------------------------------------------------------ +/** + * phpCAS::getProxiedService() type for HTTP GET + */ +define("PHPCAS_PROXIED_SERVICE_HTTP_GET", 'CAS_ProxiedService_Http_Get'); +/** + * phpCAS::getProxiedService() type for HTTP POST + */ +define("PHPCAS_PROXIED_SERVICE_HTTP_POST", 'CAS_ProxiedService_Http_Post'); +/** + * phpCAS::getProxiedService() type for IMAP + */ +define("PHPCAS_PROXIED_SERVICE_IMAP", 'CAS_ProxiedService_Imap'); + + +/** @} */ +// ------------------------------------------------------------------------ +// LANGUAGES +// ------------------------------------------------------------------------ +/** + * @addtogroup publicLang + * @{ + */ + +define("PHPCAS_LANG_ENGLISH", 'CAS_Languages_English'); +define("PHPCAS_LANG_FRENCH", 'CAS_Languages_French'); +define("PHPCAS_LANG_GREEK", 'CAS_Languages_Greek'); +define("PHPCAS_LANG_GERMAN", 'CAS_Languages_German'); +define("PHPCAS_LANG_JAPANESE", 'CAS_Languages_Japanese'); +define("PHPCAS_LANG_SPANISH", 'CAS_Languages_Spanish'); +define("PHPCAS_LANG_CATALAN", 'CAS_Languages_Catalan'); +define("PHPCAS_LANG_CHINESE_SIMPLIFIED", 'CAS_Languages_ChineseSimplified'); + +/** @} */ + +/** + * @addtogroup internalLang + * @{ + */ + +/** + * phpCAS default language (when phpCAS::setLang() is not used) + */ +define("PHPCAS_LANG_DEFAULT", PHPCAS_LANG_ENGLISH); + +/** @} */ +// ------------------------------------------------------------------------ +// DEBUG +// ------------------------------------------------------------------------ +/** + * @addtogroup publicDebug + * @{ + */ + +/** + * The default directory for the debug file under Unix. + * @return string directory for the debug file + */ +function gettmpdir() { +if (!empty($_ENV['TMP'])) { return realpath($_ENV['TMP']); } +if (!empty($_ENV['TMPDIR'])) { return realpath( $_ENV['TMPDIR']); } +if (!empty($_ENV['TEMP'])) { return realpath( $_ENV['TEMP']); } +return "/tmp"; +} +define('DEFAULT_DEBUG_DIR', gettmpdir()."/"); + +/** @} */ + +// include the class autoloader +require_once dirname(__FILE__) . '/CAS/Autoload.php'; + +/** + * The phpCAS class is a simple container for the phpCAS library. It provides CAS + * authentication for web applications written in PHP. + * + * @ingroup public + * @class phpCAS + * @category Authentication + * @package PhpCAS + * @author Pascal Aubry + * @author Olivier Berger + * @author Brett Bieber + * @author Joachim Fritschi + * @author Adam Franco + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +class phpCAS +{ + + /** + * This variable is used by the interface class phpCAS. + * + * @var CAS_Client + * @hideinitializer + */ + private static $_PHPCAS_CLIENT; + + /** + * @var array + * This variable is used to store where the initializer is called from + * (to print a comprehensive error in case of multiple calls). + * + * @hideinitializer + */ + private static $_PHPCAS_INIT_CALL; + + /** + * @var array + * This variable is used to store phpCAS debug mode. + * + * @hideinitializer + */ + private static $_PHPCAS_DEBUG; + + /** + * This variable is used to enable verbose mode + * This pevents debug info to be show to the user. Since it's a security + * feature the default is false + * + * @hideinitializer + */ + private static $_PHPCAS_VERBOSE = false; + + + // ######################################################################## + // INITIALIZATION + // ######################################################################## + + /** + * @addtogroup publicInit + * @{ + */ + + /** + * phpCAS client initializer. + * + * @param string $server_version the version of the CAS server + * @param string $server_hostname the hostname of the CAS server + * @param int $server_port the port the CAS server is running on + * @param string $server_uri the URI the CAS server is responding on + * @param bool $changeSessionID Allow phpCAS to change the session_id (Single + * Sign Out/handleLogoutRequests is based on that change) + * + * @return void a newly created CAS_Client object + * @note Only one of the phpCAS::client() and phpCAS::proxy functions should be + * called, only once, and before all other methods (except phpCAS::getVersion() + * and phpCAS::setDebug()). + */ + public static function client($server_version, $server_hostname, + $server_port, $server_uri, $changeSessionID = true + ) { + phpCAS :: traceBegin(); + if (is_object(self::$_PHPCAS_CLIENT)) { + phpCAS :: error(self::$_PHPCAS_INIT_CALL['method'] . '() has already been called (at ' . self::$_PHPCAS_INIT_CALL['file'] . ':' . self::$_PHPCAS_INIT_CALL['line'] . ')'); + } + + // store where the initializer is called from + $dbg = debug_backtrace(); + self::$_PHPCAS_INIT_CALL = array ( + 'done' => true, + 'file' => $dbg[0]['file'], + 'line' => $dbg[0]['line'], + 'method' => __CLASS__ . '::' . __FUNCTION__ + ); + + // initialize the object $_PHPCAS_CLIENT + try { + self::$_PHPCAS_CLIENT = new CAS_Client( + $server_version, false, $server_hostname, $server_port, $server_uri, + $changeSessionID + ); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); + } + phpCAS :: traceEnd(); + } + + /** + * phpCAS proxy initializer. + * + * @param string $server_version the version of the CAS server + * @param string $server_hostname the hostname of the CAS server + * @param int $server_port the port the CAS server is running on + * @param string $server_uri the URI the CAS server is responding on + * @param bool $changeSessionID Allow phpCAS to change the session_id (Single + * Sign Out/handleLogoutRequests is based on that change) + * + * @return void a newly created CAS_Client object + * @note Only one of the phpCAS::client() and phpCAS::proxy functions should be + * called, only once, and before all other methods (except phpCAS::getVersion() + * and phpCAS::setDebug()). + */ + public static function proxy($server_version, $server_hostname, + $server_port, $server_uri, $changeSessionID = true + ) { + phpCAS :: traceBegin(); + if (is_object(self::$_PHPCAS_CLIENT)) { + phpCAS :: error(self::$_PHPCAS_INIT_CALL['method'] . '() has already been called (at ' . self::$_PHPCAS_INIT_CALL['file'] . ':' . self::$_PHPCAS_INIT_CALL['line'] . ')'); + } + + // store where the initialzer is called from + $dbg = debug_backtrace(); + self::$_PHPCAS_INIT_CALL = array ( + 'done' => true, + 'file' => $dbg[0]['file'], + 'line' => $dbg[0]['line'], + 'method' => __CLASS__ . '::' . __FUNCTION__ + ); + + // initialize the object $_PHPCAS_CLIENT + try { + self::$_PHPCAS_CLIENT = new CAS_Client( + $server_version, true, $server_hostname, $server_port, $server_uri, + $changeSessionID + ); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); + } + phpCAS :: traceEnd(); + } + + /** + * Answer whether or not the client or proxy has been initialized + * + * @return bool + */ + public static function isInitialized () + { + return (is_object(self::$_PHPCAS_CLIENT)); + } + + /** @} */ + // ######################################################################## + // DEBUGGING + // ######################################################################## + + /** + * @addtogroup publicDebug + * @{ + */ + + /** + * Set/unset debug mode + * + * @param string $filename the name of the file used for logging, or false + * to stop debugging. + * + * @return void + */ + public static function setDebug($filename = '') + { + if ($filename != false && gettype($filename) != 'string') { + phpCAS :: error('type mismatched for parameter $dbg (should be false or the name of the log file)'); + } + if ($filename === false) { + self::$_PHPCAS_DEBUG['filename'] = false; + + } else { + if (empty ($filename)) { + if (preg_match('/^Win.*/', getenv('OS'))) { + if (isset ($_ENV['TMP'])) { + $debugDir = $_ENV['TMP'] . '/'; + } else { + $debugDir = ''; + } + } else { + $debugDir = DEFAULT_DEBUG_DIR; + } + $filename = $debugDir . 'phpCAS.log'; + } + + if (empty (self::$_PHPCAS_DEBUG['unique_id'])) { + self::$_PHPCAS_DEBUG['unique_id'] = substr(strtoupper(md5(uniqid(''))), 0, 4); + } + + self::$_PHPCAS_DEBUG['filename'] = $filename; + self::$_PHPCAS_DEBUG['indent'] = 0; + + phpCAS :: trace('START ('.date("Y-m-d H:i:s").') phpCAS-' . PHPCAS_VERSION . ' ******************'); + } + } + + /** + * Enable verbose errors messages in the website output + * This is a security relevant since internal status info may leak an may + * help an attacker. Default is therefore false + * + * @param bool $verbose enable verbose output + * + * @return void + */ + public static function setVerbose($verbose) + { + if ($verbose === true) { + self::$_PHPCAS_VERBOSE = true; + } else { + self::$_PHPCAS_VERBOSE = false; + } + } + + + /** + * Show is verbose mode is on + * + * @return bool verbose + */ + public static function getVerbose() + { + return self::$_PHPCAS_VERBOSE; + } + + /** + * Logs a string in debug mode. + * + * @param string $str the string to write + * + * @return void + * @private + */ + public static function log($str) + { + $indent_str = "."; + + + if (!empty(self::$_PHPCAS_DEBUG['filename'])) { + // Check if file exists and modifiy file permissions to be only + // readable by the webserver + if (!file_exists(self::$_PHPCAS_DEBUG['filename'])) { + touch(self::$_PHPCAS_DEBUG['filename']); + // Chmod will fail on windows + @chmod(self::$_PHPCAS_DEBUG['filename'], 0600); + } + for ($i = 0; $i < self::$_PHPCAS_DEBUG['indent']; $i++) { + + $indent_str .= '| '; + } + // allow for multiline output with proper identing. Usefull for + // dumping cas answers etc. + $str2 = str_replace("\n", "\n" . self::$_PHPCAS_DEBUG['unique_id'] . ' ' . $indent_str, $str); + error_log(self::$_PHPCAS_DEBUG['unique_id'] . ' ' . $indent_str . $str2 . "\n", 3, self::$_PHPCAS_DEBUG['filename']); + } + + } + + /** + * This method is used by interface methods to print an error and where the + * function was originally called from. + * + * @param string $msg the message to print + * + * @return void + * @private + */ + public static function error($msg) + { + phpCAS :: traceBegin(); + $dbg = debug_backtrace(); + $function = '?'; + $file = '?'; + $line = '?'; + if (is_array($dbg)) { + for ($i = 1; $i < sizeof($dbg); $i++) { + if (is_array($dbg[$i]) && isset($dbg[$i]['class']) ) { + if ($dbg[$i]['class'] == __CLASS__) { + $function = $dbg[$i]['function']; + $file = $dbg[$i]['file']; + $line = $dbg[$i]['line']; + } + } + } + } + if (self::$_PHPCAS_VERBOSE) { + echo "
\nphpCAS error: " . __CLASS__ . "::" . $function . '(): ' . htmlentities($msg) . " in " . $file . " on line " . $line . "
\n"; + } else { + echo "
\nError: ". DEFAULT_ERROR ."
\n"; + } + phpCAS :: trace($msg . ' in ' . $file . 'on line ' . $line ); + phpCAS :: traceEnd(); + + throw new CAS_GracefullTerminationException(__CLASS__ . "::" . $function . '(): ' . $msg); + } + + /** + * This method is used to log something in debug mode. + * + * @param string $str string to log + * + * @return void + */ + public static function trace($str) + { + $dbg = debug_backtrace(); + phpCAS :: log($str . ' [' . basename($dbg[0]['file']) . ':' . $dbg[0]['line'] . ']'); + } + + /** + * This method is used to indicate the start of the execution of a function + * in debug mode. + * + * @return void + */ + public static function traceBegin() + { + $dbg = debug_backtrace(); + $str = '=> '; + if (!empty ($dbg[1]['class'])) { + $str .= $dbg[1]['class'] . '::'; + } + $str .= $dbg[1]['function'] . '('; + if (is_array($dbg[1]['args'])) { + foreach ($dbg[1]['args'] as $index => $arg) { + if ($index != 0) { + $str .= ', '; + } + if (is_object($arg)) { + $str .= get_class($arg); + } else { + $str .= str_replace(array("\r\n", "\n", "\r"), "", var_export($arg, true)); + } + } + } + if (isset($dbg[1]['file'])) { + $file = basename($dbg[1]['file']); + } else { + $file = 'unknown_file'; + } + if (isset($dbg[1]['line'])) { + $line = $dbg[1]['line']; + } else { + $line = 'unknown_line'; + } + $str .= ') [' . $file . ':' . $line . ']'; + phpCAS :: log($str); + if (!isset(self::$_PHPCAS_DEBUG['indent'])) { + self::$_PHPCAS_DEBUG['indent'] = 0; + } else { + self::$_PHPCAS_DEBUG['indent']++; + } + } + + /** + * This method is used to indicate the end of the execution of a function in + * debug mode. + * + * @param mixed $res the result of the function + * + * @return void + */ + public static function traceEnd($res = '') + { + if (empty(self::$_PHPCAS_DEBUG['indent'])) { + self::$_PHPCAS_DEBUG['indent'] = 0; + } else { + self::$_PHPCAS_DEBUG['indent']--; + } + $str = ''; + if (is_object($res)) { + $str .= '<= ' . get_class($res); + } else { + $str .= '<= ' . str_replace(array("\r\n", "\n", "\r"), "", var_export($res, true)); + } + + phpCAS :: log($str); + } + + /** + * This method is used to indicate the end of the execution of the program + * + * @return void + */ + public static function traceExit() + { + phpCAS :: log('exit()'); + while (self::$_PHPCAS_DEBUG['indent'] > 0) { + phpCAS :: log('-'); + self::$_PHPCAS_DEBUG['indent']--; + } + } + + /** @} */ + // ######################################################################## + // INTERNATIONALIZATION + // ######################################################################## + /** + * @addtogroup publicLang + * @{ + */ + + /** + * This method is used to set the language used by phpCAS. + * + * @param string $lang string representing the language. + * + * @return void + * + * @sa PHPCAS_LANG_FRENCH, PHPCAS_LANG_ENGLISH + * @note Can be called only once. + */ + public static function setLang($lang) + { + phpCAS::_validateClientExists(); + + try { + self::$_PHPCAS_CLIENT->setLang($lang); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); + } + } + + /** @} */ + // ######################################################################## + // VERSION + // ######################################################################## + /** + * @addtogroup public + * @{ + */ + + /** + * This method returns the phpCAS version. + * + * @return string the phpCAS version. + */ + public static function getVersion() + { + return PHPCAS_VERSION; + } + + /** + * This method returns supported protocols. + * + * @return array an array of all supported protocols. Use internal protocol name as array key. + */ + public static function getSupportedProtocols() + { + $supportedProtocols = array(); + $supportedProtocols[CAS_VERSION_1_0] = 'CAS 1.0'; + $supportedProtocols[CAS_VERSION_2_0] = 'CAS 2.0'; + $supportedProtocols[CAS_VERSION_3_0] = 'CAS 3.0'; + $supportedProtocols[SAML_VERSION_1_1] = 'SAML 1.1'; + + return $supportedProtocols; + } + + /** @} */ + // ######################################################################## + // HTML OUTPUT + // ######################################################################## + /** + * @addtogroup publicOutput + * @{ + */ + + /** + * This method sets the HTML header used for all outputs. + * + * @param string $header the HTML header. + * + * @return void + */ + public static function setHTMLHeader($header) + { + phpCAS::_validateClientExists(); + + try { + self::$_PHPCAS_CLIENT->setHTMLHeader($header); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); + } + } + + /** + * This method sets the HTML footer used for all outputs. + * + * @param string $footer the HTML footer. + * + * @return void + */ + public static function setHTMLFooter($footer) + { + phpCAS::_validateClientExists(); + + try { + self::$_PHPCAS_CLIENT->setHTMLFooter($footer); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); + } + } + + /** @} */ + // ######################################################################## + // PGT STORAGE + // ######################################################################## + /** + * @addtogroup publicPGTStorage + * @{ + */ + + /** + * This method can be used to set a custom PGT storage object. + * + * @param CAS_PGTStorage_AbstractStorage $storage a PGT storage object that inherits from the + * CAS_PGTStorage_AbstractStorage class + * + * @return void + */ + public static function setPGTStorage($storage) + { + phpCAS :: traceBegin(); + phpCAS::_validateProxyExists(); + + try { + self::$_PHPCAS_CLIENT->setPGTStorage($storage); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); + } + phpCAS :: traceEnd(); + } + + /** + * This method is used to tell phpCAS to store the response of the + * CAS server to PGT requests in a database. + * + * @param string $dsn_or_pdo a dsn string to use for creating a PDO + * object or a PDO object + * @param string $username the username to use when connecting to the + * database + * @param string $password the password to use when connecting to the + * database + * @param string $table the table to use for storing and retrieving + * PGT's + * @param string $driver_options any driver options to use when connecting + * to the database + * + * @return void + */ + public static function setPGTStorageDb($dsn_or_pdo, $username='', + $password='', $table='', $driver_options=null + ) { + phpCAS :: traceBegin(); + phpCAS::_validateProxyExists(); + + try { + self::$_PHPCAS_CLIENT->setPGTStorageDb($dsn_or_pdo, $username, $password, $table, $driver_options); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); + } + phpCAS :: traceEnd(); + } + + /** + * This method is used to tell phpCAS to store the response of the + * CAS server to PGT requests onto the filesystem. + * + * @param string $path the path where the PGT's should be stored + * + * @return void + */ + public static function setPGTStorageFile($path = '') + { + phpCAS :: traceBegin(); + phpCAS::_validateProxyExists(); + + try { + self::$_PHPCAS_CLIENT->setPGTStorageFile($path); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); + } + phpCAS :: traceEnd(); + } + /** @} */ + // ######################################################################## + // ACCESS TO EXTERNAL SERVICES + // ######################################################################## + /** + * @addtogroup publicServices + * @{ + */ + + /** + * Answer a proxy-authenticated service handler. + * + * @param string $type The service type. One of + * PHPCAS_PROXIED_SERVICE_HTTP_GET; PHPCAS_PROXIED_SERVICE_HTTP_POST; + * PHPCAS_PROXIED_SERVICE_IMAP + * + * @return CAS_ProxiedService + * @throws InvalidArgumentException If the service type is unknown. + */ + public static function getProxiedService ($type) + { + phpCAS :: traceBegin(); + phpCAS::_validateProxyExists(); + + try { + $res = self::$_PHPCAS_CLIENT->getProxiedService($type); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); + } + + phpCAS :: traceEnd(); + return $res; + } + + /** + * Initialize a proxied-service handler with the proxy-ticket it should use. + * + * @param CAS_ProxiedService $proxiedService Proxied Service Handler + * + * @return void + * @throws CAS_ProxyTicketException If there is a proxy-ticket failure. + * The code of the Exception will be one of: + * PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE + * PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE + * PHPCAS_SERVICE_PT_FAILURE + */ + public static function initializeProxiedService (CAS_ProxiedService $proxiedService) + { + phpCAS::_validateProxyExists(); + + try { + self::$_PHPCAS_CLIENT->initializeProxiedService($proxiedService); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); + } + } + + /** + * This method is used to access an HTTP[S] service. + * + * @param string $url the service to access. + * @param int &$err_code an error code Possible values are + * PHPCAS_SERVICE_OK (on success), PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE, + * PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE, PHPCAS_SERVICE_PT_FAILURE, + * PHPCAS_SERVICE_NOT_AVAILABLE. + * @param string &$output the output of the service (also used to give an + * error message on failure). + * + * @return bool true on success, false otherwise (in this later case, + * $err_code gives the reason why it failed and $output contains an error + * message). + */ + public static function serviceWeb($url, & $err_code, & $output) + { + phpCAS :: traceBegin(); + phpCAS::_validateProxyExists(); + + try { + $res = self::$_PHPCAS_CLIENT->serviceWeb($url, $err_code, $output); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); + } + + phpCAS :: traceEnd($res); + return $res; + } + + /** + * This method is used to access an IMAP/POP3/NNTP service. + * + * @param string $url a string giving the URL of the service, + * including the mailing box for IMAP URLs, as accepted by imap_open(). + * @param string $service a string giving for CAS retrieve Proxy ticket + * @param string $flags options given to imap_open(). + * @param int &$err_code an error code Possible values are + * PHPCAS_SERVICE_OK (on success), PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE, + * PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE, PHPCAS_SERVICE_PT_FAILURE, + * PHPCAS_SERVICE_NOT_AVAILABLE. + * @param string &$err_msg an error message on failure + * @param string &$pt the Proxy Ticket (PT) retrieved from the CAS + * server to access the URL on success, false on error). + * + * @return object|false IMAP stream on success, false otherwise (in this later + * case, $err_code gives the reason why it failed and $err_msg contains an + * error message). + */ + public static function serviceMail($url, $service, $flags, & $err_code, & $err_msg, & $pt) + { + phpCAS :: traceBegin(); + phpCAS::_validateProxyExists(); + + try { + $res = self::$_PHPCAS_CLIENT->serviceMail($url, $service, $flags, $err_code, $err_msg, $pt); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); + } + + phpCAS :: traceEnd($res); + return $res; + } + + /** @} */ + // ######################################################################## + // AUTHENTICATION + // ######################################################################## + /** + * @addtogroup publicAuth + * @{ + */ + + /** + * Set the times authentication will be cached before really accessing the + * CAS server in gateway mode: + * - -1: check only once, and then never again (until you pree login) + * - 0: always check + * - n: check every "n" time + * + * @param int $n an integer. + * + * @return void + */ + public static function setCacheTimesForAuthRecheck($n) + { + phpCAS::_validateClientExists(); + + try { + self::$_PHPCAS_CLIENT->setCacheTimesForAuthRecheck($n); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); + } + } + + + /** + * Set a callback function to be run when receiving CAS attributes + * + * The callback function will be passed an $success_elements + * payload of the response (\DOMElement) as its first parameter. + * + * @param string $function Callback function + * @param array $additionalArgs optional array of arguments + * + * @return void + */ + public static function setCasAttributeParserCallback($function, array $additionalArgs = array()) + { + phpCAS::_validateClientExists(); + + self::$_PHPCAS_CLIENT->setCasAttributeParserCallback($function, $additionalArgs); + } + + /** + * Set a callback function to be run when a user authenticates. + * + * The callback function will be passed a $logoutTicket as its first + * parameter, followed by any $additionalArgs you pass. The $logoutTicket + * parameter is an opaque string that can be used to map the session-id to + * logout request in order to support single-signout in applications that + * manage their own sessions (rather than letting phpCAS start the session). + * + * phpCAS::forceAuthentication() will always exit and forward client unless + * they are already authenticated. To perform an action at the moment the user + * logs in (such as registering an account, performing logging, etc), register + * a callback function here. + * + * @param callable $function Callback function + * @param array $additionalArgs optional array of arguments + * + * @return void + */ + public static function setPostAuthenticateCallback ($function, array $additionalArgs = array()) + { + phpCAS::_validateClientExists(); + + self::$_PHPCAS_CLIENT->setPostAuthenticateCallback($function, $additionalArgs); + } + + /** + * Set a callback function to be run when a single-signout request is + * received. The callback function will be passed a $logoutTicket as its + * first parameter, followed by any $additionalArgs you pass. The + * $logoutTicket parameter is an opaque string that can be used to map a + * session-id to the logout request in order to support single-signout in + * applications that manage their own sessions (rather than letting phpCAS + * start and destroy the session). + * + * @param callable $function Callback function + * @param array $additionalArgs optional array of arguments + * + * @return void + */ + public static function setSingleSignoutCallback ($function, array $additionalArgs = array()) + { + phpCAS::_validateClientExists(); + + self::$_PHPCAS_CLIENT->setSingleSignoutCallback($function, $additionalArgs); + } + + /** + * This method is called to check if the user is already authenticated + * locally or has a global cas session. A already existing cas session is + * determined by a cas gateway call.(cas login call without any interactive + * prompt) + * + * @return bool true when the user is authenticated, false when a previous + * gateway login failed or the function will not return if the user is + * redirected to the cas server for a gateway login attempt + */ + public static function checkAuthentication() + { + phpCAS :: traceBegin(); + phpCAS::_validateClientExists(); + + $auth = self::$_PHPCAS_CLIENT->checkAuthentication(); + + // store where the authentication has been checked and the result + self::$_PHPCAS_CLIENT->markAuthenticationCall($auth); + + phpCAS :: traceEnd($auth); + return $auth; + } + + /** + * This method is called to force authentication if the user was not already + * authenticated. If the user is not authenticated, halt by redirecting to + * the CAS server. + * + * @return bool Authentication + */ + public static function forceAuthentication() + { + phpCAS :: traceBegin(); + phpCAS::_validateClientExists(); + $auth = self::$_PHPCAS_CLIENT->forceAuthentication(); + + // store where the authentication has been checked and the result + self::$_PHPCAS_CLIENT->markAuthenticationCall($auth); + + /* if (!$auth) { + phpCAS :: trace('user is not authenticated, redirecting to the CAS server'); + self::$_PHPCAS_CLIENT->forceAuthentication(); + } else { + phpCAS :: trace('no need to authenticate (user `' . phpCAS :: getUser() . '\' is already authenticated)'); + }*/ + + phpCAS :: traceEnd(); + return $auth; + } + + /** + * This method is called to renew the authentication. + * + * @return void + **/ + public static function renewAuthentication() + { + phpCAS :: traceBegin(); + phpCAS::_validateClientExists(); + + $auth = self::$_PHPCAS_CLIENT->renewAuthentication(); + + // store where the authentication has been checked and the result + self::$_PHPCAS_CLIENT->markAuthenticationCall($auth); + + //self::$_PHPCAS_CLIENT->renewAuthentication(); + phpCAS :: traceEnd(); + } + + /** + * This method is called to check if the user is authenticated (previously or by + * tickets given in the URL). + * + * @return bool true when the user is authenticated. + */ + public static function isAuthenticated() + { + phpCAS :: traceBegin(); + phpCAS::_validateClientExists(); + + // call the isAuthenticated method of the $_PHPCAS_CLIENT object + $auth = self::$_PHPCAS_CLIENT->isAuthenticated(); + + // store where the authentication has been checked and the result + self::$_PHPCAS_CLIENT->markAuthenticationCall($auth); + + phpCAS :: traceEnd($auth); + return $auth; + } + + /** + * Checks whether authenticated based on $_SESSION. Useful to avoid + * server calls. + * + * @return bool true if authenticated, false otherwise. + * @since 0.4.22 by Brendan Arnold + */ + public static function isSessionAuthenticated() + { + phpCAS::_validateClientExists(); + + return (self::$_PHPCAS_CLIENT->isSessionAuthenticated()); + } + + /** + * This method returns the CAS user's login name. + * + * @return string the login name of the authenticated user + * @warning should only be called after phpCAS::forceAuthentication() + * or phpCAS::checkAuthentication(). + * */ + public static function getUser() + { + phpCAS::_validateClientExists(); + + try { + return self::$_PHPCAS_CLIENT->getUser(); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); + } + } + + /** + * Answer attributes about the authenticated user. + * + * @warning should only be called after phpCAS::forceAuthentication() + * or phpCAS::checkAuthentication(). + * + * @return array + */ + public static function getAttributes() + { + phpCAS::_validateClientExists(); + + try { + return self::$_PHPCAS_CLIENT->getAttributes(); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); + } + } + + /** + * Answer true if there are attributes for the authenticated user. + * + * @warning should only be called after phpCAS::forceAuthentication() + * or phpCAS::checkAuthentication(). + * + * @return bool + */ + public static function hasAttributes() + { + phpCAS::_validateClientExists(); + + try { + return self::$_PHPCAS_CLIENT->hasAttributes(); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); + } + } + + /** + * Answer true if an attribute exists for the authenticated user. + * + * @param string $key attribute name + * + * @return bool + * @warning should only be called after phpCAS::forceAuthentication() + * or phpCAS::checkAuthentication(). + */ + public static function hasAttribute($key) + { + phpCAS::_validateClientExists(); + + try { + return self::$_PHPCAS_CLIENT->hasAttribute($key); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); + } + } + + /** + * Answer an attribute for the authenticated user. + * + * @param string $key attribute name + * + * @return mixed string for a single value or an array if multiple values exist. + * @warning should only be called after phpCAS::forceAuthentication() + * or phpCAS::checkAuthentication(). + */ + public static function getAttribute($key) + { + phpCAS::_validateClientExists(); + + try { + return self::$_PHPCAS_CLIENT->getAttribute($key); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); + } + } + + /** + * Handle logout requests. + * + * @param bool $check_client additional safety check + * @param array $allowed_clients array of allowed clients + * + * @return void + */ + public static function handleLogoutRequests($check_client = true, $allowed_clients = array()) + { + phpCAS::_validateClientExists(); + + return (self::$_PHPCAS_CLIENT->handleLogoutRequests($check_client, $allowed_clients)); + } + + /** + * This method returns the URL to be used to login. + * + * @return string the login URL + */ + public static function getServerLoginURL() + { + phpCAS::_validateClientExists(); + + return self::$_PHPCAS_CLIENT->getServerLoginURL(); + } + + /** + * Set the login URL of the CAS server. + * + * @param string $url the login URL + * + * @return void + * @since 0.4.21 by Wyman Chan + */ + public static function setServerLoginURL($url = '') + { + phpCAS :: traceBegin(); + phpCAS::_validateClientExists(); + + try { + self::$_PHPCAS_CLIENT->setServerLoginURL($url); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); + } + + phpCAS :: traceEnd(); + } + + /** + * Set the serviceValidate URL of the CAS server. + * Used for all CAS versions of URL validations. + * Examples: + * CAS 1.0 http://www.exemple.com/validate + * CAS 2.0 http://www.exemple.com/validateURL + * CAS 3.0 http://www.exemple.com/p3/serviceValidate + * + * @param string $url the serviceValidate URL + * + * @return void + */ + public static function setServerServiceValidateURL($url = '') + { + phpCAS :: traceBegin(); + phpCAS::_validateClientExists(); + + try { + self::$_PHPCAS_CLIENT->setServerServiceValidateURL($url); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); + } + + phpCAS :: traceEnd(); + } + + /** + * Set the proxyValidate URL of the CAS server. + * Used for all CAS versions of proxy URL validations + * Examples: + * CAS 1.0 http://www.exemple.com/ + * CAS 2.0 http://www.exemple.com/proxyValidate + * CAS 3.0 http://www.exemple.com/p3/proxyValidate + * + * @param string $url the proxyValidate URL + * + * @return void + */ + public static function setServerProxyValidateURL($url = '') + { + phpCAS :: traceBegin(); + phpCAS::_validateClientExists(); + + try { + self::$_PHPCAS_CLIENT->setServerProxyValidateURL($url); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); + } + + phpCAS :: traceEnd(); + } + + /** + * Set the samlValidate URL of the CAS server. + * + * @param string $url the samlValidate URL + * + * @return void + */ + public static function setServerSamlValidateURL($url = '') + { + phpCAS :: traceBegin(); + phpCAS::_validateClientExists(); + + try { + self::$_PHPCAS_CLIENT->setServerSamlValidateURL($url); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); + } + + phpCAS :: traceEnd(); + } + + /** + * This method returns the URL to be used to logout. + * + * @return string the URL to use to log out + */ + public static function getServerLogoutURL() + { + phpCAS::_validateClientExists(); + + return self::$_PHPCAS_CLIENT->getServerLogoutURL(); + } + + /** + * Set the logout URL of the CAS server. + * + * @param string $url the logout URL + * + * @return void + * @since 0.4.21 by Wyman Chan + */ + public static function setServerLogoutURL($url = '') + { + phpCAS :: traceBegin(); + phpCAS::_validateClientExists(); + + try { + self::$_PHPCAS_CLIENT->setServerLogoutURL($url); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); + } + + phpCAS :: traceEnd(); + } + + /** + * This method is used to logout from CAS. + * + * @param string $params an array that contains the optional url and + * service parameters that will be passed to the CAS server + * + * @return void + */ + public static function logout($params = "") + { + phpCAS :: traceBegin(); + phpCAS::_validateClientExists(); + + $parsedParams = array (); + if ($params != "") { + if (is_string($params)) { + phpCAS :: error('method `phpCAS::logout($url)\' is now deprecated, use `phpCAS::logoutWithUrl($url)\' instead'); + } + if (!is_array($params)) { + phpCAS :: error('type mismatched for parameter $params (should be `array\')'); + } + foreach ($params as $key => $value) { + if ($key != "service" && $key != "url") { + phpCAS :: error('only `url\' and `service\' parameters are allowed for method `phpCAS::logout($params)\''); + } + $parsedParams[$key] = $value; + } + } + self::$_PHPCAS_CLIENT->logout($parsedParams); + // never reached + phpCAS :: traceEnd(); + } + + /** + * This method is used to logout from CAS. Halts by redirecting to the CAS + * server. + * + * @param string $service a URL that will be transmitted to the CAS server + * + * @return void + */ + public static function logoutWithRedirectService($service) + { + phpCAS :: traceBegin(); + phpCAS::_validateClientExists(); + + if (!is_string($service)) { + phpCAS :: error('type mismatched for parameter $service (should be `string\')'); + } + self::$_PHPCAS_CLIENT->logout(array ( "service" => $service )); + // never reached + phpCAS :: traceEnd(); + } + + /** + * This method is used to logout from CAS. Halts by redirecting to the CAS + * server. + * + * @param string $url a URL that will be transmitted to the CAS server + * + * @return void + * @deprecated The url parameter has been removed from the CAS server as of + * version 3.3.5.1 + */ + public static function logoutWithUrl($url) + { + trigger_error('Function deprecated for cas servers >= 3.3.5.1', E_USER_DEPRECATED); + phpCAS :: traceBegin(); + if (!is_object(self::$_PHPCAS_CLIENT)) { + phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()'); + } + if (!is_string($url)) { + phpCAS :: error('type mismatched for parameter $url (should be `string\')'); + } + self::$_PHPCAS_CLIENT->logout(array ( "url" => $url )); + // never reached + phpCAS :: traceEnd(); + } + + /** + * This method is used to logout from CAS. Halts by redirecting to the CAS + * server. + * + * @param string $service a URL that will be transmitted to the CAS server + * @param string $url a URL that will be transmitted to the CAS server + * + * @return void + * + * @deprecated The url parameter has been removed from the CAS server as of + * version 3.3.5.1 + */ + public static function logoutWithRedirectServiceAndUrl($service, $url) + { + trigger_error('Function deprecated for cas servers >= 3.3.5.1', E_USER_DEPRECATED); + phpCAS :: traceBegin(); + phpCAS::_validateClientExists(); + + if (!is_string($service)) { + phpCAS :: error('type mismatched for parameter $service (should be `string\')'); + } + if (!is_string($url)) { + phpCAS :: error('type mismatched for parameter $url (should be `string\')'); + } + self::$_PHPCAS_CLIENT->logout( + array ( + "service" => $service, + "url" => $url + ) + ); + // never reached + phpCAS :: traceEnd(); + } + + /** + * Set the fixed URL that will be used by the CAS server to transmit the + * PGT. When this method is not called, a phpCAS script uses its own URL + * for the callback. + * + * @param string $url the URL + * + * @return void + */ + public static function setFixedCallbackURL($url = '') + { + phpCAS :: traceBegin(); + phpCAS::_validateProxyExists(); + + try { + self::$_PHPCAS_CLIENT->setCallbackURL($url); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); + } + + phpCAS :: traceEnd(); + } + + /** + * Set the fixed URL that will be set as the CAS service parameter. When this + * method is not called, a phpCAS script uses its own URL. + * + * @param string $url the URL + * + * @return void + */ + public static function setFixedServiceURL($url) + { + phpCAS :: traceBegin(); + phpCAS::_validateProxyExists(); + + try { + self::$_PHPCAS_CLIENT->setURL($url); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); + } + + phpCAS :: traceEnd(); + } + + /** + * Get the URL that is set as the CAS service parameter. + * + * @return string Service Url + */ + public static function getServiceURL() + { + phpCAS::_validateProxyExists(); + return (self::$_PHPCAS_CLIENT->getURL()); + } + + /** + * Retrieve a Proxy Ticket from the CAS server. + * + * @param string $target_service Url string of service to proxy + * @param int &$err_code error code + * @param string &$err_msg error message + * + * @return string Proxy Ticket + */ + public static function retrievePT($target_service, & $err_code, & $err_msg) + { + phpCAS::_validateProxyExists(); + + try { + return (self::$_PHPCAS_CLIENT->retrievePT($target_service, $err_code, $err_msg)); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); + } + } + + /** + * Set the certificate of the CAS server CA and if the CN should be properly + * verified. + * + * @param string $cert CA certificate file name + * @param bool $validate_cn Validate CN in certificate (default true) + * + * @return void + */ + public static function setCasServerCACert($cert, $validate_cn = true) + { + phpCAS :: traceBegin(); + phpCAS::_validateClientExists(); + + try { + self::$_PHPCAS_CLIENT->setCasServerCACert($cert, $validate_cn); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); + } + + phpCAS :: traceEnd(); + } + + /** + * Set no SSL validation for the CAS server. + * + * @return void + */ + public static function setNoCasServerValidation() + { + phpCAS :: traceBegin(); + phpCAS::_validateClientExists(); + + phpCAS :: trace('You have configured no validation of the legitimacy of the cas server. This is not recommended for production use.'); + self::$_PHPCAS_CLIENT->setNoCasServerValidation(); + phpCAS :: traceEnd(); + } + + + /** + * Disable the removal of a CAS-Ticket from the URL when authenticating + * DISABLING POSES A SECURITY RISK: + * We normally remove the ticket by an additional redirect as a security + * precaution to prevent a ticket in the HTTP_REFERRER or be carried over in + * the URL parameter + * + * @return void + */ + public static function setNoClearTicketsFromUrl() + { + phpCAS :: traceBegin(); + phpCAS::_validateClientExists(); + + self::$_PHPCAS_CLIENT->setNoClearTicketsFromUrl(); + phpCAS :: traceEnd(); + } + + /** @} */ + + /** + * Change CURL options. + * CURL is used to connect through HTTPS to CAS server + * + * @param string $key the option key + * @param string $value the value to set + * + * @return void + */ + public static function setExtraCurlOption($key, $value) + { + phpCAS :: traceBegin(); + phpCAS::_validateClientExists(); + + self::$_PHPCAS_CLIENT->setExtraCurlOption($key, $value); + phpCAS :: traceEnd(); + } + + /** + * Set a salt/seed for the session-id hash to make it harder to guess. + * + * When $changeSessionID = true phpCAS will create a session-id that is derived + * from the service ticket. Doing so allows phpCAS to look-up and destroy the + * proper session on single-log-out requests. While the service tickets + * provided by the CAS server may include enough data to generate a strong + * hash, clients may provide an additional salt to ensure that session ids + * are not guessable if the session tickets do not have enough entropy. + * + * @param string $salt The salt to combine with the session ticket. + * + * @return void + */ + public static function setSessionIdSalt($salt) { + phpCAS :: traceBegin(); + phpCAS::_validateClientExists(); + self::$_PHPCAS_CLIENT->setSessionIdSalt($salt); + phpCAS :: traceEnd(); + } + + /** + * If you want your service to be proxied you have to enable it (default + * disabled) and define an accepable list of proxies that are allowed to + * proxy your service. + * + * Add each allowed proxy definition object. For the normal CAS_ProxyChain + * class, the constructor takes an array of proxies to match. The list is in + * reverse just as seen from the service. Proxies have to be defined in reverse + * from the service to the user. If a user hits service A and gets proxied via + * B to service C the list of acceptable on C would be array(B,A). The definition + * of an individual proxy can be either a string or a regexp (preg_match is used) + * that will be matched against the proxy list supplied by the cas server + * when validating the proxy tickets. The strings are compared starting from + * the beginning and must fully match with the proxies in the list. + * Example: + * phpCAS::allowProxyChain(new CAS_ProxyChain(array( + * 'https://app.example.com/' + * ))); + * phpCAS::allowProxyChain(new CAS_ProxyChain(array( + * '/^https:\/\/app[0-9]\.example\.com\/rest\//', + * 'http://client.example.com/' + * ))); + * + * For quick testing or in certain production screnarios you might want to + * allow allow any other valid service to proxy your service. To do so, add + * the "Any" chain: + * phpCAS::allowProxyChain(new CAS_ProxyChain_Any); + * THIS SETTING IS HOWEVER NOT RECOMMENDED FOR PRODUCTION AND HAS SECURITY + * IMPLICATIONS: YOU ARE ALLOWING ANY SERVICE TO ACT ON BEHALF OF A USER + * ON THIS SERVICE. + * + * @param CAS_ProxyChain_Interface $proxy_chain A proxy-chain that will be + * matched against the proxies requesting access + * + * @return void + */ + public static function allowProxyChain(CAS_ProxyChain_Interface $proxy_chain) + { + phpCAS :: traceBegin(); + phpCAS::_validateClientExists(); + + if (self::$_PHPCAS_CLIENT->getServerVersion() !== CAS_VERSION_2_0 + && self::$_PHPCAS_CLIENT->getServerVersion() !== CAS_VERSION_3_0 + ) { + phpCAS :: error('this method can only be used with the cas 2.0/3.0 protocols'); + } + self::$_PHPCAS_CLIENT->getAllowedProxyChains()->allowProxyChain($proxy_chain); + phpCAS :: traceEnd(); + } + + /** + * Answer an array of proxies that are sitting in front of this application. + * This method will only return a non-empty array if we have received and + * validated a Proxy Ticket. + * + * @return array + * @access public + * @since 6/25/09 + */ + public static function getProxies () + { + phpCAS::_validateProxyExists(); + + return(self::$_PHPCAS_CLIENT->getProxies()); + } + + // ######################################################################## + // PGTIOU/PGTID and logoutRequest rebroadcasting + // ######################################################################## + + /** + * Add a pgtIou/pgtId and logoutRequest rebroadcast node. + * + * @param string $rebroadcastNodeUrl The rebroadcast node URL. Can be + * hostname or IP. + * + * @return void + */ + public static function addRebroadcastNode($rebroadcastNodeUrl) + { + phpCAS::traceBegin(); + phpCAS::log('rebroadcastNodeUrl:'.$rebroadcastNodeUrl); + phpCAS::_validateClientExists(); + + try { + self::$_PHPCAS_CLIENT->addRebroadcastNode($rebroadcastNodeUrl); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); + } + + phpCAS::traceEnd(); + } + + /** + * This method is used to add header parameters when rebroadcasting + * pgtIou/pgtId or logoutRequest. + * + * @param String $header Header to send when rebroadcasting. + * + * @return void + */ + public static function addRebroadcastHeader($header) + { + phpCAS :: traceBegin(); + phpCAS::_validateClientExists(); + + try { + self::$_PHPCAS_CLIENT->addRebroadcastHeader($header); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); + } + + phpCAS :: traceEnd(); + } + + /** + * Checks if a client already exists + * + * @throws CAS_OutOfSequenceBeforeClientException + * + * @return void + */ + private static function _validateClientExists() + { + if (!is_object(self::$_PHPCAS_CLIENT)) { + throw new CAS_OutOfSequenceBeforeClientException(); + } + } + + /** + * Checks of a proxy client aready exists + * + * @throws CAS_OutOfSequenceBeforeProxyException + * + * @return void + */ + private static function _validateProxyExists() + { + if (!is_object(self::$_PHPCAS_CLIENT)) { + throw new CAS_OutOfSequenceBeforeProxyException(); + } + } + + /** + * For testing purposes, use this method to set the client to a test double + * + * @return void + */ + public static function setCasClient(\CAS_Client $client) + { + self::$_PHPCAS_CLIENT = $client; + } +} +// ######################################################################## +// DOCUMENTATION +// ######################################################################## + +// ######################################################################## +// MAIN PAGE + +/** + * @mainpage + * + * The following pages only show the source documentation. + * + */ + +// ######################################################################## +// MODULES DEFINITION + +/** @defgroup public User interface */ + +/** @defgroup publicInit Initialization + * @ingroup public */ + +/** @defgroup publicAuth Authentication + * @ingroup public */ + +/** @defgroup publicServices Access to external services + * @ingroup public */ + +/** @defgroup publicConfig Configuration + * @ingroup public */ + +/** @defgroup publicLang Internationalization + * @ingroup publicConfig */ + +/** @defgroup publicOutput HTML output + * @ingroup publicConfig */ + +/** @defgroup publicPGTStorage PGT storage + * @ingroup publicConfig */ + +/** @defgroup publicDebug Debugging + * @ingroup public */ + +/** @defgroup internal Implementation */ + +/** @defgroup internalAuthentication Authentication + * @ingroup internal */ + +/** @defgroup internalBasic CAS Basic client features (CAS 1.0, Service Tickets) + * @ingroup internal */ + +/** @defgroup internalProxy CAS Proxy features (CAS 2.0, Proxy Granting Tickets) + * @ingroup internal */ + +/** @defgroup internalSAML CAS SAML features (SAML 1.1) + * @ingroup internal */ + +/** @defgroup internalPGTStorage PGT storage + * @ingroup internalProxy */ + +/** @defgroup internalPGTStorageDb PGT storage in a database + * @ingroup internalPGTStorage */ + +/** @defgroup internalPGTStorageFile PGT storage on the filesystem + * @ingroup internalPGTStorage */ + +/** @defgroup internalCallback Callback from the CAS server + * @ingroup internalProxy */ + +/** @defgroup internalProxyServices Proxy other services + * @ingroup internalProxy */ + +/** @defgroup internalService CAS client features (CAS 2.0, Proxied service) + * @ingroup internal */ + +/** @defgroup internalConfig Configuration + * @ingroup internal */ + +/** @defgroup internalBehave Internal behaviour of phpCAS + * @ingroup internalConfig */ + +/** @defgroup internalOutput HTML output + * @ingroup internalConfig */ + +/** @defgroup internalLang Internationalization + * @ingroup internalConfig + * + * To add a new language: + * - 1. define a new constant PHPCAS_LANG_XXXXXX in CAS/CAS.php + * - 2. copy any file from CAS/languages to CAS/languages/XXXXXX.php + * - 3. Make the translations + */ + +/** @defgroup internalDebug Debugging + * @ingroup internal */ + +/** @defgroup internalMisc Miscellaneous + * @ingroup internal */ + +// ######################################################################## +// EXAMPLES + +/** + * @example example_simple.php + */ +/** + * @example example_service.php + */ +/** + * @example example_service_that_proxies.php + */ +/** + * @example example_service_POST.php + */ +/** + * @example example_proxy_serviceWeb.php + */ +/** + * @example example_proxy_serviceWeb_chaining.php + */ +/** + * @example example_proxy_POST.php + */ +/** + * @example example_proxy_GET.php + */ +/** + * @example example_lang.php + */ +/** + * @example example_html.php + */ +/** + * @example example_pgt_storage_file.php + */ +/** + * @example example_pgt_storage_db.php + */ +/** + * @example example_gateway.php + */ +/** + * @example example_logout.php + */ +/** + * @example example_rebroadcast.php + */ +/** + * @example example_custom_urls.php + */ +/** + * @example example_advanced_saml11.php + */ diff --git a/vendor/apereo/phpcas/source/CAS/AuthenticationException.php b/vendor/apereo/phpcas/source/CAS/AuthenticationException.php new file mode 100644 index 0000000000..3b73685ff9 --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/AuthenticationException.php @@ -0,0 +1,111 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +/** + * This interface defines methods that allow proxy-authenticated service handlers + * to interact with phpCAS. + * + * Proxy service handlers must implement this interface as well as call + * phpCAS::initializeProxiedService($this) at some point in their implementation. + * + * While not required, proxy-authenticated service handlers are encouraged to + * implement the CAS_ProxiedService_Testable interface to facilitate unit testing. + * + * @class CAS_AuthenticationException + * @category Authentication + * @package PhpCAS + * @author Joachim Fritschi + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +class CAS_AuthenticationException +extends RuntimeException +implements CAS_Exception +{ + + /** + * This method is used to print the HTML output when the user was not + * authenticated. + * + * @param CAS_Client $client phpcas client + * @param string $failure the failure that occured + * @param string $cas_url the URL the CAS server was asked for + * @param bool $no_response the response from the CAS server (other + * parameters are ignored if TRUE) + * @param bool $bad_response bad response from the CAS server ($err_code + * and $err_msg ignored if TRUE) + * @param string $cas_response the response of the CAS server + * @param int $err_code the error code given by the CAS server + * @param string $err_msg the error message given by the CAS server + */ + public function __construct($client,$failure,$cas_url,$no_response, + $bad_response=false,$cas_response='',$err_code=-1,$err_msg='' + ) { + $messages = array(); + phpCAS::traceBegin(); + $lang = $client->getLangObj(); + $client->printHTMLHeader($lang->getAuthenticationFailed()); + printf( + $lang->getYouWereNotAuthenticated(), + htmlentities($client->getURL()), + isset($_SERVER['SERVER_ADMIN']) ? $_SERVER['SERVER_ADMIN']:'' + ); + phpCAS::trace($messages[] = 'CAS URL: '.$cas_url); + phpCAS::trace($messages[] = 'Authentication failure: '.$failure); + if ( $no_response ) { + phpCAS::trace($messages[] = 'Reason: no response from the CAS server'); + } else { + if ( $bad_response ) { + phpCAS::trace($messages[] = 'Reason: bad response from the CAS server'); + } else { + switch ($client->getServerVersion()) { + case CAS_VERSION_1_0: + phpCAS::trace($messages[] = 'Reason: CAS error'); + break; + case CAS_VERSION_2_0: + case CAS_VERSION_3_0: + if ( $err_code === -1 ) { + phpCAS::trace($messages[] = 'Reason: no CAS error'); + } else { + phpCAS::trace($messages[] = 'Reason: ['.$err_code.'] CAS error: '.$err_msg); + } + break; + } + } + phpCAS::trace($messages[] = 'CAS response: '.$cas_response); + } + $client->printHTMLFooter(); + phpCAS::traceExit(); + + parent::__construct(implode("\n", $messages)); + } + +} +?> diff --git a/vendor/apereo/phpcas/source/CAS/Autoload.php b/vendor/apereo/phpcas/source/CAS/Autoload.php new file mode 100644 index 0000000000..5e9b140c78 --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/Autoload.php @@ -0,0 +1,90 @@ + + * @copyright 2008 Regents of the University of Nebraska + * @license http://www1.unl.edu/wdn/wiki/Software_License BSD License + * @link http://code.google.com/p/simplecas/ + **/ + +/** + * Autoload a class + * + * @param string $class Classname to load + * + * @return bool + */ +function CAS_autoload($class) +{ + // Static to hold the Include Path to CAS + static $include_path; + // Check only for CAS classes + if (substr($class, 0, 4) !== 'CAS_') { + return false; + } + // Setup the include path if it's not already set from a previous call + if (empty($include_path)) { + $include_path = array(dirname(dirname(__FILE__)), dirname(dirname(__FILE__)) . '/../test/' ); + } + + // Declare local variable to store the expected full path to the file + + foreach ($include_path as $path) { + $file_path = $path . '/' . str_replace('_', '/', $class) . '.php'; + $fp = @fopen($file_path, 'r', true); + if ($fp) { + fclose($fp); + include $file_path; + if (!class_exists($class, false) && !interface_exists($class, false)) { + die( + new Exception( + 'Class ' . $class . ' was not present in ' . + $file_path . + ' [CAS_autoload]' + ) + ); + } + return true; + } + } + $e = new Exception( + 'Class ' . $class . ' could not be loaded from ' . + $file_path . ', file does not exist (Path="' + . implode(':', $include_path) .'") [CAS_autoload]' + ); + $trace = $e->getTrace(); + if (isset($trace[2]) && isset($trace[2]['function']) + && in_array($trace[2]['function'], array('class_exists', 'interface_exists')) + ) { + return false; + } + if (isset($trace[1]) && isset($trace[1]['function']) + && in_array($trace[1]['function'], array('class_exists', 'interface_exists')) + ) { + return false; + } + die ((string) $e); +} + +// set up __autoload +if (!(spl_autoload_functions()) + || !in_array('CAS_autoload', spl_autoload_functions()) +) { + spl_autoload_register('CAS_autoload'); + if (function_exists('__autoload') + && !in_array('__autoload', spl_autoload_functions()) + ) { + // __autoload() was being used, but now would be ignored, add + // it to the autoload stack + spl_autoload_register('__autoload'); + } +} + +?> diff --git a/vendor/apereo/phpcas/source/CAS/Client.php b/vendor/apereo/phpcas/source/CAS/Client.php new file mode 100644 index 0000000000..338bd50c4e --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/Client.php @@ -0,0 +1,3947 @@ + + * @author Olivier Berger + * @author Brett Bieber + * @author Joachim Fritschi + * @author Adam Franco + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +/** + * The CAS_Client class is a client interface that provides CAS authentication + * to PHP applications. + * + * @class CAS_Client + * @category Authentication + * @package PhpCAS + * @author Pascal Aubry + * @author Olivier Berger + * @author Brett Bieber + * @author Joachim Fritschi + * @author Adam Franco + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + * + */ + +class CAS_Client +{ + + // ######################################################################## + // HTML OUTPUT + // ######################################################################## + /** + * @addtogroup internalOutput + * @{ + */ + + /** + * This method filters a string by replacing special tokens by appropriate values + * and prints it. The corresponding tokens are taken into account: + * - __CAS_VERSION__ + * - __PHPCAS_VERSION__ + * - __SERVER_BASE_URL__ + * + * Used by CAS_Client::PrintHTMLHeader() and CAS_Client::printHTMLFooter(). + * + * @param string $str the string to filter and output + * + * @return void + */ + private function _htmlFilterOutput($str) + { + $str = str_replace('__CAS_VERSION__', $this->getServerVersion(), $str); + $str = str_replace('__PHPCAS_VERSION__', phpCAS::getVersion(), $str); + $str = str_replace('__SERVER_BASE_URL__', $this->_getServerBaseURL(), $str); + echo $str; + } + + /** + * A string used to print the header of HTML pages. Written by + * CAS_Client::setHTMLHeader(), read by CAS_Client::printHTMLHeader(). + * + * @hideinitializer + * @see CAS_Client::setHTMLHeader, CAS_Client::printHTMLHeader() + */ + private $_output_header = ''; + + /** + * This method prints the header of the HTML output (after filtering). If + * CAS_Client::setHTMLHeader() was not used, a default header is output. + * + * @param string $title the title of the page + * + * @return void + * @see _htmlFilterOutput() + */ + public function printHTMLHeader($title) + { + $this->_htmlFilterOutput( + str_replace( + '__TITLE__', $title, + (empty($this->_output_header) + ? '__TITLE__

__TITLE__

' + : $this->_output_header) + ) + ); + } + + /** + * A string used to print the footer of HTML pages. Written by + * CAS_Client::setHTMLFooter(), read by printHTMLFooter(). + * + * @hideinitializer + * @see CAS_Client::setHTMLFooter, CAS_Client::printHTMLFooter() + */ + private $_output_footer = ''; + + /** + * This method prints the footer of the HTML output (after filtering). If + * CAS_Client::setHTMLFooter() was not used, a default footer is output. + * + * @return void + * @see _htmlFilterOutput() + */ + public function printHTMLFooter() + { + $lang = $this->getLangObj(); + $this->_htmlFilterOutput( + empty($this->_output_footer)? + (phpCAS::getVerbose())? + '
phpCAS __PHPCAS_VERSION__ ' + .$lang->getUsingServer() + .' __SERVER_BASE_URL__ (CAS __CAS_VERSION__)
' + :'' + :$this->_output_footer + ); + } + + /** + * This method set the HTML header used for all outputs. + * + * @param string $header the HTML header. + * + * @return void + */ + public function setHTMLHeader($header) + { + // Argument Validation + if (gettype($header) != 'string') + throw new CAS_TypeMismatchException($header, '$header', 'string'); + + $this->_output_header = $header; + } + + /** + * This method set the HTML footer used for all outputs. + * + * @param string $footer the HTML footer. + * + * @return void + */ + public function setHTMLFooter($footer) + { + // Argument Validation + if (gettype($footer) != 'string') + throw new CAS_TypeMismatchException($footer, '$footer', 'string'); + + $this->_output_footer = $footer; + } + + + /** @} */ + + + // ######################################################################## + // INTERNATIONALIZATION + // ######################################################################## + /** + * @addtogroup internalLang + * @{ + */ + /** + * A string corresponding to the language used by phpCAS. Written by + * CAS_Client::setLang(), read by CAS_Client::getLang(). + + * @note debugging information is always in english (debug purposes only). + */ + private $_lang = PHPCAS_LANG_DEFAULT; + + /** + * This method is used to set the language used by phpCAS. + * + * @param string $lang representing the language. + * + * @return void + */ + public function setLang($lang) + { + // Argument Validation + if (gettype($lang) != 'string') + throw new CAS_TypeMismatchException($lang, '$lang', 'string'); + + phpCAS::traceBegin(); + $obj = new $lang(); + if (!($obj instanceof CAS_Languages_LanguageInterface)) { + throw new CAS_InvalidArgumentException( + '$className must implement the CAS_Languages_LanguageInterface' + ); + } + $this->_lang = $lang; + phpCAS::traceEnd(); + } + /** + * Create the language + * + * @return CAS_Languages_LanguageInterface object implementing the class + */ + public function getLangObj() + { + $classname = $this->_lang; + return new $classname(); + } + + /** @} */ + // ######################################################################## + // CAS SERVER CONFIG + // ######################################################################## + /** + * @addtogroup internalConfig + * @{ + */ + + /** + * a record to store information about the CAS server. + * - $_server['version']: the version of the CAS server + * - $_server['hostname']: the hostname of the CAS server + * - $_server['port']: the port the CAS server is running on + * - $_server['uri']: the base URI the CAS server is responding on + * - $_server['base_url']: the base URL of the CAS server + * - $_server['login_url']: the login URL of the CAS server + * - $_server['service_validate_url']: the service validating URL of the + * CAS server + * - $_server['proxy_url']: the proxy URL of the CAS server + * - $_server['proxy_validate_url']: the proxy validating URL of the CAS server + * - $_server['logout_url']: the logout URL of the CAS server + * + * $_server['version'], $_server['hostname'], $_server['port'] and + * $_server['uri'] are written by CAS_Client::CAS_Client(), read by + * CAS_Client::getServerVersion(), CAS_Client::_getServerHostname(), + * CAS_Client::_getServerPort() and CAS_Client::_getServerURI(). + * + * The other fields are written and read by CAS_Client::_getServerBaseURL(), + * CAS_Client::getServerLoginURL(), CAS_Client::getServerServiceValidateURL(), + * CAS_Client::getServerProxyValidateURL() and CAS_Client::getServerLogoutURL(). + * + * @hideinitializer + */ + private $_server = array( + 'version' => '', + 'hostname' => 'none', + 'port' => -1, + 'uri' => 'none'); + + /** + * This method is used to retrieve the version of the CAS server. + * + * @return string the version of the CAS server. + */ + public function getServerVersion() + { + return $this->_server['version']; + } + + /** + * This method is used to retrieve the hostname of the CAS server. + * + * @return string the hostname of the CAS server. + */ + private function _getServerHostname() + { + return $this->_server['hostname']; + } + + /** + * This method is used to retrieve the port of the CAS server. + * + * @return int the port of the CAS server. + */ + private function _getServerPort() + { + return $this->_server['port']; + } + + /** + * This method is used to retrieve the URI of the CAS server. + * + * @return string a URI. + */ + private function _getServerURI() + { + return $this->_server['uri']; + } + + /** + * This method is used to retrieve the base URL of the CAS server. + * + * @return string a URL. + */ + private function _getServerBaseURL() + { + // the URL is build only when needed + if ( empty($this->_server['base_url']) ) { + $this->_server['base_url'] = 'https://' . $this->_getServerHostname(); + if ($this->_getServerPort()!=443) { + $this->_server['base_url'] .= ':' + .$this->_getServerPort(); + } + $this->_server['base_url'] .= $this->_getServerURI(); + } + return $this->_server['base_url']; + } + + /** + * This method is used to retrieve the login URL of the CAS server. + * + * @param bool $gateway true to check authentication, false to force it + * @param bool $renew true to force the authentication with the CAS server + * + * @return string a URL. + * @note It is recommended that CAS implementations ignore the "gateway" + * parameter if "renew" is set + */ + public function getServerLoginURL($gateway=false,$renew=false) + { + phpCAS::traceBegin(); + // the URL is build only when needed + if ( empty($this->_server['login_url']) ) { + $this->_server['login_url'] = $this->_buildQueryUrl($this->_getServerBaseURL().'login','service='.urlencode($this->getURL())); + } + $url = $this->_server['login_url']; + if ($renew) { + // It is recommended that when the "renew" parameter is set, its + // value be "true" + $url = $this->_buildQueryUrl($url, 'renew=true'); + } elseif ($gateway) { + // It is recommended that when the "gateway" parameter is set, its + // value be "true" + $url = $this->_buildQueryUrl($url, 'gateway=true'); + } + phpCAS::traceEnd($url); + return $url; + } + + /** + * This method sets the login URL of the CAS server. + * + * @param string $url the login URL + * + * @return string login url + */ + public function setServerLoginURL($url) + { + // Argument Validation + if (gettype($url) != 'string') + throw new CAS_TypeMismatchException($url, '$url', 'string'); + + return $this->_server['login_url'] = $url; + } + + + /** + * This method sets the serviceValidate URL of the CAS server. + * + * @param string $url the serviceValidate URL + * + * @return string serviceValidate URL + */ + public function setServerServiceValidateURL($url) + { + // Argument Validation + if (gettype($url) != 'string') + throw new CAS_TypeMismatchException($url, '$url', 'string'); + + return $this->_server['service_validate_url'] = $url; + } + + + /** + * This method sets the proxyValidate URL of the CAS server. + * + * @param string $url the proxyValidate URL + * + * @return string proxyValidate URL + */ + public function setServerProxyValidateURL($url) + { + // Argument Validation + if (gettype($url) != 'string') + throw new CAS_TypeMismatchException($url, '$url', 'string'); + + return $this->_server['proxy_validate_url'] = $url; + } + + + /** + * This method sets the samlValidate URL of the CAS server. + * + * @param string $url the samlValidate URL + * + * @return string samlValidate URL + */ + public function setServerSamlValidateURL($url) + { + // Argument Validation + if (gettype($url) != 'string') + throw new CAS_TypeMismatchException($url, '$url', 'string'); + + return $this->_server['saml_validate_url'] = $url; + } + + + /** + * This method is used to retrieve the service validating URL of the CAS server. + * + * @return string serviceValidate URL. + */ + public function getServerServiceValidateURL() + { + phpCAS::traceBegin(); + // the URL is build only when needed + if ( empty($this->_server['service_validate_url']) ) { + switch ($this->getServerVersion()) { + case CAS_VERSION_1_0: + $this->_server['service_validate_url'] = $this->_getServerBaseURL() + .'validate'; + break; + case CAS_VERSION_2_0: + $this->_server['service_validate_url'] = $this->_getServerBaseURL() + .'serviceValidate'; + break; + case CAS_VERSION_3_0: + $this->_server['service_validate_url'] = $this->_getServerBaseURL() + .'p3/serviceValidate'; + break; + } + } + $url = $this->_buildQueryUrl( + $this->_server['service_validate_url'], + 'service='.urlencode($this->getURL()) + ); + phpCAS::traceEnd($url); + return $url; + } + /** + * This method is used to retrieve the SAML validating URL of the CAS server. + * + * @return string samlValidate URL. + */ + public function getServerSamlValidateURL() + { + phpCAS::traceBegin(); + // the URL is build only when needed + if ( empty($this->_server['saml_validate_url']) ) { + switch ($this->getServerVersion()) { + case SAML_VERSION_1_1: + $this->_server['saml_validate_url'] = $this->_getServerBaseURL().'samlValidate'; + break; + } + } + + $url = $this->_buildQueryUrl( + $this->_server['saml_validate_url'], + 'TARGET='.urlencode($this->getURL()) + ); + phpCAS::traceEnd($url); + return $url; + } + + /** + * This method is used to retrieve the proxy validating URL of the CAS server. + * + * @return string proxyValidate URL. + */ + public function getServerProxyValidateURL() + { + phpCAS::traceBegin(); + // the URL is build only when needed + if ( empty($this->_server['proxy_validate_url']) ) { + switch ($this->getServerVersion()) { + case CAS_VERSION_1_0: + $this->_server['proxy_validate_url'] = ''; + break; + case CAS_VERSION_2_0: + $this->_server['proxy_validate_url'] = $this->_getServerBaseURL().'proxyValidate'; + break; + case CAS_VERSION_3_0: + $this->_server['proxy_validate_url'] = $this->_getServerBaseURL().'p3/proxyValidate'; + break; + } + } + $url = $this->_buildQueryUrl( + $this->_server['proxy_validate_url'], + 'service='.urlencode($this->getURL()) + ); + phpCAS::traceEnd($url); + return $url; + } + + + /** + * This method is used to retrieve the proxy URL of the CAS server. + * + * @return string proxy URL. + */ + public function getServerProxyURL() + { + // the URL is build only when needed + if ( empty($this->_server['proxy_url']) ) { + switch ($this->getServerVersion()) { + case CAS_VERSION_1_0: + $this->_server['proxy_url'] = ''; + break; + case CAS_VERSION_2_0: + case CAS_VERSION_3_0: + $this->_server['proxy_url'] = $this->_getServerBaseURL().'proxy'; + break; + } + } + return $this->_server['proxy_url']; + } + + /** + * This method is used to retrieve the logout URL of the CAS server. + * + * @return string logout URL. + */ + public function getServerLogoutURL() + { + // the URL is build only when needed + if ( empty($this->_server['logout_url']) ) { + $this->_server['logout_url'] = $this->_getServerBaseURL().'logout'; + } + return $this->_server['logout_url']; + } + + /** + * This method sets the logout URL of the CAS server. + * + * @param string $url the logout URL + * + * @return string logout url + */ + public function setServerLogoutURL($url) + { + // Argument Validation + if (gettype($url) != 'string') + throw new CAS_TypeMismatchException($url, '$url', 'string'); + + return $this->_server['logout_url'] = $url; + } + + /** + * An array to store extra curl options. + */ + private $_curl_options = array(); + + /** + * This method is used to set additional user curl options. + * + * @param string $key name of the curl option + * @param string $value value of the curl option + * + * @return void + */ + public function setExtraCurlOption($key, $value) + { + $this->_curl_options[$key] = $value; + } + + /** @} */ + + // ######################################################################## + // Change the internal behaviour of phpcas + // ######################################################################## + + /** + * @addtogroup internalBehave + * @{ + */ + + /** + * The class to instantiate for making web requests in readUrl(). + * The class specified must implement the CAS_Request_RequestInterface. + * By default CAS_Request_CurlRequest is used, but this may be overridden to + * supply alternate request mechanisms for testing. + */ + private $_requestImplementation = 'CAS_Request_CurlRequest'; + + /** + * Override the default implementation used to make web requests in readUrl(). + * This class must implement the CAS_Request_RequestInterface. + * + * @param string $className name of the RequestImplementation class + * + * @return void + */ + public function setRequestImplementation ($className) + { + $obj = new $className; + if (!($obj instanceof CAS_Request_RequestInterface)) { + throw new CAS_InvalidArgumentException( + '$className must implement the CAS_Request_RequestInterface' + ); + } + $this->_requestImplementation = $className; + } + + /** + * @var boolean $_clearTicketsFromUrl; If true, phpCAS will clear session + * tickets from the URL after a successful authentication. + */ + private $_clearTicketsFromUrl = true; + + /** + * Configure the client to not send redirect headers and call exit() on + * authentication success. The normal redirect is used to remove the service + * ticket from the client's URL, but for running unit tests we need to + * continue without exiting. + * + * Needed for testing authentication + * + * @return void + */ + public function setNoClearTicketsFromUrl () + { + $this->_clearTicketsFromUrl = false; + } + + /** + * @var callback $_attributeParserCallbackFunction; + */ + private $_casAttributeParserCallbackFunction = null; + + /** + * @var array $_attributeParserCallbackArgs; + */ + private $_casAttributeParserCallbackArgs = array(); + + /** + * Set a callback function to be run when parsing CAS attributes + * + * The callback function will be passed a XMLNode as its first parameter, + * followed by any $additionalArgs you pass. + * + * @param string $function callback function to call + * @param array $additionalArgs optional array of arguments + * + * @return void + */ + public function setCasAttributeParserCallback($function, array $additionalArgs = array()) + { + $this->_casAttributeParserCallbackFunction = $function; + $this->_casAttributeParserCallbackArgs = $additionalArgs; + } + + /** @var callable $_postAuthenticateCallbackFunction; + */ + private $_postAuthenticateCallbackFunction = null; + + /** + * @var array $_postAuthenticateCallbackArgs; + */ + private $_postAuthenticateCallbackArgs = array(); + + /** + * Set a callback function to be run when a user authenticates. + * + * The callback function will be passed a $logoutTicket as its first parameter, + * followed by any $additionalArgs you pass. The $logoutTicket parameter is an + * opaque string that can be used to map a session-id to the logout request + * in order to support single-signout in applications that manage their own + * sessions (rather than letting phpCAS start the session). + * + * phpCAS::forceAuthentication() will always exit and forward client unless + * they are already authenticated. To perform an action at the moment the user + * logs in (such as registering an account, performing logging, etc), register + * a callback function here. + * + * @param callable $function callback function to call + * @param array $additionalArgs optional array of arguments + * + * @return void + */ + public function setPostAuthenticateCallback ($function, array $additionalArgs = array()) + { + $this->_postAuthenticateCallbackFunction = $function; + $this->_postAuthenticateCallbackArgs = $additionalArgs; + } + + /** + * @var callable $_signoutCallbackFunction; + */ + private $_signoutCallbackFunction = null; + + /** + * @var array $_signoutCallbackArgs; + */ + private $_signoutCallbackArgs = array(); + + /** + * Set a callback function to be run when a single-signout request is received. + * + * The callback function will be passed a $logoutTicket as its first parameter, + * followed by any $additionalArgs you pass. The $logoutTicket parameter is an + * opaque string that can be used to map a session-id to the logout request in + * order to support single-signout in applications that manage their own sessions + * (rather than letting phpCAS start and destroy the session). + * + * @param callable $function callback function to call + * @param array $additionalArgs optional array of arguments + * + * @return void + */ + public function setSingleSignoutCallback ($function, array $additionalArgs = array()) + { + $this->_signoutCallbackFunction = $function; + $this->_signoutCallbackArgs = $additionalArgs; + } + + // ######################################################################## + // Methods for supplying code-flow feedback to integrators. + // ######################################################################## + + /** + * Ensure that this is actually a proxy object or fail with an exception + * + * @throws CAS_OutOfSequenceBeforeProxyException + * + * @return void + */ + public function ensureIsProxy() + { + if (!$this->isProxy()) { + throw new CAS_OutOfSequenceBeforeProxyException(); + } + } + + /** + * Mark the caller of authentication. This will help client integraters determine + * problems with their code flow if they call a function such as getUser() before + * authentication has occurred. + * + * @param bool $auth True if authentication was successful, false otherwise. + * + * @return null + */ + public function markAuthenticationCall ($auth) + { + // store where the authentication has been checked and the result + $dbg = debug_backtrace(); + $this->_authentication_caller = array ( + 'file' => $dbg[1]['file'], + 'line' => $dbg[1]['line'], + 'method' => $dbg[1]['class'] . '::' . $dbg[1]['function'], + 'result' => (boolean)$auth + ); + } + private $_authentication_caller; + + /** + * Answer true if authentication has been checked. + * + * @return bool + */ + public function wasAuthenticationCalled () + { + return !empty($this->_authentication_caller); + } + + /** + * Ensure that authentication was checked. Terminate with exception if no + * authentication was performed + * + * @throws CAS_OutOfSequenceBeforeAuthenticationCallException + * + * @return void + */ + private function _ensureAuthenticationCalled() + { + if (!$this->wasAuthenticationCalled()) { + throw new CAS_OutOfSequenceBeforeAuthenticationCallException(); + } + } + + /** + * Answer the result of the authentication call. + * + * Throws a CAS_OutOfSequenceException if wasAuthenticationCalled() is false + * and markAuthenticationCall() didn't happen. + * + * @return bool + */ + public function wasAuthenticationCallSuccessful () + { + $this->_ensureAuthenticationCalled(); + return $this->_authentication_caller['result']; + } + + + /** + * Ensure that authentication was checked. Terminate with exception if no + * authentication was performed + * + * @throws CAS_OutOfSequenceException + * + * @return void + */ + public function ensureAuthenticationCallSuccessful() + { + $this->_ensureAuthenticationCalled(); + if (!$this->_authentication_caller['result']) { + throw new CAS_OutOfSequenceException( + 'authentication was checked (by ' + . $this->getAuthenticationCallerMethod() + . '() at ' . $this->getAuthenticationCallerFile() + . ':' . $this->getAuthenticationCallerLine() + . ') but the method returned false' + ); + } + } + + /** + * Answer information about the authentication caller. + * + * Throws a CAS_OutOfSequenceException if wasAuthenticationCalled() is false + * and markAuthenticationCall() didn't happen. + * + * @return string the file that called authentication + */ + public function getAuthenticationCallerFile () + { + $this->_ensureAuthenticationCalled(); + return $this->_authentication_caller['file']; + } + + /** + * Answer information about the authentication caller. + * + * Throws a CAS_OutOfSequenceException if wasAuthenticationCalled() is false + * and markAuthenticationCall() didn't happen. + * + * @return int the line that called authentication + */ + public function getAuthenticationCallerLine () + { + $this->_ensureAuthenticationCalled(); + return $this->_authentication_caller['line']; + } + + /** + * Answer information about the authentication caller. + * + * Throws a CAS_OutOfSequenceException if wasAuthenticationCalled() is false + * and markAuthenticationCall() didn't happen. + * + * @return string the method that called authentication + */ + public function getAuthenticationCallerMethod () + { + $this->_ensureAuthenticationCalled(); + return $this->_authentication_caller['method']; + } + + /** @} */ + + // ######################################################################## + // CONSTRUCTOR + // ######################################################################## + /** + * @addtogroup internalConfig + * @{ + */ + + /** + * CAS_Client constructor. + * + * @param string $server_version the version of the CAS server + * @param bool $proxy true if the CAS client is a CAS proxy + * @param string $server_hostname the hostname of the CAS server + * @param int $server_port the port the CAS server is running on + * @param string $server_uri the URI the CAS server is responding on + * @param bool $changeSessionID Allow phpCAS to change the session_id + * (Single Sign Out/handleLogoutRequests + * is based on that change) + * + * @return self a newly created CAS_Client object + */ + public function __construct( + $server_version, + $proxy, + $server_hostname, + $server_port, + $server_uri, + $changeSessionID = true + ) { + // Argument validation + if (gettype($server_version) != 'string') + throw new CAS_TypeMismatchException($server_version, '$server_version', 'string'); + if (gettype($proxy) != 'boolean') + throw new CAS_TypeMismatchException($proxy, '$proxy', 'boolean'); + if (gettype($server_hostname) != 'string') + throw new CAS_TypeMismatchException($server_hostname, '$server_hostname', 'string'); + if (gettype($server_port) != 'integer') + throw new CAS_TypeMismatchException($server_port, '$server_port', 'integer'); + if (gettype($server_uri) != 'string') + throw new CAS_TypeMismatchException($server_uri, '$server_uri', 'string'); + if (gettype($changeSessionID) != 'boolean') + throw new CAS_TypeMismatchException($changeSessionID, '$changeSessionID', 'boolean'); + + phpCAS::traceBegin(); + // true : allow to change the session_id(), false session_id won't be + // change and logout won't be handle because of that + $this->_setChangeSessionID($changeSessionID); + + // skip Session Handling for logout requests and if don't want it' + if (session_id()=="" && !$this->_isLogoutRequest()) { + session_start(); + phpCAS :: trace("Starting a new session " . session_id()); + } + // Only for debug purposes + if ($this->isSessionAuthenticated()){ + phpCAS :: trace("Session is authenticated as: " . $_SESSION['phpCAS']['user']); + } else { + phpCAS :: trace("Session is not authenticated"); + } + // are we in proxy mode ? + $this->_proxy = $proxy; + + // Make cookie handling available. + if ($this->isProxy()) { + if (!isset($_SESSION['phpCAS'])) { + $_SESSION['phpCAS'] = array(); + } + if (!isset($_SESSION['phpCAS']['service_cookies'])) { + $_SESSION['phpCAS']['service_cookies'] = array(); + } + $this->_serviceCookieJar = new CAS_CookieJar( + $_SESSION['phpCAS']['service_cookies'] + ); + } + + // check version + $supportedProtocols = phpCAS::getSupportedProtocols(); + if (isset($supportedProtocols[$server_version]) === false) { + phpCAS::error( + 'this version of CAS (`'.$server_version + .'\') is not supported by phpCAS '.phpCAS::getVersion() + ); + } + + if ($server_version === CAS_VERSION_1_0 && $this->isProxy()) { + phpCAS::error( + 'CAS proxies are not supported in CAS '.$server_version + ); + } + + $this->_server['version'] = $server_version; + + // check hostname + if ( empty($server_hostname) + || !preg_match('/[\.\d\-a-z]*/', $server_hostname) + ) { + phpCAS::error('bad CAS server hostname (`'.$server_hostname.'\')'); + } + $this->_server['hostname'] = $server_hostname; + + // check port + if ( $server_port == 0 + || !is_int($server_port) + ) { + phpCAS::error('bad CAS server port (`'.$server_hostname.'\')'); + } + $this->_server['port'] = $server_port; + + // check URI + if ( !preg_match('/[\.\d\-_a-z\/]*/', $server_uri) ) { + phpCAS::error('bad CAS server URI (`'.$server_uri.'\')'); + } + // add leading and trailing `/' and remove doubles + if(strstr($server_uri, '?') === false) $server_uri .= '/'; + $server_uri = preg_replace('/\/\//', '/', '/'.$server_uri); + $this->_server['uri'] = $server_uri; + + // set to callback mode if PgtIou and PgtId CGI GET parameters are provided + if ( $this->isProxy() ) { + $this->_setCallbackMode(!empty($_GET['pgtIou'])&&!empty($_GET['pgtId'])); + } + + if ( $this->_isCallbackMode() ) { + //callback mode: check that phpCAS is secured + if ( !$this->_isHttps() ) { + phpCAS::error( + 'CAS proxies must be secured to use phpCAS; PGT\'s will not be received from the CAS server' + ); + } + } else { + //normal mode: get ticket and remove it from CGI parameters for + // developers + $ticket = (isset($_GET['ticket']) ? $_GET['ticket'] : null); + if (preg_match('/^[SP]T-/', $ticket) ) { + phpCAS::trace('Ticket \''.$ticket.'\' found'); + $this->setTicket($ticket); + unset($_GET['ticket']); + } else if ( !empty($ticket) ) { + //ill-formed ticket, halt + phpCAS::error( + 'ill-formed ticket found in the URL (ticket=`' + .htmlentities($ticket).'\')' + ); + } + + } + phpCAS::traceEnd(); + } + + /** @} */ + + // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + // XX XX + // XX Session Handling XX + // XX XX + // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + + /** + * @addtogroup internalConfig + * @{ + */ + + + /** + * @var bool A variable to whether phpcas will use its own session handling. Default = true + * @hideinitializer + */ + private $_change_session_id = true; + + /** + * Set a parameter whether to allow phpCAS to change session_id + * + * @param bool $allowed allow phpCAS to change session_id + * + * @return void + */ + private function _setChangeSessionID($allowed) + { + $this->_change_session_id = $allowed; + } + + /** + * Get whether phpCAS is allowed to change session_id + * + * @return bool + */ + public function getChangeSessionID() + { + return $this->_change_session_id; + } + + /** @} */ + + // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + // XX XX + // XX AUTHENTICATION XX + // XX XX + // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + + /** + * @addtogroup internalAuthentication + * @{ + */ + + /** + * The Authenticated user. Written by CAS_Client::_setUser(), read by + * CAS_Client::getUser(). + * + * @hideinitializer + */ + private $_user = ''; + + /** + * This method sets the CAS user's login name. + * + * @param string $user the login name of the authenticated user. + * + * @return void + */ + private function _setUser($user) + { + $this->_user = $user; + } + + /** + * This method returns the CAS user's login name. + * + * @return string the login name of the authenticated user + * + * @warning should be called only after CAS_Client::forceAuthentication() or + * CAS_Client::isAuthenticated(), otherwise halt with an error. + */ + public function getUser() + { + // Sequence validation + $this->ensureAuthenticationCallSuccessful(); + + return $this->_getUser(); + } + + /** + * This method returns the CAS user's login name. + * + * @return string the login name of the authenticated user + * + * @warning should be called only after CAS_Client::forceAuthentication() or + * CAS_Client::isAuthenticated(), otherwise halt with an error. + */ + private function _getUser() + { + // This is likely a duplicate check that could be removed.... + if ( empty($this->_user) ) { + phpCAS::error( + 'this method should be used only after '.__CLASS__ + .'::forceAuthentication() or '.__CLASS__.'::isAuthenticated()' + ); + } + return $this->_user; + } + + /** + * The Authenticated users attributes. Written by + * CAS_Client::setAttributes(), read by CAS_Client::getAttributes(). + * @attention client applications should use phpCAS::getAttributes(). + * + * @hideinitializer + */ + private $_attributes = array(); + + /** + * Set an array of attributes + * + * @param array $attributes a key value array of attributes + * + * @return void + */ + public function setAttributes($attributes) + { + $this->_attributes = $attributes; + } + + /** + * Get an key values arry of attributes + * + * @return array of attributes + */ + public function getAttributes() + { + // Sequence validation + $this->ensureAuthenticationCallSuccessful(); + // This is likely a duplicate check that could be removed.... + if ( empty($this->_user) ) { + // if no user is set, there shouldn't be any attributes also... + phpCAS::error( + 'this method should be used only after '.__CLASS__ + .'::forceAuthentication() or '.__CLASS__.'::isAuthenticated()' + ); + } + return $this->_attributes; + } + + /** + * Check whether attributes are available + * + * @return bool attributes available + */ + public function hasAttributes() + { + // Sequence validation + $this->ensureAuthenticationCallSuccessful(); + + return !empty($this->_attributes); + } + /** + * Check whether a specific attribute with a name is available + * + * @param string $key name of attribute + * + * @return bool is attribute available + */ + public function hasAttribute($key) + { + // Sequence validation + $this->ensureAuthenticationCallSuccessful(); + + return $this->_hasAttribute($key); + } + + /** + * Check whether a specific attribute with a name is available + * + * @param string $key name of attribute + * + * @return bool is attribute available + */ + private function _hasAttribute($key) + { + return (is_array($this->_attributes) + && array_key_exists($key, $this->_attributes)); + } + + /** + * Get a specific attribute by name + * + * @param string $key name of attribute + * + * @return string attribute values + */ + public function getAttribute($key) + { + // Sequence validation + $this->ensureAuthenticationCallSuccessful(); + + if ($this->_hasAttribute($key)) { + return $this->_attributes[$key]; + } + } + + /** + * This method is called to renew the authentication of the user + * If the user is authenticated, renew the connection + * If not, redirect to CAS + * + * @return bool true when the user is authenticated; otherwise halt. + */ + public function renewAuthentication() + { + phpCAS::traceBegin(); + // Either way, the user is authenticated by CAS + if (isset( $_SESSION['phpCAS']['auth_checked'])) { + unset($_SESSION['phpCAS']['auth_checked']); + } + if ( $this->isAuthenticated(true) ) { + phpCAS::trace('user already authenticated'); + $res = true; + } else { + $this->redirectToCas(false, true); + // never reached + $res = false; + } + phpCAS::traceEnd(); + return $res; + } + + /** + * This method is called to be sure that the user is authenticated. When not + * authenticated, halt by redirecting to the CAS server; otherwise return true. + * + * @return bool true when the user is authenticated; otherwise halt. + */ + public function forceAuthentication() + { + phpCAS::traceBegin(); + + if ( $this->isAuthenticated() ) { + // the user is authenticated, nothing to be done. + phpCAS::trace('no need to authenticate'); + $res = true; + } else { + // the user is not authenticated, redirect to the CAS server + if (isset($_SESSION['phpCAS']['auth_checked'])) { + unset($_SESSION['phpCAS']['auth_checked']); + } + $this->redirectToCas(false/* no gateway */); + // never reached + $res = false; + } + phpCAS::traceEnd($res); + return $res; + } + + /** + * An integer that gives the number of times authentication will be cached + * before rechecked. + * + * @hideinitializer + */ + private $_cache_times_for_auth_recheck = 0; + + /** + * Set the number of times authentication will be cached before rechecked. + * + * @param int $n number of times to wait for a recheck + * + * @return void + */ + public function setCacheTimesForAuthRecheck($n) + { + if (gettype($n) != 'integer') + throw new CAS_TypeMismatchException($n, '$n', 'string'); + + $this->_cache_times_for_auth_recheck = $n; + } + + /** + * This method is called to check whether the user is authenticated or not. + * + * @return bool true when the user is authenticated, false when a previous + * gateway login failed or the function will not return if the user is + * redirected to the cas server for a gateway login attempt + */ + public function checkAuthentication() + { + phpCAS::traceBegin(); + if ( $this->isAuthenticated() ) { + phpCAS::trace('user is authenticated'); + /* The 'auth_checked' variable is removed just in case it's set. */ + unset($_SESSION['phpCAS']['auth_checked']); + $res = true; + } else if (isset($_SESSION['phpCAS']['auth_checked'])) { + // the previous request has redirected the client to the CAS server + // with gateway=true + unset($_SESSION['phpCAS']['auth_checked']); + $res = false; + } else { + // avoid a check against CAS on every request + if (!isset($_SESSION['phpCAS']['unauth_count'])) { + $_SESSION['phpCAS']['unauth_count'] = -2; // uninitialized + } + + if (($_SESSION['phpCAS']['unauth_count'] != -2 + && $this->_cache_times_for_auth_recheck == -1) + || ($_SESSION['phpCAS']['unauth_count'] >= 0 + && $_SESSION['phpCAS']['unauth_count'] < $this->_cache_times_for_auth_recheck) + ) { + $res = false; + + if ($this->_cache_times_for_auth_recheck != -1) { + $_SESSION['phpCAS']['unauth_count']++; + phpCAS::trace( + 'user is not authenticated (cached for ' + .$_SESSION['phpCAS']['unauth_count'].' times of ' + .$this->_cache_times_for_auth_recheck.')' + ); + } else { + phpCAS::trace( + 'user is not authenticated (cached for until login pressed)' + ); + } + } else { + $_SESSION['phpCAS']['unauth_count'] = 0; + $_SESSION['phpCAS']['auth_checked'] = true; + phpCAS::trace('user is not authenticated (cache reset)'); + $this->redirectToCas(true/* gateway */); + // never reached + $res = false; + } + } + phpCAS::traceEnd($res); + return $res; + } + + /** + * This method is called to check if the user is authenticated (previously or by + * tickets given in the URL). + * + * @param bool $renew true to force the authentication with the CAS server + * + * @return bool true when the user is authenticated. Also may redirect to the + * same URL without the ticket. + */ + public function isAuthenticated($renew=false) + { + phpCAS::traceBegin(); + $res = false; + $validate_url = ''; + if ( $this->_wasPreviouslyAuthenticated() ) { + if ($this->hasTicket()) { + // User has a additional ticket but was already authenticated + phpCAS::trace( + 'ticket was present and will be discarded, use renewAuthenticate()' + ); + if ($this->_clearTicketsFromUrl) { + phpCAS::trace("Prepare redirect to : ".$this->getURL()); + session_write_close(); + header('Location: '.$this->getURL()); + flush(); + phpCAS::traceExit(); + throw new CAS_GracefullTerminationException(); + } else { + phpCAS::trace( + 'Already authenticated, but skipping ticket clearing since setNoClearTicketsFromUrl() was used.' + ); + $res = true; + } + } else { + // the user has already (previously during the session) been + // authenticated, nothing to be done. + phpCAS::trace( + 'user was already authenticated, no need to look for tickets' + ); + $res = true; + } + + // Mark the auth-check as complete to allow post-authentication + // callbacks to make use of phpCAS::getUser() and similar methods + $this->markAuthenticationCall($res); + } else { + if ($this->hasTicket()) { + switch ($this->getServerVersion()) { + case CAS_VERSION_1_0: + // if a Service Ticket was given, validate it + phpCAS::trace( + 'CAS 1.0 ticket `'.$this->getTicket().'\' is present' + ); + $this->validateCAS10( + $validate_url, $text_response, $tree_response, $renew + ); // if it fails, it halts + phpCAS::trace( + 'CAS 1.0 ticket `'.$this->getTicket().'\' was validated' + ); + $_SESSION['phpCAS']['user'] = $this->_getUser(); + $res = true; + $logoutTicket = $this->getTicket(); + break; + case CAS_VERSION_2_0: + case CAS_VERSION_3_0: + // if a Proxy Ticket was given, validate it + phpCAS::trace( + 'CAS '.$this->getServerVersion().' ticket `'.$this->getTicket().'\' is present' + ); + $this->validateCAS20( + $validate_url, $text_response, $tree_response, $renew + ); // note: if it fails, it halts + phpCAS::trace( + 'CAS '.$this->getServerVersion().' ticket `'.$this->getTicket().'\' was validated' + ); + if ( $this->isProxy() ) { + $this->_validatePGT( + $validate_url, $text_response, $tree_response + ); // idem + phpCAS::trace('PGT `'.$this->_getPGT().'\' was validated'); + $_SESSION['phpCAS']['pgt'] = $this->_getPGT(); + } + $_SESSION['phpCAS']['user'] = $this->_getUser(); + if (!empty($this->_attributes)) { + $_SESSION['phpCAS']['attributes'] = $this->_attributes; + } + $proxies = $this->getProxies(); + if (!empty($proxies)) { + $_SESSION['phpCAS']['proxies'] = $this->getProxies(); + } + $res = true; + $logoutTicket = $this->getTicket(); + break; + case SAML_VERSION_1_1: + // if we have a SAML ticket, validate it. + phpCAS::trace( + 'SAML 1.1 ticket `'.$this->getTicket().'\' is present' + ); + $this->validateSA( + $validate_url, $text_response, $tree_response, $renew + ); // if it fails, it halts + phpCAS::trace( + 'SAML 1.1 ticket `'.$this->getTicket().'\' was validated' + ); + $_SESSION['phpCAS']['user'] = $this->_getUser(); + $_SESSION['phpCAS']['attributes'] = $this->_attributes; + $res = true; + $logoutTicket = $this->getTicket(); + break; + default: + phpCAS::trace('Protocoll error'); + break; + } + } else { + // no ticket given, not authenticated + phpCAS::trace('no ticket found'); + } + + // Mark the auth-check as complete to allow post-authentication + // callbacks to make use of phpCAS::getUser() and similar methods + $this->markAuthenticationCall($res); + + if ($res) { + // call the post-authenticate callback if registered. + if ($this->_postAuthenticateCallbackFunction) { + $args = $this->_postAuthenticateCallbackArgs; + array_unshift($args, $logoutTicket); + call_user_func_array( + $this->_postAuthenticateCallbackFunction, $args + ); + } + + // if called with a ticket parameter, we need to redirect to the + // app without the ticket so that CAS-ification is transparent + // to the browser (for later POSTS) most of the checks and + // errors should have been made now, so we're safe for redirect + // without masking error messages. remove the ticket as a + // security precaution to prevent a ticket in the HTTP_REFERRER + if ($this->_clearTicketsFromUrl) { + phpCAS::trace("Prepare redirect to : ".$this->getURL()); + session_write_close(); + header('Location: '.$this->getURL()); + flush(); + phpCAS::traceExit(); + throw new CAS_GracefullTerminationException(); + } + } + } + phpCAS::traceEnd($res); + return $res; + } + + /** + * This method tells if the current session is authenticated. + * + * @return bool true if authenticated based soley on $_SESSION variable + */ + public function isSessionAuthenticated () + { + return !empty($_SESSION['phpCAS']['user']); + } + + /** + * This method tells if the user has already been (previously) authenticated + * by looking into the session variables. + * + * @note This function switches to callback mode when needed. + * + * @return bool true when the user has already been authenticated; false otherwise. + */ + private function _wasPreviouslyAuthenticated() + { + phpCAS::traceBegin(); + + if ( $this->_isCallbackMode() ) { + // Rebroadcast the pgtIou and pgtId to all nodes + if ($this->_rebroadcast&&!isset($_POST['rebroadcast'])) { + $this->_rebroadcast(self::PGTIOU); + } + $this->_callback(); + } + + $auth = false; + + if ( $this->isProxy() ) { + // CAS proxy: username and PGT must be present + if ( $this->isSessionAuthenticated() + && !empty($_SESSION['phpCAS']['pgt']) + ) { + // authentication already done + $this->_setUser($_SESSION['phpCAS']['user']); + if (isset($_SESSION['phpCAS']['attributes'])) { + $this->setAttributes($_SESSION['phpCAS']['attributes']); + } + $this->_setPGT($_SESSION['phpCAS']['pgt']); + phpCAS::trace( + 'user = `'.$_SESSION['phpCAS']['user'].'\', PGT = `' + .$_SESSION['phpCAS']['pgt'].'\'' + ); + + // Include the list of proxies + if (isset($_SESSION['phpCAS']['proxies'])) { + $this->_setProxies($_SESSION['phpCAS']['proxies']); + phpCAS::trace( + 'proxies = "' + .implode('", "', $_SESSION['phpCAS']['proxies']).'"' + ); + } + + $auth = true; + } elseif ( $this->isSessionAuthenticated() + && empty($_SESSION['phpCAS']['pgt']) + ) { + // these two variables should be empty or not empty at the same time + phpCAS::trace( + 'username found (`'.$_SESSION['phpCAS']['user'] + .'\') but PGT is empty' + ); + // unset all tickets to enforce authentication + unset($_SESSION['phpCAS']); + $this->setTicket(''); + } elseif ( !$this->isSessionAuthenticated() + && !empty($_SESSION['phpCAS']['pgt']) + ) { + // these two variables should be empty or not empty at the same time + phpCAS::trace( + 'PGT found (`'.$_SESSION['phpCAS']['pgt'] + .'\') but username is empty' + ); + // unset all tickets to enforce authentication + unset($_SESSION['phpCAS']); + $this->setTicket(''); + } else { + phpCAS::trace('neither user nor PGT found'); + } + } else { + // `simple' CAS client (not a proxy): username must be present + if ( $this->isSessionAuthenticated() ) { + // authentication already done + $this->_setUser($_SESSION['phpCAS']['user']); + if (isset($_SESSION['phpCAS']['attributes'])) { + $this->setAttributes($_SESSION['phpCAS']['attributes']); + } + phpCAS::trace('user = `'.$_SESSION['phpCAS']['user'].'\''); + + // Include the list of proxies + if (isset($_SESSION['phpCAS']['proxies'])) { + $this->_setProxies($_SESSION['phpCAS']['proxies']); + phpCAS::trace( + 'proxies = "' + .implode('", "', $_SESSION['phpCAS']['proxies']).'"' + ); + } + + $auth = true; + } else { + phpCAS::trace('no user found'); + } + } + + phpCAS::traceEnd($auth); + return $auth; + } + + /** + * This method is used to redirect the client to the CAS server. + * It is used by CAS_Client::forceAuthentication() and + * CAS_Client::checkAuthentication(). + * + * @param bool $gateway true to check authentication, false to force it + * @param bool $renew true to force the authentication with the CAS server + * + * @return void + */ + public function redirectToCas($gateway=false,$renew=false) + { + phpCAS::traceBegin(); + $cas_url = $this->getServerLoginURL($gateway, $renew); + session_write_close(); + if (php_sapi_name() === 'cli') { + @header('Location: '.$cas_url); + } else { + header('Location: '.$cas_url); + } + phpCAS::trace("Redirect to : ".$cas_url); + $lang = $this->getLangObj(); + $this->printHTMLHeader($lang->getAuthenticationWanted()); + printf('

'. $lang->getShouldHaveBeenRedirected(). '

', $cas_url); + $this->printHTMLFooter(); + phpCAS::traceExit(); + throw new CAS_GracefullTerminationException(); + } + + + /** + * This method is used to logout from CAS. + * + * @param array $params an array that contains the optional url and service + * parameters that will be passed to the CAS server + * + * @return void + */ + public function logout($params) + { + phpCAS::traceBegin(); + $cas_url = $this->getServerLogoutURL(); + $paramSeparator = '?'; + if (isset($params['url'])) { + $cas_url = $cas_url . $paramSeparator . "url=" + . urlencode($params['url']); + $paramSeparator = '&'; + } + if (isset($params['service'])) { + $cas_url = $cas_url . $paramSeparator . "service=" + . urlencode($params['service']); + } + header('Location: '.$cas_url); + phpCAS::trace("Prepare redirect to : ".$cas_url); + + phpCAS::trace("Destroying session : ".session_id()); + session_unset(); + session_destroy(); + if (session_status() === PHP_SESSION_NONE) { + phpCAS::trace("Session terminated"); + } else { + phpCAS::error("Session was not terminated"); + phpCAS::trace("Session was not terminated"); + } + $lang = $this->getLangObj(); + $this->printHTMLHeader($lang->getLogout()); + printf('

'.$lang->getShouldHaveBeenRedirected(). '

', $cas_url); + $this->printHTMLFooter(); + phpCAS::traceExit(); + throw new CAS_GracefullTerminationException(); + } + + /** + * Check of the current request is a logout request + * + * @return bool is logout request. + */ + private function _isLogoutRequest() + { + return !empty($_POST['logoutRequest']); + } + + /** + * This method handles logout requests. + * + * @param bool $check_client true to check the client bofore handling + * the request, false not to perform any access control. True by default. + * @param array $allowed_clients an array of host names allowed to send + * logout requests. + * + * @return void + */ + public function handleLogoutRequests($check_client=true, $allowed_clients=array()) + { + phpCAS::traceBegin(); + if (!$this->_isLogoutRequest()) { + phpCAS::trace("Not a logout request"); + phpCAS::traceEnd(); + return; + } + if (!$this->getChangeSessionID() + && is_null($this->_signoutCallbackFunction) + ) { + phpCAS::trace( + "phpCAS can't handle logout requests if it is not allowed to change session_id." + ); + } + phpCAS::trace("Logout requested"); + $decoded_logout_rq = urldecode($_POST['logoutRequest']); + phpCAS::trace("SAML REQUEST: ".$decoded_logout_rq); + $allowed = false; + if ($check_client) { + if ($allowed_clients === array()) { + $allowed_clients = array( $this->_getServerHostname() ); + } + $client_ip = $_SERVER['REMOTE_ADDR']; + $client = gethostbyaddr($client_ip); + phpCAS::trace("Client: ".$client."/".$client_ip); + foreach ($allowed_clients as $allowed_client) { + if (($client == $allowed_client) + || ($client_ip == $allowed_client) + ) { + phpCAS::trace( + "Allowed client '".$allowed_client + ."' matches, logout request is allowed" + ); + $allowed = true; + break; + } else { + phpCAS::trace( + "Allowed client '".$allowed_client."' does not match" + ); + } + } + } else { + phpCAS::trace("No access control set"); + $allowed = true; + } + // If Logout command is permitted proceed with the logout + if ($allowed) { + phpCAS::trace("Logout command allowed"); + // Rebroadcast the logout request + if ($this->_rebroadcast && !isset($_POST['rebroadcast'])) { + $this->_rebroadcast(self::LOGOUT); + } + // Extract the ticket from the SAML Request + preg_match( + "|(.*)|", + $decoded_logout_rq, $tick, PREG_OFFSET_CAPTURE, 3 + ); + $wrappedSamlSessionIndex = preg_replace( + '||', '', $tick[0][0] + ); + $ticket2logout = preg_replace( + '||', '', $wrappedSamlSessionIndex + ); + phpCAS::trace("Ticket to logout: ".$ticket2logout); + + // call the post-authenticate callback if registered. + if ($this->_signoutCallbackFunction) { + $args = $this->_signoutCallbackArgs; + array_unshift($args, $ticket2logout); + call_user_func_array($this->_signoutCallbackFunction, $args); + } + + // If phpCAS is managing the session_id, destroy session thanks to + // session_id. + if ($this->getChangeSessionID()) { + $session_id = $this->_sessionIdForTicket($ticket2logout); + phpCAS::trace("Session id: ".$session_id); + + // destroy a possible application session created before phpcas + if (session_id() !== "") { + session_unset(); + session_destroy(); + } + // fix session ID + session_id($session_id); + $_COOKIE[session_name()]=$session_id; + $_GET[session_name()]=$session_id; + + // Overwrite session + session_start(); + session_unset(); + session_destroy(); + phpCAS::trace("Session ". $session_id . " destroyed"); + } + } else { + phpCAS::error("Unauthorized logout request from client '".$client."'"); + phpCAS::trace("Unauthorized logout request from client '".$client."'"); + } + flush(); + phpCAS::traceExit(); + throw new CAS_GracefullTerminationException(); + + } + + /** @} */ + + // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + // XX XX + // XX BASIC CLIENT FEATURES (CAS 1.0) XX + // XX XX + // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + + // ######################################################################## + // ST + // ######################################################################## + /** + * @addtogroup internalBasic + * @{ + */ + + /** + * The Ticket provided in the URL of the request if present + * (empty otherwise). Written by CAS_Client::CAS_Client(), read by + * CAS_Client::getTicket() and CAS_Client::_hasPGT(). + * + * @hideinitializer + */ + private $_ticket = ''; + + /** + * This method returns the Service Ticket provided in the URL of the request. + * + * @return string service ticket. + */ + public function getTicket() + { + return $this->_ticket; + } + + /** + * This method stores the Service Ticket. + * + * @param string $st The Service Ticket. + * + * @return void + */ + public function setTicket($st) + { + $this->_ticket = $st; + } + + /** + * This method tells if a Service Ticket was stored. + * + * @return bool if a Service Ticket has been stored. + */ + public function hasTicket() + { + return !empty($this->_ticket); + } + + /** @} */ + + // ######################################################################## + // ST VALIDATION + // ######################################################################## + /** + * @addtogroup internalBasic + * @{ + */ + + /** + * @var string the certificate of the CAS server CA. + * + * @hideinitializer + */ + private $_cas_server_ca_cert = null; + + + /** + + * validate CN of the CAS server certificate + + * + + * @hideinitializer + + */ + + private $_cas_server_cn_validate = true; + + /** + * Set to true not to validate the CAS server. + * + * @hideinitializer + */ + private $_no_cas_server_validation = false; + + + /** + * Set the CA certificate of the CAS server. + * + * @param string $cert the PEM certificate file name of the CA that emited + * the cert of the server + * @param bool $validate_cn valiate CN of the CAS server certificate + * + * @return void + */ + public function setCasServerCACert($cert, $validate_cn) + { + // Argument validation + if (gettype($cert) != 'string') { + throw new CAS_TypeMismatchException($cert, '$cert', 'string'); + } + if (gettype($validate_cn) != 'boolean') { + throw new CAS_TypeMismatchException($validate_cn, '$validate_cn', 'boolean'); + } + if ( !file_exists($cert) && $this->_requestImplementation !== 'CAS_TestHarness_DummyRequest'){ + throw new CAS_InvalidArgumentException("Certificate file does not exist " . $this->_requestImplementation); + } + $this->_cas_server_ca_cert = $cert; + $this->_cas_server_cn_validate = $validate_cn; + } + + /** + * Set no SSL validation for the CAS server. + * + * @return void + */ + public function setNoCasServerValidation() + { + $this->_no_cas_server_validation = true; + } + + /** + * This method is used to validate a CAS 1,0 ticket; halt on failure, and + * sets $validate_url, $text_reponse and $tree_response on success. + * + * @param string &$validate_url reference to the the URL of the request to + * the CAS server. + * @param string &$text_response reference to the response of the CAS + * server, as is (XML text). + * @param string &$tree_response reference to the response of the CAS + * server, as a DOM XML tree. + * @param bool $renew true to force the authentication with the CAS server + * + * @return bool true when successfull and issue a CAS_AuthenticationException + * and false on an error + * @throws CAS_AuthenticationException + */ + public function validateCAS10(&$validate_url,&$text_response,&$tree_response,$renew=false) + { + phpCAS::traceBegin(); + // build the URL to validate the ticket + $validate_url = $this->getServerServiceValidateURL() + .'&ticket='.urlencode($this->getTicket()); + + if ( $renew ) { + // pass the renew + $validate_url .= '&renew=true'; + } + + // open and read the URL + if ( !$this->_readURL($validate_url, $headers, $text_response, $err_msg) ) { + phpCAS::trace( + 'could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')' + ); + throw new CAS_AuthenticationException( + $this, 'CAS 1.0 ticket not validated', $validate_url, + true/*$no_response*/ + ); + } + + if (preg_match('/^no\n/', $text_response)) { + phpCAS::trace('Ticket has not been validated'); + throw new CAS_AuthenticationException( + $this, 'ST not validated', $validate_url, false/*$no_response*/, + false/*$bad_response*/, $text_response + ); + } else if (!preg_match('/^yes\n/', $text_response)) { + phpCAS::trace('ill-formed response'); + throw new CAS_AuthenticationException( + $this, 'Ticket not validated', $validate_url, + false/*$no_response*/, true/*$bad_response*/, $text_response + ); + } + // ticket has been validated, extract the user name + $arr = preg_split('/\n/', $text_response); + $this->_setUser(trim($arr[1])); + + $this->_renameSession($this->getTicket()); + + // at this step, ticket has been validated and $this->_user has been set, + phpCAS::traceEnd(true); + return true; + } + + /** @} */ + + + // ######################################################################## + // SAML VALIDATION + // ######################################################################## + /** + * @addtogroup internalSAML + * @{ + */ + + /** + * This method is used to validate a SAML TICKET; halt on failure, and sets + * $validate_url, $text_reponse and $tree_response on success. These + * parameters are used later by CAS_Client::_validatePGT() for CAS proxies. + * + * @param string &$validate_url reference to the the URL of the request to + * the CAS server. + * @param string &$text_response reference to the response of the CAS + * server, as is (XML text). + * @param string &$tree_response reference to the response of the CAS + * server, as a DOM XML tree. + * @param bool $renew true to force the authentication with the CAS server + * + * @return bool true when successfull and issue a CAS_AuthenticationException + * and false on an error + * + * @throws CAS_AuthenticationException + */ + public function validateSA(&$validate_url,&$text_response,&$tree_response,$renew=false) + { + phpCAS::traceBegin(); + $result = false; + // build the URL to validate the ticket + $validate_url = $this->getServerSamlValidateURL(); + + if ( $renew ) { + // pass the renew + $validate_url .= '&renew=true'; + } + + // open and read the URL + if ( !$this->_readURL($validate_url, $headers, $text_response, $err_msg) ) { + phpCAS::trace( + 'could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')' + ); + throw new CAS_AuthenticationException( + $this, 'SA not validated', $validate_url, true/*$no_response*/ + ); + } + + phpCAS::trace('server version: '.$this->getServerVersion()); + + // analyze the result depending on the version + switch ($this->getServerVersion()) { + case SAML_VERSION_1_1: + // create new DOMDocument Object + $dom = new DOMDocument(); + // Fix possible whitspace problems + $dom->preserveWhiteSpace = false; + // read the response of the CAS server into a DOM object + if (!($dom->loadXML($text_response))) { + phpCAS::trace('dom->loadXML() failed'); + throw new CAS_AuthenticationException( + $this, 'SA not validated', $validate_url, + false/*$no_response*/, true/*$bad_response*/, + $text_response + ); + } + // read the root node of the XML tree + if (!($tree_response = $dom->documentElement)) { + phpCAS::trace('documentElement() failed'); + throw new CAS_AuthenticationException( + $this, 'SA not validated', $validate_url, + false/*$no_response*/, true/*$bad_response*/, + $text_response + ); + } else if ( $tree_response->localName != 'Envelope' ) { + // insure that tag name is 'Envelope' + phpCAS::trace( + 'bad XML root node (should be `Envelope\' instead of `' + .$tree_response->localName.'\'' + ); + throw new CAS_AuthenticationException( + $this, 'SA not validated', $validate_url, + false/*$no_response*/, true/*$bad_response*/, + $text_response + ); + } else if ($tree_response->getElementsByTagName("NameIdentifier")->length != 0) { + // check for the NameIdentifier tag in the SAML response + $success_elements = $tree_response->getElementsByTagName("NameIdentifier"); + phpCAS::trace('NameIdentifier found'); + $user = trim($success_elements->item(0)->nodeValue); + phpCAS::trace('user = `'.$user.'`'); + $this->_setUser($user); + $this->_setSessionAttributes($text_response); + $result = true; + } else { + phpCAS::trace('no tag found in SAML payload'); + throw new CAS_AuthenticationException( + $this, 'SA not validated', $validate_url, + false/*$no_response*/, true/*$bad_response*/, + $text_response + ); + } + } + if ($result) { + $this->_renameSession($this->getTicket()); + } + // at this step, ST has been validated and $this->_user has been set, + phpCAS::traceEnd($result); + return $result; + } + + /** + * This method will parse the DOM and pull out the attributes from the SAML + * payload and put them into an array, then put the array into the session. + * + * @param string $text_response the SAML payload. + * + * @return bool true when successfull and false if no attributes a found + */ + private function _setSessionAttributes($text_response) + { + phpCAS::traceBegin(); + + $result = false; + + $attr_array = array(); + + // create new DOMDocument Object + $dom = new DOMDocument(); + // Fix possible whitspace problems + $dom->preserveWhiteSpace = false; + if (($dom->loadXML($text_response))) { + $xPath = new DOMXPath($dom); + $xPath->registerNamespace('samlp', 'urn:oasis:names:tc:SAML:1.0:protocol'); + $xPath->registerNamespace('saml', 'urn:oasis:names:tc:SAML:1.0:assertion'); + $nodelist = $xPath->query("//saml:Attribute"); + + if ($nodelist) { + foreach ($nodelist as $node) { + $xres = $xPath->query("saml:AttributeValue", $node); + $name = $node->getAttribute("AttributeName"); + $value_array = array(); + foreach ($xres as $node2) { + $value_array[] = $node2->nodeValue; + } + $attr_array[$name] = $value_array; + } + // UGent addition... + foreach ($attr_array as $attr_key => $attr_value) { + if (count($attr_value) > 1) { + $this->_attributes[$attr_key] = $attr_value; + phpCAS::trace("* " . $attr_key . "=" . print_r($attr_value, true)); + } else { + $this->_attributes[$attr_key] = $attr_value[0]; + phpCAS::trace("* " . $attr_key . "=" . $attr_value[0]); + } + } + $result = true; + } else { + phpCAS::trace("SAML Attributes are empty"); + $result = false; + } + } + phpCAS::traceEnd($result); + return $result; + } + + /** @} */ + + // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + // XX XX + // XX PROXY FEATURES (CAS 2.0) XX + // XX XX + // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + + // ######################################################################## + // PROXYING + // ######################################################################## + /** + * @addtogroup internalProxy + * @{ + */ + + /** + * @var bool is the client a proxy + * A boolean telling if the client is a CAS proxy or not. Written by + * CAS_Client::CAS_Client(), read by CAS_Client::isProxy(). + */ + private $_proxy; + + /** + * @var CAS_CookieJar Handler for managing service cookies. + */ + private $_serviceCookieJar; + + /** + * Tells if a CAS client is a CAS proxy or not + * + * @return bool true when the CAS client is a CAS proxy, false otherwise + */ + public function isProxy() + { + return $this->_proxy; + } + + + /** @} */ + // ######################################################################## + // PGT + // ######################################################################## + /** + * @addtogroup internalProxy + * @{ + */ + + /** + * the Proxy Grnting Ticket given by the CAS server (empty otherwise). + * Written by CAS_Client::_setPGT(), read by CAS_Client::_getPGT() and + * CAS_Client::_hasPGT(). + * + * @hideinitializer + */ + private $_pgt = ''; + + /** + * This method returns the Proxy Granting Ticket given by the CAS server. + * + * @return string the Proxy Granting Ticket. + */ + private function _getPGT() + { + return $this->_pgt; + } + + /** + * This method stores the Proxy Granting Ticket. + * + * @param string $pgt The Proxy Granting Ticket. + * + * @return void + */ + private function _setPGT($pgt) + { + $this->_pgt = $pgt; + } + + /** + * This method tells if a Proxy Granting Ticket was stored. + * + * @return bool true if a Proxy Granting Ticket has been stored. + */ + private function _hasPGT() + { + return !empty($this->_pgt); + } + + /** @} */ + + // ######################################################################## + // CALLBACK MODE + // ######################################################################## + /** + * @addtogroup internalCallback + * @{ + */ + /** + * each PHP script using phpCAS in proxy mode is its own callback to get the + * PGT back from the CAS server. callback_mode is detected by the constructor + * thanks to the GET parameters. + */ + + /** + * @var bool a boolean to know if the CAS client is running in callback mode. Written by + * CAS_Client::setCallBackMode(), read by CAS_Client::_isCallbackMode(). + * + * @hideinitializer + */ + private $_callback_mode = false; + + /** + * This method sets/unsets callback mode. + * + * @param bool $callback_mode true to set callback mode, false otherwise. + * + * @return void + */ + private function _setCallbackMode($callback_mode) + { + $this->_callback_mode = $callback_mode; + } + + /** + * This method returns true when the CAS client is running in callback mode, + * false otherwise. + * + * @return bool A boolean. + */ + private function _isCallbackMode() + { + return $this->_callback_mode; + } + + /** + * the URL that should be used for the PGT callback (in fact the URL of the + * current request without any CGI parameter). Written and read by + * CAS_Client::_getCallbackURL(). + * + * @hideinitializer + */ + private $_callback_url = ''; + + /** + * This method returns the URL that should be used for the PGT callback (in + * fact the URL of the current request without any CGI parameter, except if + * phpCAS::setFixedCallbackURL() was used). + * + * @return string The callback URL + */ + private function _getCallbackURL() + { + // the URL is built when needed only + if ( empty($this->_callback_url) ) { + // remove the ticket if present in the URL + $final_uri = 'https://'; + $final_uri .= $this->_getClientUrl(); + $request_uri = $_SERVER['REQUEST_URI']; + $request_uri = preg_replace('/\?.*$/', '', $request_uri); + $final_uri .= $request_uri; + $this->_callback_url = $final_uri; + } + return $this->_callback_url; + } + + /** + * This method sets the callback url. + * + * @param string $url url to set callback + * + * @return string the callback url + */ + public function setCallbackURL($url) + { + // Sequence validation + $this->ensureIsProxy(); + // Argument Validation + if (gettype($url) != 'string') + throw new CAS_TypeMismatchException($url, '$url', 'string'); + + return $this->_callback_url = $url; + } + + /** + * This method is called by CAS_Client::CAS_Client() when running in callback + * mode. It stores the PGT and its PGT Iou, prints its output and halts. + * + * @return void + */ + private function _callback() + { + phpCAS::traceBegin(); + if (preg_match('/^PGTIOU-[\.\-\w]+$/', $_GET['pgtIou'])) { + if (preg_match('/^[PT]GT-[\.\-\w]+$/', $_GET['pgtId'])) { + $this->printHTMLHeader('phpCAS callback'); + $pgt_iou = $_GET['pgtIou']; + $pgt = $_GET['pgtId']; + phpCAS::trace('Storing PGT `'.$pgt.'\' (id=`'.$pgt_iou.'\')'); + echo '

Storing PGT `'.$pgt.'\' (id=`'.$pgt_iou.'\').

'; + $this->_storePGT($pgt, $pgt_iou); + $this->printHTMLFooter(); + phpCAS::traceExit("Successfull Callback"); + } else { + phpCAS::error('PGT format invalid' . $_GET['pgtId']); + phpCAS::traceExit('PGT format invalid' . $_GET['pgtId']); + } + } else { + phpCAS::error('PGTiou format invalid' . $_GET['pgtIou']); + phpCAS::traceExit('PGTiou format invalid' . $_GET['pgtIou']); + } + + // Flush the buffer to prevent from sending anything other then a 200 + // Success Status back to the CAS Server. The Exception would normally + // report as a 500 error. + flush(); + throw new CAS_GracefullTerminationException(); + } + + + /** @} */ + + // ######################################################################## + // PGT STORAGE + // ######################################################################## + /** + * @addtogroup internalPGTStorage + * @{ + */ + + /** + * @var CAS_PGTStorage_AbstractStorage + * an instance of a class inheriting of PGTStorage, used to deal with PGT + * storage. Created by CAS_Client::setPGTStorageFile(), used + * by CAS_Client::setPGTStorageFile() and CAS_Client::_initPGTStorage(). + * + * @hideinitializer + */ + private $_pgt_storage = null; + + /** + * This method is used to initialize the storage of PGT's. + * Halts on error. + * + * @return void + */ + private function _initPGTStorage() + { + // if no SetPGTStorageXxx() has been used, default to file + if ( !is_object($this->_pgt_storage) ) { + $this->setPGTStorageFile(); + } + + // initializes the storage + $this->_pgt_storage->init(); + } + + /** + * This method stores a PGT. Halts on error. + * + * @param string $pgt the PGT to store + * @param string $pgt_iou its corresponding Iou + * + * @return void + */ + private function _storePGT($pgt,$pgt_iou) + { + // ensure that storage is initialized + $this->_initPGTStorage(); + // writes the PGT + $this->_pgt_storage->write($pgt, $pgt_iou); + } + + /** + * This method reads a PGT from its Iou and deletes the corresponding + * storage entry. + * + * @param string $pgt_iou the PGT Iou + * + * @return string mul The PGT corresponding to the Iou, false when not found. + */ + private function _loadPGT($pgt_iou) + { + // ensure that storage is initialized + $this->_initPGTStorage(); + // read the PGT + return $this->_pgt_storage->read($pgt_iou); + } + + /** + * This method can be used to set a custom PGT storage object. + * + * @param CAS_PGTStorage_AbstractStorage $storage a PGT storage object that + * inherits from the CAS_PGTStorage_AbstractStorage class + * + * @return void + */ + public function setPGTStorage($storage) + { + // Sequence validation + $this->ensureIsProxy(); + + // check that the storage has not already been set + if ( is_object($this->_pgt_storage) ) { + phpCAS::error('PGT storage already defined'); + } + + // check to make sure a valid storage object was specified + if ( !($storage instanceof CAS_PGTStorage_AbstractStorage) ) + throw new CAS_TypeMismatchException($storage, '$storage', 'CAS_PGTStorage_AbstractStorage object'); + + // store the PGTStorage object + $this->_pgt_storage = $storage; + } + + /** + * This method is used to tell phpCAS to store the response of the + * CAS server to PGT requests in a database. + * + * @param string|PDO $dsn_or_pdo a dsn string to use for creating a PDO + * object or a PDO object + * @param string $username the username to use when connecting to the + * database + * @param string $password the password to use when connecting to the + * database + * @param string $table the table to use for storing and retrieving + * PGTs + * @param string $driver_options any driver options to use when connecting + * to the database + * + * @return void + */ + public function setPGTStorageDb( + $dsn_or_pdo, $username='', $password='', $table='', $driver_options=null + ) { + // Sequence validation + $this->ensureIsProxy(); + + // Argument validation + if (!(is_object($dsn_or_pdo) && $dsn_or_pdo instanceof PDO) && !is_string($dsn_or_pdo)) + throw new CAS_TypeMismatchException($dsn_or_pdo, '$dsn_or_pdo', 'string or PDO object'); + if (gettype($username) != 'string') + throw new CAS_TypeMismatchException($username, '$username', 'string'); + if (gettype($password) != 'string') + throw new CAS_TypeMismatchException($password, '$password', 'string'); + if (gettype($table) != 'string') + throw new CAS_TypeMismatchException($table, '$password', 'string'); + + // create the storage object + $this->setPGTStorage( + new CAS_PGTStorage_Db( + $this, $dsn_or_pdo, $username, $password, $table, $driver_options + ) + ); + } + + /** + * This method is used to tell phpCAS to store the response of the + * CAS server to PGT requests onto the filesystem. + * + * @param string $path the path where the PGT's should be stored + * + * @return void + */ + public function setPGTStorageFile($path='') + { + // Sequence validation + $this->ensureIsProxy(); + + // Argument validation + if (gettype($path) != 'string') + throw new CAS_TypeMismatchException($path, '$path', 'string'); + + // create the storage object + $this->setPGTStorage(new CAS_PGTStorage_File($this, $path)); + } + + + // ######################################################################## + // PGT VALIDATION + // ######################################################################## + /** + * This method is used to validate a PGT; halt on failure. + * + * @param string &$validate_url the URL of the request to the CAS server. + * @param string $text_response the response of the CAS server, as is + * (XML text); result of + * CAS_Client::validateCAS10() or + * CAS_Client::validateCAS20(). + * @param DOMElement $tree_response the response of the CAS server, as a DOM XML + * tree; result of CAS_Client::validateCAS10() or CAS_Client::validateCAS20(). + * + * @return bool true when successfull and issue a CAS_AuthenticationException + * and false on an error + * + * @throws CAS_AuthenticationException + */ + private function _validatePGT(&$validate_url,$text_response,$tree_response) + { + phpCAS::traceBegin(); + if ( $tree_response->getElementsByTagName("proxyGrantingTicket")->length == 0) { + phpCAS::trace(' not found'); + // authentication succeded, but no PGT Iou was transmitted + throw new CAS_AuthenticationException( + $this, 'Ticket validated but no PGT Iou transmitted', + $validate_url, false/*$no_response*/, false/*$bad_response*/, + $text_response + ); + } else { + // PGT Iou transmitted, extract it + $pgt_iou = trim( + $tree_response->getElementsByTagName("proxyGrantingTicket")->item(0)->nodeValue + ); + if (preg_match('/^PGTIOU-[\.\-\w]+$/', $pgt_iou)) { + $pgt = $this->_loadPGT($pgt_iou); + if ( $pgt == false ) { + phpCAS::trace('could not load PGT'); + throw new CAS_AuthenticationException( + $this, + 'PGT Iou was transmitted but PGT could not be retrieved', + $validate_url, false/*$no_response*/, + false/*$bad_response*/, $text_response + ); + } + $this->_setPGT($pgt); + } else { + phpCAS::trace('PGTiou format error'); + throw new CAS_AuthenticationException( + $this, 'PGT Iou was transmitted but has wrong format', + $validate_url, false/*$no_response*/, false/*$bad_response*/, + $text_response + ); + } + } + phpCAS::traceEnd(true); + return true; + } + + // ######################################################################## + // PGT VALIDATION + // ######################################################################## + + /** + * This method is used to retrieve PT's from the CAS server thanks to a PGT. + * + * @param string $target_service the service to ask for with the PT. + * @param int &$err_code an error code (PHPCAS_SERVICE_OK on success). + * @param string &$err_msg an error message (empty on success). + * + * @return string|false a Proxy Ticket, or false on error. + */ + public function retrievePT($target_service,&$err_code,&$err_msg) + { + // Argument validation + if (gettype($target_service) != 'string') + throw new CAS_TypeMismatchException($target_service, '$target_service', 'string'); + + phpCAS::traceBegin(); + + // by default, $err_msg is set empty and $pt to true. On error, $pt is + // set to false and $err_msg to an error message. At the end, if $pt is false + // and $error_msg is still empty, it is set to 'invalid response' (the most + // commonly encountered error). + $err_msg = ''; + + // build the URL to retrieve the PT + $cas_url = $this->getServerProxyURL().'?targetService=' + .urlencode($target_service).'&pgt='.$this->_getPGT(); + + // open and read the URL + if ( !$this->_readURL($cas_url, $headers, $cas_response, $err_msg) ) { + phpCAS::trace( + 'could not open URL \''.$cas_url.'\' to validate ('.$err_msg.')' + ); + $err_code = PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE; + $err_msg = 'could not retrieve PT (no response from the CAS server)'; + phpCAS::traceEnd(false); + return false; + } + + $bad_response = false; + + // create new DOMDocument object + $dom = new DOMDocument(); + // Fix possible whitspace problems + $dom->preserveWhiteSpace = false; + // read the response of the CAS server into a DOM object + if ( !($dom->loadXML($cas_response))) { + phpCAS::trace('dom->loadXML() failed'); + // read failed + $bad_response = true; + } + + if ( !$bad_response ) { + // read the root node of the XML tree + if ( !($root = $dom->documentElement) ) { + phpCAS::trace('documentElement failed'); + // read failed + $bad_response = true; + } + } + + if ( !$bad_response ) { + // insure that tag name is 'serviceResponse' + if ( $root->localName != 'serviceResponse' ) { + phpCAS::trace('localName failed'); + // bad root node + $bad_response = true; + } + } + + if ( !$bad_response ) { + // look for a proxySuccess tag + if ( $root->getElementsByTagName("proxySuccess")->length != 0) { + $proxy_success_list = $root->getElementsByTagName("proxySuccess"); + + // authentication succeded, look for a proxyTicket tag + if ( $proxy_success_list->item(0)->getElementsByTagName("proxyTicket")->length != 0) { + $err_code = PHPCAS_SERVICE_OK; + $err_msg = ''; + $pt = trim( + $proxy_success_list->item(0)->getElementsByTagName("proxyTicket")->item(0)->nodeValue + ); + phpCAS::trace('original PT: '.trim($pt)); + phpCAS::traceEnd($pt); + return $pt; + } else { + phpCAS::trace(' was found, but not '); + } + } else if ($root->getElementsByTagName("proxyFailure")->length != 0) { + // look for a proxyFailure tag + $proxy_failure_list = $root->getElementsByTagName("proxyFailure"); + + // authentication failed, extract the error + $err_code = PHPCAS_SERVICE_PT_FAILURE; + $err_msg = 'PT retrieving failed (code=`' + .$proxy_failure_list->item(0)->getAttribute('code') + .'\', message=`' + .trim($proxy_failure_list->item(0)->nodeValue) + .'\')'; + phpCAS::traceEnd(false); + return false; + } else { + phpCAS::trace('neither nor found'); + } + } + + // at this step, we are sure that the response of the CAS server was + // illformed + $err_code = PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE; + $err_msg = 'Invalid response from the CAS server (response=`' + .$cas_response.'\')'; + + phpCAS::traceEnd(false); + return false; + } + + /** @} */ + + // ######################################################################## + // READ CAS SERVER ANSWERS + // ######################################################################## + + /** + * @addtogroup internalMisc + * @{ + */ + + /** + * This method is used to acces a remote URL. + * + * @param string $url the URL to access. + * @param string &$headers an array containing the HTTP header lines of the + * response (an empty array on failure). + * @param string &$body the body of the response, as a string (empty on + * failure). + * @param string &$err_msg an error message, filled on failure. + * + * @return bool true on success, false otherwise (in this later case, $err_msg + * contains an error message). + */ + private function _readURL($url, &$headers, &$body, &$err_msg) + { + phpCAS::traceBegin(); + $className = $this->_requestImplementation; + $request = new $className(); + + if (count($this->_curl_options)) { + $request->setCurlOptions($this->_curl_options); + } + + $request->setUrl($url); + + if (empty($this->_cas_server_ca_cert) && !$this->_no_cas_server_validation) { + phpCAS::error( + 'one of the methods phpCAS::setCasServerCACert() or phpCAS::setNoCasServerValidation() must be called.' + ); + } + if ($this->_cas_server_ca_cert != '') { + $request->setSslCaCert( + $this->_cas_server_ca_cert, $this->_cas_server_cn_validate + ); + } + + // add extra stuff if SAML + if ($this->getServerVersion() == SAML_VERSION_1_1) { + $request->addHeader("soapaction: http://www.oasis-open.org/committees/security"); + $request->addHeader("cache-control: no-cache"); + $request->addHeader("pragma: no-cache"); + $request->addHeader("accept: text/xml"); + $request->addHeader("connection: keep-alive"); + $request->addHeader("content-type: text/xml"); + $request->makePost(); + $request->setPostBody($this->_buildSAMLPayload()); + } + + if ($request->send()) { + $headers = $request->getResponseHeaders(); + $body = $request->getResponseBody(); + $err_msg = ''; + phpCAS::traceEnd(true); + return true; + } else { + $headers = ''; + $body = ''; + $err_msg = $request->getErrorMessage(); + phpCAS::traceEnd(false); + return false; + } + } + + /** + * This method is used to build the SAML POST body sent to /samlValidate URL. + * + * @return string the SOAP-encased SAMLP artifact (the ticket). + */ + private function _buildSAMLPayload() + { + phpCAS::traceBegin(); + + //get the ticket + $sa = urlencode($this->getTicket()); + + $body = SAML_SOAP_ENV.SAML_SOAP_BODY.SAMLP_REQUEST + .SAML_ASSERTION_ARTIFACT.$sa.SAML_ASSERTION_ARTIFACT_CLOSE + .SAMLP_REQUEST_CLOSE.SAML_SOAP_BODY_CLOSE.SAML_SOAP_ENV_CLOSE; + + phpCAS::traceEnd($body); + return ($body); + } + + /** @} **/ + + // ######################################################################## + // ACCESS TO EXTERNAL SERVICES + // ######################################################################## + + /** + * @addtogroup internalProxyServices + * @{ + */ + + + /** + * Answer a proxy-authenticated service handler. + * + * @param string $type The service type. One of: + * PHPCAS_PROXIED_SERVICE_HTTP_GET, PHPCAS_PROXIED_SERVICE_HTTP_POST, + * PHPCAS_PROXIED_SERVICE_IMAP + * + * @return CAS_ProxiedService + * @throws InvalidArgumentException If the service type is unknown. + */ + public function getProxiedService ($type) + { + // Sequence validation + $this->ensureIsProxy(); + $this->ensureAuthenticationCallSuccessful(); + + // Argument validation + if (gettype($type) != 'string') + throw new CAS_TypeMismatchException($type, '$type', 'string'); + + switch ($type) { + case PHPCAS_PROXIED_SERVICE_HTTP_GET: + case PHPCAS_PROXIED_SERVICE_HTTP_POST: + $requestClass = $this->_requestImplementation; + $request = new $requestClass(); + if (count($this->_curl_options)) { + $request->setCurlOptions($this->_curl_options); + } + $proxiedService = new $type($request, $this->_serviceCookieJar); + if ($proxiedService instanceof CAS_ProxiedService_Testable) { + $proxiedService->setCasClient($this); + } + return $proxiedService; + case PHPCAS_PROXIED_SERVICE_IMAP; + $proxiedService = new CAS_ProxiedService_Imap($this->_getUser()); + if ($proxiedService instanceof CAS_ProxiedService_Testable) { + $proxiedService->setCasClient($this); + } + return $proxiedService; + default: + throw new CAS_InvalidArgumentException( + "Unknown proxied-service type, $type." + ); + } + } + + /** + * Initialize a proxied-service handler with the proxy-ticket it should use. + * + * @param CAS_ProxiedService $proxiedService service handler + * + * @return void + * + * @throws CAS_ProxyTicketException If there is a proxy-ticket failure. + * The code of the Exception will be one of: + * PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE + * PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE + * PHPCAS_SERVICE_PT_FAILURE + * @throws CAS_ProxiedService_Exception If there is a failure getting the + * url from the proxied service. + */ + public function initializeProxiedService (CAS_ProxiedService $proxiedService) + { + // Sequence validation + $this->ensureIsProxy(); + $this->ensureAuthenticationCallSuccessful(); + + $url = $proxiedService->getServiceUrl(); + if (!is_string($url)) { + throw new CAS_ProxiedService_Exception( + "Proxied Service ".get_class($proxiedService) + ."->getServiceUrl() should have returned a string, returned a " + .gettype($url)." instead." + ); + } + $pt = $this->retrievePT($url, $err_code, $err_msg); + if (!$pt) { + throw new CAS_ProxyTicketException($err_msg, $err_code); + } + $proxiedService->setProxyTicket($pt); + } + + /** + * This method is used to access an HTTP[S] service. + * + * @param string $url the service to access. + * @param int &$err_code an error code Possible values are + * PHPCAS_SERVICE_OK (on success), PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE, + * PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE, PHPCAS_SERVICE_PT_FAILURE, + * PHPCAS_SERVICE_NOT_AVAILABLE. + * @param string &$output the output of the service (also used to give an error + * message on failure). + * + * @return bool true on success, false otherwise (in this later case, $err_code + * gives the reason why it failed and $output contains an error message). + */ + public function serviceWeb($url,&$err_code,&$output) + { + // Sequence validation + $this->ensureIsProxy(); + $this->ensureAuthenticationCallSuccessful(); + + // Argument validation + if (gettype($url) != 'string') + throw new CAS_TypeMismatchException($url, '$url', 'string'); + + try { + $service = $this->getProxiedService(PHPCAS_PROXIED_SERVICE_HTTP_GET); + $service->setUrl($url); + $service->send(); + $output = $service->getResponseBody(); + $err_code = PHPCAS_SERVICE_OK; + return true; + } catch (CAS_ProxyTicketException $e) { + $err_code = $e->getCode(); + $output = $e->getMessage(); + return false; + } catch (CAS_ProxiedService_Exception $e) { + $lang = $this->getLangObj(); + $output = sprintf( + $lang->getServiceUnavailable(), $url, $e->getMessage() + ); + $err_code = PHPCAS_SERVICE_NOT_AVAILABLE; + return false; + } + } + + /** + * This method is used to access an IMAP/POP3/NNTP service. + * + * @param string $url a string giving the URL of the service, including + * the mailing box for IMAP URLs, as accepted by imap_open(). + * @param string $serviceUrl a string giving for CAS retrieve Proxy ticket + * @param string $flags options given to imap_open(). + * @param int &$err_code an error code Possible values are + * PHPCAS_SERVICE_OK (on success), PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE, + * PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE, PHPCAS_SERVICE_PT_FAILURE, + * PHPCAS_SERVICE_NOT_AVAILABLE. + * @param string &$err_msg an error message on failure + * @param string &$pt the Proxy Ticket (PT) retrieved from the CAS + * server to access the URL on success, false on error). + * + * @return object|false an IMAP stream on success, false otherwise (in this later + * case, $err_code gives the reason why it failed and $err_msg contains an + * error message). + */ + public function serviceMail($url,$serviceUrl,$flags,&$err_code,&$err_msg,&$pt) + { + // Sequence validation + $this->ensureIsProxy(); + $this->ensureAuthenticationCallSuccessful(); + + // Argument validation + if (gettype($url) != 'string') + throw new CAS_TypeMismatchException($url, '$url', 'string'); + if (gettype($serviceUrl) != 'string') + throw new CAS_TypeMismatchException($serviceUrl, '$serviceUrl', 'string'); + if (gettype($flags) != 'integer') + throw new CAS_TypeMismatchException($flags, '$flags', 'string'); + + try { + $service = $this->getProxiedService(PHPCAS_PROXIED_SERVICE_IMAP); + $service->setServiceUrl($serviceUrl); + $service->setMailbox($url); + $service->setOptions($flags); + + $stream = $service->open(); + $err_code = PHPCAS_SERVICE_OK; + $pt = $service->getImapProxyTicket(); + return $stream; + } catch (CAS_ProxyTicketException $e) { + $err_msg = $e->getMessage(); + $err_code = $e->getCode(); + $pt = false; + return false; + } catch (CAS_ProxiedService_Exception $e) { + $lang = $this->getLangObj(); + $err_msg = sprintf( + $lang->getServiceUnavailable(), + $url, + $e->getMessage() + ); + $err_code = PHPCAS_SERVICE_NOT_AVAILABLE; + $pt = false; + return false; + } + } + + /** @} **/ + + // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + // XX XX + // XX PROXIED CLIENT FEATURES (CAS 2.0) XX + // XX XX + // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + + // ######################################################################## + // PT + // ######################################################################## + /** + * @addtogroup internalService + * @{ + */ + + /** + * This array will store a list of proxies in front of this application. This + * property will only be populated if this script is being proxied rather than + * accessed directly. + * + * It is set in CAS_Client::validateCAS20() and can be read by + * CAS_Client::getProxies() + * + * @access private + */ + private $_proxies = array(); + + /** + * Answer an array of proxies that are sitting in front of this application. + * + * This method will only return a non-empty array if we have received and + * validated a Proxy Ticket. + * + * @return array + * @access public + */ + public function getProxies() + { + return $this->_proxies; + } + + /** + * Set the Proxy array, probably from persistant storage. + * + * @param array $proxies An array of proxies + * + * @return void + * @access private + */ + private function _setProxies($proxies) + { + $this->_proxies = $proxies; + if (!empty($proxies)) { + // For proxy-authenticated requests people are not viewing the URL + // directly since the client is another application making a + // web-service call. + // Because of this, stripping the ticket from the URL is unnecessary + // and causes another web-service request to be performed. Additionally, + // if session handling on either the client or the server malfunctions + // then the subsequent request will not complete successfully. + $this->setNoClearTicketsFromUrl(); + } + } + + /** + * A container of patterns to be allowed as proxies in front of the cas client. + * + * @var CAS_ProxyChain_AllowedList + */ + private $_allowed_proxy_chains; + + /** + * Answer the CAS_ProxyChain_AllowedList object for this client. + * + * @return CAS_ProxyChain_AllowedList + */ + public function getAllowedProxyChains () + { + if (empty($this->_allowed_proxy_chains)) { + $this->_allowed_proxy_chains = new CAS_ProxyChain_AllowedList(); + } + return $this->_allowed_proxy_chains; + } + + /** @} */ + // ######################################################################## + // PT VALIDATION + // ######################################################################## + /** + * @addtogroup internalProxied + * @{ + */ + + /** + * This method is used to validate a cas 2.0 ST or PT; halt on failure + * Used for all CAS 2.0 validations + * + * @param string &$validate_url the url of the reponse + * @param string &$text_response the text of the repsones + * @param DOMElement &$tree_response the domxml tree of the respones + * @param bool $renew true to force the authentication with the CAS server + * + * @return bool true when successfull and issue a CAS_AuthenticationException + * and false on an error + * + * @throws CAS_AuthenticationException + */ + public function validateCAS20(&$validate_url,&$text_response,&$tree_response, $renew=false) + { + phpCAS::traceBegin(); + phpCAS::trace($text_response); + // build the URL to validate the ticket + if ($this->getAllowedProxyChains()->isProxyingAllowed()) { + $validate_url = $this->getServerProxyValidateURL().'&ticket=' + .urlencode($this->getTicket()); + } else { + $validate_url = $this->getServerServiceValidateURL().'&ticket=' + .urlencode($this->getTicket()); + } + + if ( $this->isProxy() ) { + // pass the callback url for CAS proxies + $validate_url .= '&pgtUrl='.urlencode($this->_getCallbackURL()); + } + + if ( $renew ) { + // pass the renew + $validate_url .= '&renew=true'; + } + + // open and read the URL + if ( !$this->_readURL($validate_url, $headers, $text_response, $err_msg) ) { + phpCAS::trace( + 'could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')' + ); + throw new CAS_AuthenticationException( + $this, 'Ticket not validated', $validate_url, + true/*$no_response*/ + ); + } + + // create new DOMDocument object + $dom = new DOMDocument(); + // Fix possible whitspace problems + $dom->preserveWhiteSpace = false; + // CAS servers should only return data in utf-8 + $dom->encoding = "utf-8"; + // read the response of the CAS server into a DOMDocument object + if ( !($dom->loadXML($text_response))) { + // read failed + throw new CAS_AuthenticationException( + $this, 'Ticket not validated', $validate_url, + false/*$no_response*/, true/*$bad_response*/, $text_response + ); + } else if ( !($tree_response = $dom->documentElement) ) { + // read the root node of the XML tree + // read failed + throw new CAS_AuthenticationException( + $this, 'Ticket not validated', $validate_url, + false/*$no_response*/, true/*$bad_response*/, $text_response + ); + } else if ($tree_response->localName != 'serviceResponse') { + // insure that tag name is 'serviceResponse' + // bad root node + throw new CAS_AuthenticationException( + $this, 'Ticket not validated', $validate_url, + false/*$no_response*/, true/*$bad_response*/, $text_response + ); + } else if ( $tree_response->getElementsByTagName("authenticationFailure")->length != 0) { + // authentication failed, extract the error code and message and throw exception + $auth_fail_list = $tree_response + ->getElementsByTagName("authenticationFailure"); + throw new CAS_AuthenticationException( + $this, 'Ticket not validated', $validate_url, + false/*$no_response*/, false/*$bad_response*/, + $text_response, + $auth_fail_list->item(0)->getAttribute('code')/*$err_code*/, + trim($auth_fail_list->item(0)->nodeValue)/*$err_msg*/ + ); + } else if ($tree_response->getElementsByTagName("authenticationSuccess")->length != 0) { + // authentication succeded, extract the user name + $success_elements = $tree_response + ->getElementsByTagName("authenticationSuccess"); + if ( $success_elements->item(0)->getElementsByTagName("user")->length == 0) { + // no user specified => error + throw new CAS_AuthenticationException( + $this, 'Ticket not validated', $validate_url, + false/*$no_response*/, true/*$bad_response*/, $text_response + ); + } else { + $this->_setUser( + trim( + $success_elements->item(0)->getElementsByTagName("user")->item(0)->nodeValue + ) + ); + $this->_readExtraAttributesCas20($success_elements); + // Store the proxies we are sitting behind for authorization checking + $proxyList = array(); + if ( sizeof($arr = $success_elements->item(0)->getElementsByTagName("proxy")) > 0) { + foreach ($arr as $proxyElem) { + phpCAS::trace("Found Proxy: ".$proxyElem->nodeValue); + $proxyList[] = trim($proxyElem->nodeValue); + } + $this->_setProxies($proxyList); + phpCAS::trace("Storing Proxy List"); + } + // Check if the proxies in front of us are allowed + if (!$this->getAllowedProxyChains()->isProxyListAllowed($proxyList)) { + throw new CAS_AuthenticationException( + $this, 'Proxy not allowed', $validate_url, + false/*$no_response*/, true/*$bad_response*/, + $text_response + ); + } else { + $result = true; + } + } + } else { + throw new CAS_AuthenticationException( + $this, 'Ticket not validated', $validate_url, + false/*$no_response*/, true/*$bad_response*/, + $text_response + ); + } + + $this->_renameSession($this->getTicket()); + + // at this step, Ticket has been validated and $this->_user has been set, + + phpCAS::traceEnd($result); + return $result; + } + + + /** + * This method will parse the DOM and pull out the attributes from the XML + * payload and put them into an array, then put the array into the session. + * + * @param DOMNodeList $success_elements payload of the response + * + * @return bool true when successfull, halt otherwise by calling + * CAS_Client::_authError(). + */ + private function _readExtraAttributesCas20($success_elements) + { + phpCAS::traceBegin(); + + $extra_attributes = array(); + + // "Jasig Style" Attributes: + // + // + // + // jsmith + // + // RubyCAS + // Smith + // John + // CN=Staff,OU=Groups,DC=example,DC=edu + // CN=Spanish Department,OU=Departments,OU=Groups,DC=example,DC=edu + // + // PGTIOU-84678-8a9d2sfa23casd + // + // + // + if ($this->_casAttributeParserCallbackFunction !== null + && is_callable($this->_casAttributeParserCallbackFunction) + ) { + array_unshift($this->_casAttributeParserCallbackArgs, $success_elements->item(0)); + phpCAS :: trace("Calling attritubeParser callback"); + $extra_attributes = call_user_func_array( + $this->_casAttributeParserCallbackFunction, + $this->_casAttributeParserCallbackArgs + ); + } elseif ( $success_elements->item(0)->getElementsByTagName("attributes")->length != 0) { + $attr_nodes = $success_elements->item(0) + ->getElementsByTagName("attributes"); + phpCAS :: trace("Found nested jasig style attributes"); + if ($attr_nodes->item(0)->hasChildNodes()) { + // Nested Attributes + foreach ($attr_nodes->item(0)->childNodes as $attr_child) { + phpCAS :: trace( + "Attribute [".$attr_child->localName."] = " + .$attr_child->nodeValue + ); + $this->_addAttributeToArray( + $extra_attributes, $attr_child->localName, + $attr_child->nodeValue + ); + } + } + } else { + // "RubyCAS Style" attributes + // + // + // + // jsmith + // + // RubyCAS + // Smith + // John + // CN=Staff,OU=Groups,DC=example,DC=edu + // CN=Spanish Department,OU=Departments,OU=Groups,DC=example,DC=edu + // + // PGTIOU-84678-8a9d2sfa23casd + // + // + // + phpCAS :: trace("Testing for rubycas style attributes"); + $childnodes = $success_elements->item(0)->childNodes; + foreach ($childnodes as $attr_node) { + switch ($attr_node->localName) { + case 'user': + case 'proxies': + case 'proxyGrantingTicket': + break; + default: + if (strlen(trim($attr_node->nodeValue))) { + phpCAS :: trace( + "Attribute [".$attr_node->localName."] = ".$attr_node->nodeValue + ); + $this->_addAttributeToArray( + $extra_attributes, $attr_node->localName, + $attr_node->nodeValue + ); + } + } + } + } + + // "Name-Value" attributes. + // + // Attribute format from these mailing list thread: + // http://jasig.275507.n4.nabble.com/CAS-attributes-and-how-they-appear-in-the-CAS-response-td264272.html + // Note: This is a less widely used format, but in use by at least two institutions. + // + // + // + // jsmith + // + // + // + // + // + // + // + // PGTIOU-84678-8a9d2sfa23casd + // + // + // + if (!count($extra_attributes) + && $success_elements->item(0)->getElementsByTagName("attribute")->length != 0 + ) { + $attr_nodes = $success_elements->item(0) + ->getElementsByTagName("attribute"); + $firstAttr = $attr_nodes->item(0); + if (!$firstAttr->hasChildNodes() + && $firstAttr->hasAttribute('name') + && $firstAttr->hasAttribute('value') + ) { + phpCAS :: trace("Found Name-Value style attributes"); + // Nested Attributes + foreach ($attr_nodes as $attr_node) { + if ($attr_node->hasAttribute('name') + && $attr_node->hasAttribute('value') + ) { + phpCAS :: trace( + "Attribute [".$attr_node->getAttribute('name') + ."] = ".$attr_node->getAttribute('value') + ); + $this->_addAttributeToArray( + $extra_attributes, $attr_node->getAttribute('name'), + $attr_node->getAttribute('value') + ); + } + } + } + } + + $this->setAttributes($extra_attributes); + phpCAS::traceEnd(); + return true; + } + + /** + * Add an attribute value to an array of attributes. + * + * @param array &$attributeArray reference to array + * @param string $name name of attribute + * @param string $value value of attribute + * + * @return void + */ + private function _addAttributeToArray(array &$attributeArray, $name, $value) + { + // If multiple attributes exist, add as an array value + if (isset($attributeArray[$name])) { + // Initialize the array with the existing value + if (!is_array($attributeArray[$name])) { + $existingValue = $attributeArray[$name]; + $attributeArray[$name] = array($existingValue); + } + + $attributeArray[$name][] = trim($value); + } else { + $attributeArray[$name] = trim($value); + } + } + + /** @} */ + + // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + // XX XX + // XX MISC XX + // XX XX + // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + + /** + * @addtogroup internalMisc + * @{ + */ + + // ######################################################################## + // URL + // ######################################################################## + /** + * the URL of the current request (without any ticket CGI parameter). Written + * and read by CAS_Client::getURL(). + * + * @hideinitializer + */ + private $_url = ''; + + + /** + * This method sets the URL of the current request + * + * @param string $url url to set for service + * + * @return void + */ + public function setURL($url) + { + // Argument Validation + if (gettype($url) != 'string') + throw new CAS_TypeMismatchException($url, '$url', 'string'); + + $this->_url = $url; + } + + /** + * This method returns the URL of the current request (without any ticket + * CGI parameter). + * + * @return string The URL + */ + public function getURL() + { + phpCAS::traceBegin(); + // the URL is built when needed only + if ( empty($this->_url) ) { + // remove the ticket if present in the URL + $final_uri = ($this->_isHttps()) ? 'https' : 'http'; + $final_uri .= '://'; + + $final_uri .= $this->_getClientUrl(); + $request_uri = explode('?', $_SERVER['REQUEST_URI'], 2); + $final_uri .= $request_uri[0]; + + if (isset($request_uri[1]) && $request_uri[1]) { + $query_string= $this->_removeParameterFromQueryString('ticket', $request_uri[1]); + + // If the query string still has anything left, + // append it to the final URI + if ($query_string !== '') { + $final_uri .= "?$query_string"; + } + } + + phpCAS::trace("Final URI: $final_uri"); + $this->setURL($final_uri); + } + phpCAS::traceEnd($this->_url); + return $this->_url; + } + + /** + * This method sets the base URL of the CAS server. + * + * @param string $url the base URL + * + * @return string base url + */ + public function setBaseURL($url) + { + // Argument Validation + if (gettype($url) != 'string') + throw new CAS_TypeMismatchException($url, '$url', 'string'); + + return $this->_server['base_url'] = $url; + } + + + /** + * Try to figure out the phpCAS client URL with possible Proxys / Ports etc. + * + * @return string Server URL with domain:port + */ + private function _getClientUrl() + { + if (!empty($_SERVER['HTTP_X_FORWARDED_HOST'])) { + // explode the host list separated by comma and use the first host + $hosts = explode(',', $_SERVER['HTTP_X_FORWARDED_HOST']); + // see rfc7239#5.3 and rfc7230#2.7.1: port is in HTTP_X_FORWARDED_HOST if non default + return $hosts[0]; + } else if (!empty($_SERVER['HTTP_X_FORWARDED_SERVER'])) { + $server_url = $_SERVER['HTTP_X_FORWARDED_SERVER']; + } else { + if (empty($_SERVER['SERVER_NAME'])) { + $server_url = $_SERVER['HTTP_HOST']; + } else { + $server_url = $_SERVER['SERVER_NAME']; + } + } + if (!strpos($server_url, ':')) { + if (empty($_SERVER['HTTP_X_FORWARDED_PORT'])) { + $server_port = $_SERVER['SERVER_PORT']; + } else { + $ports = explode(',', $_SERVER['HTTP_X_FORWARDED_PORT']); + $server_port = $ports[0]; + } + + if ( ($this->_isHttps() && $server_port!=443) + || (!$this->_isHttps() && $server_port!=80) + ) { + $server_url .= ':'; + $server_url .= $server_port; + } + } + return $server_url; + } + + /** + * This method checks to see if the request is secured via HTTPS + * + * @return bool true if https, false otherwise + */ + private function _isHttps() + { + if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO'])) { + return ($_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https'); + } elseif (!empty($_SERVER['HTTP_X_FORWARDED_PROTOCOL'])) { + return ($_SERVER['HTTP_X_FORWARDED_PROTOCOL'] === 'https'); + } elseif ( isset($_SERVER['HTTPS']) + && !empty($_SERVER['HTTPS']) + && strcasecmp($_SERVER['HTTPS'], 'off') !== 0 + ) { + return true; + } + return false; + + } + + /** + * Removes a parameter from a query string + * + * @param string $parameterName name of parameter + * @param string $queryString query string + * + * @return string new query string + * + * @link http://stackoverflow.com/questions/1842681/regular-expression-to-remove-one-parameter-from-query-string + */ + private function _removeParameterFromQueryString($parameterName, $queryString) + { + $parameterName = preg_quote($parameterName); + return preg_replace( + "/&$parameterName(=[^&]*)?|^$parameterName(=[^&]*)?&?/", + '', $queryString + ); + } + + /** + * This method is used to append query parameters to an url. Since the url + * might already contain parameter it has to be detected and to build a proper + * URL + * + * @param string $url base url to add the query params to + * @param string $query params in query form with & separated + * + * @return string url with query params + */ + private function _buildQueryUrl($url, $query) + { + $url .= (strstr($url, '?') === false) ? '?' : '&'; + $url .= $query; + return $url; + } + + /** + * Renaming the session + * + * @param string $ticket name of the ticket + * + * @return void + */ + private function _renameSession($ticket) + { + phpCAS::traceBegin(); + if ($this->getChangeSessionID()) { + if (!empty($this->_user)) { + $old_session = $_SESSION; + phpCAS :: trace("Killing session: ". session_id()); + session_destroy(); + // set up a new session, of name based on the ticket + $session_id = $this->_sessionIdForTicket($ticket); + phpCAS :: trace("Starting session: ". $session_id); + session_id($session_id); + session_start(); + phpCAS :: trace("Restoring old session vars"); + $_SESSION = $old_session; + } else { + phpCAS :: trace ( + 'Session should only be renamed after successfull authentication' + ); + } + } else { + phpCAS :: trace( + "Skipping session rename since phpCAS is not handling the session." + ); + } + phpCAS::traceEnd(); + } + + /** + * Answer a valid session-id given a CAS ticket. + * + * The output must be deterministic to allow single-log-out when presented with + * the ticket to log-out. + * + * + * @param string $ticket name of the ticket + * + * @return string + */ + private function _sessionIdForTicket($ticket) + { + // Hash the ticket to ensure that the value meets the PHP 7.1 requirement + // that session-ids have a length between 22 and 256 characters. + return hash('sha256', $this->_sessionIdSalt . $ticket); + } + + /** + * Set a salt/seed for the session-id hash to make it harder to guess. + * + * @var string $_sessionIdSalt + */ + private $_sessionIdSalt = ''; + + /** + * Set a salt/seed for the session-id hash to make it harder to guess. + * + * @param string $salt + * + * @return void + */ + public function setSessionIdSalt($salt) { + $this->_sessionIdSalt = (string)$salt; + } + + // ######################################################################## + // AUTHENTICATION ERROR HANDLING + // ######################################################################## + /** + * This method is used to print the HTML output when the user was not + * authenticated. + * + * @param string $failure the failure that occured + * @param string $cas_url the URL the CAS server was asked for + * @param bool $no_response the response from the CAS server (other + * parameters are ignored if true) + * @param bool $bad_response bad response from the CAS server ($err_code + * and $err_msg ignored if true) + * @param string $cas_response the response of the CAS server + * @param int $err_code the error code given by the CAS server + * @param string $err_msg the error message given by the CAS server + * + * @return void + */ + private function _authError( + $failure, + $cas_url, + $no_response=false, + $bad_response=false, + $cas_response='', + $err_code=-1, + $err_msg='' + ) { + phpCAS::traceBegin(); + $lang = $this->getLangObj(); + $this->printHTMLHeader($lang->getAuthenticationFailed()); + printf( + $lang->getYouWereNotAuthenticated(), htmlentities($this->getURL()), + isset($_SERVER['SERVER_ADMIN']) ? $_SERVER['SERVER_ADMIN']:'' + ); + phpCAS::trace('CAS URL: '.$cas_url); + phpCAS::trace('Authentication failure: '.$failure); + if ( $no_response ) { + phpCAS::trace('Reason: no response from the CAS server'); + } else { + if ( $bad_response ) { + phpCAS::trace('Reason: bad response from the CAS server'); + } else { + switch ($this->getServerVersion()) { + case CAS_VERSION_1_0: + phpCAS::trace('Reason: CAS error'); + break; + case CAS_VERSION_2_0: + case CAS_VERSION_3_0: + if ( $err_code === -1 ) { + phpCAS::trace('Reason: no CAS error'); + } else { + phpCAS::trace( + 'Reason: ['.$err_code.'] CAS error: '.$err_msg + ); + } + break; + } + } + phpCAS::trace('CAS response: '.$cas_response); + } + $this->printHTMLFooter(); + phpCAS::traceExit(); + throw new CAS_GracefullTerminationException(); + } + + // ######################################################################## + // PGTIOU/PGTID and logoutRequest rebroadcasting + // ######################################################################## + + /** + * Boolean of whether to rebroadcast pgtIou/pgtId and logoutRequest, and + * array of the nodes. + */ + private $_rebroadcast = false; + private $_rebroadcast_nodes = array(); + + /** + * Constants used for determining rebroadcast node type. + */ + const HOSTNAME = 0; + const IP = 1; + + /** + * Determine the node type from the URL. + * + * @param String $nodeURL The node URL. + * + * @return int hostname + * + */ + private function _getNodeType($nodeURL) + { + phpCAS::traceBegin(); + if (preg_match("/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/", $nodeURL)) { + phpCAS::traceEnd(self::IP); + return self::IP; + } else { + phpCAS::traceEnd(self::HOSTNAME); + return self::HOSTNAME; + } + } + + /** + * Store the rebroadcast node for pgtIou/pgtId and logout requests. + * + * @param string $rebroadcastNodeUrl The rebroadcast node URL. + * + * @return void + */ + public function addRebroadcastNode($rebroadcastNodeUrl) + { + // Argument validation + if ( !(bool)preg_match("/^(http|https):\/\/([A-Z0-9][A-Z0-9_-]*(?:\.[A-Z0-9][A-Z0-9_-]*)+):?(\d+)?\/?/i", $rebroadcastNodeUrl)) + throw new CAS_TypeMismatchException($rebroadcastNodeUrl, '$rebroadcastNodeUrl', 'url'); + + // Store the rebroadcast node and set flag + $this->_rebroadcast = true; + $this->_rebroadcast_nodes[] = $rebroadcastNodeUrl; + } + + /** + * An array to store extra rebroadcast curl options. + */ + private $_rebroadcast_headers = array(); + + /** + * This method is used to add header parameters when rebroadcasting + * pgtIou/pgtId or logoutRequest. + * + * @param string $header Header to send when rebroadcasting. + * + * @return void + */ + public function addRebroadcastHeader($header) + { + if (gettype($header) != 'string') + throw new CAS_TypeMismatchException($header, '$header', 'string'); + + $this->_rebroadcast_headers[] = $header; + } + + /** + * Constants used for determining rebroadcast type (logout or pgtIou/pgtId). + */ + const LOGOUT = 0; + const PGTIOU = 1; + + /** + * This method rebroadcasts logout/pgtIou requests. Can be LOGOUT,PGTIOU + * + * @param int $type type of rebroadcasting. + * + * @return void + */ + private function _rebroadcast($type) + { + phpCAS::traceBegin(); + + $rebroadcast_curl_options = array( + CURLOPT_FAILONERROR => 1, + CURLOPT_FOLLOWLOCATION => 1, + CURLOPT_RETURNTRANSFER => 1, + CURLOPT_CONNECTTIMEOUT => 1, + CURLOPT_TIMEOUT => 4); + + // Try to determine the IP address of the server + if (!empty($_SERVER['SERVER_ADDR'])) { + $ip = $_SERVER['SERVER_ADDR']; + } else if (!empty($_SERVER['LOCAL_ADDR'])) { + // IIS 7 + $ip = $_SERVER['LOCAL_ADDR']; + } + // Try to determine the DNS name of the server + if (!empty($ip)) { + $dns = gethostbyaddr($ip); + } + $multiClassName = 'CAS_Request_CurlMultiRequest'; + $multiRequest = new $multiClassName(); + + for ($i = 0; $i < sizeof($this->_rebroadcast_nodes); $i++) { + if ((($this->_getNodeType($this->_rebroadcast_nodes[$i]) == self::HOSTNAME) && !empty($dns) && (stripos($this->_rebroadcast_nodes[$i], $dns) === false)) + || (($this->_getNodeType($this->_rebroadcast_nodes[$i]) == self::IP) && !empty($ip) && (stripos($this->_rebroadcast_nodes[$i], $ip) === false)) + ) { + phpCAS::trace( + 'Rebroadcast target URL: '.$this->_rebroadcast_nodes[$i] + .$_SERVER['REQUEST_URI'] + ); + $className = $this->_requestImplementation; + $request = new $className(); + + $url = $this->_rebroadcast_nodes[$i].$_SERVER['REQUEST_URI']; + $request->setUrl($url); + + if (count($this->_rebroadcast_headers)) { + $request->addHeaders($this->_rebroadcast_headers); + } + + $request->makePost(); + if ($type == self::LOGOUT) { + // Logout request + $request->setPostBody( + 'rebroadcast=false&logoutRequest='.$_POST['logoutRequest'] + ); + } else if ($type == self::PGTIOU) { + // pgtIou/pgtId rebroadcast + $request->setPostBody('rebroadcast=false'); + } + + $request->setCurlOptions($rebroadcast_curl_options); + + $multiRequest->addRequest($request); + } else { + phpCAS::trace( + 'Rebroadcast not sent to self: ' + .$this->_rebroadcast_nodes[$i].' == '.(!empty($ip)?$ip:'') + .'/'.(!empty($dns)?$dns:'') + ); + } + } + // We need at least 1 request + if ($multiRequest->getNumRequests() > 0) { + $multiRequest->send(); + } + phpCAS::traceEnd(); + } + + /** @} */ +} diff --git a/vendor/apereo/phpcas/source/CAS/CookieJar.php b/vendor/apereo/phpcas/source/CAS/CookieJar.php new file mode 100644 index 0000000000..38f849dfe8 --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/CookieJar.php @@ -0,0 +1,384 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +/** + * This class provides access to service cookies and handles parsing of response + * headers to pull out cookie values. + * + * @class CAS_CookieJar + * @category Authentication + * @package PhpCAS + * @author Adam Franco + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ +class CAS_CookieJar +{ + + private $_cookies; + + /** + * Create a new cookie jar by passing it a reference to an array in which it + * should store cookies. + * + * @param array &$storageArray Array to store cookies + * + * @return void + */ + public function __construct (array &$storageArray) + { + $this->_cookies =& $storageArray; + } + + /** + * Store cookies for a web service request. + * Cookie storage is based on RFC 2965: http://www.ietf.org/rfc/rfc2965.txt + * + * @param string $request_url The URL that generated the response headers. + * @param array $response_headers An array of the HTTP response header strings. + * + * @return void + * + * @access private + */ + public function storeCookies ($request_url, $response_headers) + { + $urlParts = parse_url($request_url); + $defaultDomain = $urlParts['host']; + + $cookies = $this->parseCookieHeaders($response_headers, $defaultDomain); + + foreach ($cookies as $cookie) { + // Enforce the same-origin policy by verifying that the cookie + // would match the url that is setting it + if (!$this->cookieMatchesTarget($cookie, $urlParts)) { + continue; + } + + // store the cookie + $this->storeCookie($cookie); + + phpCAS::trace($cookie['name'].' -> '.$cookie['value']); + } + } + + /** + * Retrieve cookies applicable for a web service request. + * Cookie applicability is based on RFC 2965: http://www.ietf.org/rfc/rfc2965.txt + * + * @param string $request_url The url that the cookies will be for. + * + * @return array An array containing cookies. E.g. array('name' => 'val'); + * + * @access private + */ + public function getCookies ($request_url) + { + if (!count($this->_cookies)) { + return array(); + } + + // If our request URL can't be parsed, no cookies apply. + $target = parse_url($request_url); + if ($target === false) { + return array(); + } + + $this->expireCookies(); + + $matching_cookies = array(); + foreach ($this->_cookies as $key => $cookie) { + if ($this->cookieMatchesTarget($cookie, $target)) { + $matching_cookies[$cookie['name']] = $cookie['value']; + } + } + return $matching_cookies; + } + + + /** + * Parse Cookies without PECL + * From the comments in http://php.net/manual/en/function.http-parse-cookie.php + * + * @param array $header array of header lines. + * @param string $defaultDomain The domain to use if none is specified in + * the cookie. + * + * @return array of cookies + */ + protected function parseCookieHeaders( $header, $defaultDomain ) + { + phpCAS::traceBegin(); + $cookies = array(); + foreach ( $header as $line ) { + if ( preg_match('/^Set-Cookie2?: /i', $line)) { + $cookies[] = $this->parseCookieHeader($line, $defaultDomain); + } + } + + phpCAS::traceEnd($cookies); + return $cookies; + } + + /** + * Parse a single cookie header line. + * + * Based on RFC2965 http://www.ietf.org/rfc/rfc2965.txt + * + * @param string $line The header line. + * @param string $defaultDomain The domain to use if none is specified in + * the cookie. + * + * @return array + */ + protected function parseCookieHeader ($line, $defaultDomain) + { + if (!$defaultDomain) { + throw new CAS_InvalidArgumentException( + '$defaultDomain was not provided.' + ); + } + + // Set our default values + $cookie = array( + 'domain' => $defaultDomain, + 'path' => '/', + 'secure' => false, + ); + + $line = preg_replace('/^Set-Cookie2?: /i', '', trim($line)); + + // trim any trailing semicolons. + $line = trim($line, ';'); + + phpCAS::trace("Cookie Line: $line"); + + // This implementation makes the assumption that semicolons will not + // be present in quoted attribute values. While attribute values that + // contain semicolons are allowed by RFC2965, they are hopefully rare + // enough to ignore for our purposes. Most browsers make the same + // assumption. + $attributeStrings = explode(';', $line); + + foreach ( $attributeStrings as $attributeString ) { + // split on the first equals sign and use the rest as value + $attributeParts = explode('=', $attributeString, 2); + + $attributeName = trim($attributeParts[0]); + $attributeNameLC = strtolower($attributeName); + + if (isset($attributeParts[1])) { + $attributeValue = trim($attributeParts[1]); + // Values may be quoted strings. + if (strpos($attributeValue, '"') === 0) { + $attributeValue = trim($attributeValue, '"'); + // unescape any escaped quotes: + $attributeValue = str_replace('\"', '"', $attributeValue); + } + } else { + $attributeValue = null; + } + + switch ($attributeNameLC) { + case 'expires': + $cookie['expires'] = strtotime($attributeValue); + break; + case 'max-age': + $cookie['max-age'] = (int)$attributeValue; + // Set an expiry time based on the max-age + if ($cookie['max-age']) { + $cookie['expires'] = time() + $cookie['max-age']; + } else { + // If max-age is zero, then the cookie should be removed + // imediately so set an expiry before now. + $cookie['expires'] = time() - 1; + } + break; + case 'secure': + $cookie['secure'] = true; + break; + case 'domain': + case 'path': + case 'port': + case 'version': + case 'comment': + case 'commenturl': + case 'discard': + case 'httponly': + $cookie[$attributeNameLC] = $attributeValue; + break; + default: + $cookie['name'] = $attributeName; + $cookie['value'] = $attributeValue; + } + } + + return $cookie; + } + + /** + * Add, update, or remove a cookie. + * + * @param array $cookie A cookie array as created by parseCookieHeaders() + * + * @return void + * + * @access protected + */ + protected function storeCookie ($cookie) + { + // Discard any old versions of this cookie. + $this->discardCookie($cookie); + $this->_cookies[] = $cookie; + + } + + /** + * Discard an existing cookie + * + * @param array $cookie An cookie + * + * @return void + * + * @access protected + */ + protected function discardCookie ($cookie) + { + if (!isset($cookie['domain']) + || !isset($cookie['path']) + || !isset($cookie['path']) + ) { + throw new CAS_InvalidArgumentException('Invalid Cookie array passed.'); + } + + foreach ($this->_cookies as $key => $old_cookie) { + if ( $cookie['domain'] == $old_cookie['domain'] + && $cookie['path'] == $old_cookie['path'] + && $cookie['name'] == $old_cookie['name'] + ) { + unset($this->_cookies[$key]); + } + } + } + + /** + * Go through our stored cookies and remove any that are expired. + * + * @return void + * + * @access protected + */ + protected function expireCookies () + { + foreach ($this->_cookies as $key => $cookie) { + if (isset($cookie['expires']) && $cookie['expires'] < time()) { + unset($this->_cookies[$key]); + } + } + } + + /** + * Answer true if cookie is applicable to a target. + * + * @param array $cookie An array of cookie attributes. + * @param array|false $target An array of URL attributes as generated by parse_url(). + * + * @return bool + * + * @access private + */ + protected function cookieMatchesTarget ($cookie, $target) + { + if (!is_array($target)) { + throw new CAS_InvalidArgumentException( + '$target must be an array of URL attributes as generated by parse_url().' + ); + } + if (!isset($target['host'])) { + throw new CAS_InvalidArgumentException( + '$target must be an array of URL attributes as generated by parse_url().' + ); + } + + // Verify that the scheme matches + if ($cookie['secure'] && $target['scheme'] != 'https') { + return false; + } + + // Verify that the host matches + // Match domain and mulit-host cookies + if (strpos($cookie['domain'], '.') === 0) { + // .host.domain.edu cookies are valid for host.domain.edu + if (substr($cookie['domain'], 1) == $target['host']) { + // continue with other checks + } else { + // non-exact host-name matches. + // check that the target host a.b.c.edu is within .b.c.edu + $pos = strripos($target['host'], $cookie['domain']); + if (!$pos) { + return false; + } + // verify that the cookie domain is the last part of the host. + if ($pos + strlen($cookie['domain']) != strlen($target['host'])) { + return false; + } + // verify that the host name does not contain interior dots as per + // RFC 2965 section 3.3.2 Rejecting Cookies + // http://www.ietf.org/rfc/rfc2965.txt + $hostname = substr($target['host'], 0, $pos); + if (strpos($hostname, '.') !== false) { + return false; + } + } + } else { + // If the cookie host doesn't begin with '.', + // the host must case-insensitive match exactly + if (strcasecmp($target['host'], $cookie['domain']) !== 0) { + return false; + } + } + + // Verify that the port matches + if (isset($cookie['ports']) + && !in_array($target['port'], $cookie['ports']) + ) { + return false; + } + + // Verify that the path matches + if (strpos($target['path'], $cookie['path']) !== 0) { + return false; + } + + return true; + } + +} + +?> diff --git a/vendor/apereo/phpcas/source/CAS/Exception.php b/vendor/apereo/phpcas/source/CAS/Exception.php new file mode 100644 index 0000000000..d956d19759 --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/Exception.php @@ -0,0 +1,59 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +/** + * A root exception interface for all exceptions in phpCAS. + * + * All exceptions thrown in phpCAS should implement this interface to allow them + * to be caught as a category by clients. Each phpCAS exception should extend + * an appropriate SPL exception class that best fits its type. + * + * For example, an InvalidArgumentException in phpCAS should be defined as + * + * class CAS_InvalidArgumentException + * extends InvalidArgumentException + * implements CAS_Exception + * { } + * + * This definition allows the CAS_InvalidArgumentException to be caught as either + * an InvalidArgumentException or as a CAS_Exception. + * + * @class CAS_Exception + * @category Authentication + * @package PhpCAS + * @author Adam Franco + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + * + */ +interface CAS_Exception +{ + +} +?> \ No newline at end of file diff --git a/vendor/apereo/phpcas/source/CAS/GracefullTerminationException.php b/vendor/apereo/phpcas/source/CAS/GracefullTerminationException.php new file mode 100644 index 0000000000..d1d035c39b --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/GracefullTerminationException.php @@ -0,0 +1,86 @@ + + * @author Adam Franco + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +/** + * An exception for terminatinating execution or to throw for unit testing + * + * @class CAS_GracefullTerminationException.php + * @category Authentication + * @package PhpCAS + * @author Joachim Fritschi + * @author Adam Franco + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +class CAS_GracefullTerminationException +extends RuntimeException +implements CAS_Exception +{ + + /** + * Test if exceptions should be thrown or if we should just exit. + * In production usage we want to just exit cleanly when prompting the user + * for a redirect without filling the error logs with uncaught exceptions. + * In unit testing scenarios we cannot exit or we won't be able to continue + * with our tests. + * + * @param string $message Message Text + * @param int $code Error code + * + * @return self + */ + public function __construct ($message = 'Terminate Gracefully', $code = 0) + { + // Exit cleanly to avoid filling up the logs with uncaught exceptions. + if (self::$_exitWhenThrown) { + exit; + } else { + // Throw exceptions to allow unit testing to continue; + parent::__construct($message, $code); + } + } + + private static $_exitWhenThrown = true; + /** + * Force phpcas to thow Exceptions instead of calling exit() + * Needed for unit testing. Generally shouldn't be used in production due to + * an increase in Apache error logging if CAS_GracefulTerminiationExceptions + * are not caught and handled. + * + * @return void + */ + public static function throwInsteadOfExiting() + { + self::$_exitWhenThrown = false; + } + +} +?> \ No newline at end of file diff --git a/vendor/apereo/phpcas/source/CAS/InvalidArgumentException.php b/vendor/apereo/phpcas/source/CAS/InvalidArgumentException.php new file mode 100644 index 0000000000..ba43d39f8a --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/InvalidArgumentException.php @@ -0,0 +1,46 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +/** + * Exception that denotes invalid arguments were passed. + * + * @class CAS_InvalidArgumentException + * @category Authentication + * @package PhpCAS + * @author Adam Franco + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ +class CAS_InvalidArgumentException +extends InvalidArgumentException +implements CAS_Exception +{ + +} +?> \ No newline at end of file diff --git a/vendor/apereo/phpcas/source/CAS/Languages/Catalan.php b/vendor/apereo/phpcas/source/CAS/Languages/Catalan.php new file mode 100644 index 0000000000..a0b64d8eb5 --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/Languages/Catalan.php @@ -0,0 +1,114 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +/** + * Catalan language class + * + * @class CAS_Languages_Catalan + * @category Authentication + * @package PhpCAS + * @author Iván-Benjamín García Torà + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + * + * @sa @link internalLang Internationalization @endlink + * @ingroup internalLang + */ +class CAS_Languages_Catalan implements CAS_Languages_LanguageInterface +{ + /** + * Get the using server string + * + * @return string using server + */ + public function getUsingServer() + { + return 'usant servidor'; + } + + /** + * Get authentication wanted string + * + * @return string authentication wanted + */ + public function getAuthenticationWanted() + { + return 'Autentificació CAS necessària!'; + } + + /** + * Get logout string + * + * @return string logout + */ + public function getLogout() + { + return 'Sortida de CAS necessària!'; + } + + /** + * Get the should have been redirected string + * + * @return string should habe been redirected + */ + public function getShouldHaveBeenRedirected() + { + return 'Ja hauria d\ haver estat redireccionat al servidor CAS. Feu click aquí per a continuar.'; + } + + /** + * Get authentication failed string + * + * @return string authentication failed + */ + public function getAuthenticationFailed() + { + return 'Autentificació CAS fallida!'; + } + + /** + * Get the your were not authenticated string + * + * @return string not authenticated + */ + public function getYouWereNotAuthenticated() + { + return '

No estàs autentificat.

Pots tornar a intentar-ho fent click aquí.

Si el problema persisteix hauría de contactar amb l\'administrador d\'aquest llocc.

'; + } + + /** + * Get the service unavailable string + * + * @return string service unavailable + */ + public function getServiceUnavailable() + { + return 'El servei `%s\' no està disponible (%s).'; + } +} diff --git a/vendor/apereo/phpcas/source/CAS/Languages/ChineseSimplified.php b/vendor/apereo/phpcas/source/CAS/Languages/ChineseSimplified.php new file mode 100644 index 0000000000..bb665937e3 --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/Languages/ChineseSimplified.php @@ -0,0 +1,114 @@ +, Phy25 + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +/** + * Chinese Simplified language class + * + * @class CAS_Languages_ChineseSimplified + * @category Authentication + * @package PhpCAS + * @author Pascal Aubry , Phy25 + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + * + * @sa @link internalLang Internationalization @endlink + * @ingroup internalLang + */ +class CAS_Languages_ChineseSimplified implements CAS_Languages_LanguageInterface +{ + /** + * Get the using server string + * + * @return string using server + */ + public function getUsingServer() + { + return '连接的服务器'; + } + + /** + * Get authentication wanted string + * + * @return string authentication wanted + */ + public function getAuthenticationWanted() + { + return '请进行 CAS 认证!'; + } + + /** + * Get logout string + * + * @return string logout + */ + public function getLogout() + { + return '请进行 CAS 登出!'; + } + + /** + * Get the should have been redirected string + * + * @return string should habe been redirected + */ + public function getShouldHaveBeenRedirected() + { + return '你正被重定向到 CAS 服务器。点击这里继续。'; + } + + /** + * Get authentication failed string + * + * @return string authentication failed + */ + public function getAuthenticationFailed() + { + return 'CAS 认证失败!'; + } + + /** + * Get the your were not authenticated string + * + * @return string not authenticated + */ + public function getYouWereNotAuthenticated() + { + return '

你没有成功登录。

你可以点击这里重新登录。

如果问题依然存在,请联系本站管理员。

'; + } + + /** + * Get the service unavailable string + * + * @return string service unavailable + */ + public function getServiceUnavailable() + { + return '服务器 %s 不可用(%s)。'; + } +} \ No newline at end of file diff --git a/vendor/apereo/phpcas/source/CAS/Languages/English.php b/vendor/apereo/phpcas/source/CAS/Languages/English.php new file mode 100644 index 0000000000..002c1ba49e --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/Languages/English.php @@ -0,0 +1,114 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +/** + * English language class + * + * @class CAS_Languages_English + * @category Authentication + * @package PhpCAS + * @author Pascal Aubry + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + * + * @sa @link internalLang Internationalization @endlink + * @ingroup internalLang + */ +class CAS_Languages_English implements CAS_Languages_LanguageInterface +{ + /** + * Get the using server string + * + * @return string using server + */ + public function getUsingServer() + { + return 'using server'; + } + + /** + * Get authentication wanted string + * + * @return string authentication wanted + */ + public function getAuthenticationWanted() + { + return 'CAS Authentication wanted!'; + } + + /** + * Get logout string + * + * @return string logout + */ + public function getLogout() + { + return 'CAS logout wanted!'; + } + + /** + * Get the should have been redirected string + * + * @return string should habe been redirected + */ + public function getShouldHaveBeenRedirected() + { + return 'You should already have been redirected to the CAS server. Click here to continue.'; + } + + /** + * Get authentication failed string + * + * @return string authentication failed + */ + public function getAuthenticationFailed() + { + return 'CAS Authentication failed!'; + } + + /** + * Get the your were not authenticated string + * + * @return string not authenticated + */ + public function getYouWereNotAuthenticated() + { + return '

You were not authenticated.

You may submit your request again by clicking here.

If the problem persists, you may contact the administrator of this site.

'; + } + + /** + * Get the service unavailable string + * + * @return string service unavailable + */ + public function getServiceUnavailable() + { + return 'The service `%s\' is not available (%s).'; + } +} \ No newline at end of file diff --git a/vendor/apereo/phpcas/source/CAS/Languages/French.php b/vendor/apereo/phpcas/source/CAS/Languages/French.php new file mode 100644 index 0000000000..b99847a7f0 --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/Languages/French.php @@ -0,0 +1,116 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +/** + * French language class + * + * @class CAS_Languages_French + * @category Authentication + * @package PhpCAS + * @author Pascal Aubry + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + * + * @sa @link internalLang Internationalization @endlink + * @ingroup internalLang + */ +class CAS_Languages_French implements CAS_Languages_LanguageInterface +{ + /** + * Get the using server string + * + * @return string using server + */ + public function getUsingServer() + { + return 'utilisant le serveur'; + } + + /** + * Get authentication wanted string + * + * @return string authentication wanted + */ + public function getAuthenticationWanted() + { + return 'Authentication CAS nécessaire !'; + } + + /** + * Get logout string + * + * @return string logout + */ + public function getLogout() + { + return 'Déconnexion demandée !'; + } + + /** + * Get the should have been redirected string + * + * @return string should habe been redirected + */ + public function getShouldHaveBeenRedirected() + { + return 'Vous auriez du etre redirigé(e) vers le serveur CAS. Cliquez ici pour continuer.'; + } + + /** + * Get authentication failed string + * + * @return string authentication failed + */ + public function getAuthenticationFailed() + { + return 'Authentification CAS infructueuse !'; + } + + /** + * Get the your were not authenticated string + * + * @return string not authenticated + */ + public function getYouWereNotAuthenticated() + { + return '

Vous n\'avez pas été authentifié(e).

Vous pouvez soumettre votre requete à nouveau en cliquant ici.

Si le problème persiste, vous pouvez contacter l\'administrateur de ce site.

'; + } + + /** + * Get the service unavailable string + * + * @return string service unavailable + */ + public function getServiceUnavailable() + { + return 'Le service `%s\' est indisponible (%s)'; + } +} + +?> \ No newline at end of file diff --git a/vendor/apereo/phpcas/source/CAS/Languages/German.php b/vendor/apereo/phpcas/source/CAS/Languages/German.php new file mode 100644 index 0000000000..ed3150a80c --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/Languages/German.php @@ -0,0 +1,116 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +/** + * German language class + * + * @class CAS_Languages_German + * @category Authentication + * @package PhpCAS + * @author Henrik Genssen + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + * + * @sa @link internalLang Internationalization @endlink + * @ingroup internalLang + */ +class CAS_Languages_German implements CAS_Languages_LanguageInterface +{ + /** + * Get the using server string + * + * @return string using server + */ + public function getUsingServer() + { + return 'via Server'; + } + + /** + * Get authentication wanted string + * + * @return string authentication wanted + */ + public function getAuthenticationWanted() + { + return 'CAS Authentifizierung erforderlich!'; + } + + /** + * Get logout string + * + * @return string logout + */ + public function getLogout() + { + return 'CAS Abmeldung!'; + } + + /** + * Get the should have been redirected string + * + * @return string should habe been redirected + */ + public function getShouldHaveBeenRedirected() + { + return 'eigentlich häten Sie zum CAS Server weitergeleitet werden sollen. Drücken Sie hier um fortzufahren.'; + } + + /** + * Get authentication failed string + * + * @return string authentication failed + */ + public function getAuthenticationFailed() + { + return 'CAS Anmeldung fehlgeschlagen!'; + } + + /** + * Get the your were not authenticated string + * + * @return string not authenticated + */ + public function getYouWereNotAuthenticated() + { + return '

Sie wurden nicht angemeldet.

Um es erneut zu versuchen klicken Sie hier.

Wenn das Problem bestehen bleibt, kontaktieren Sie den Administrator dieser Seite.

'; + } + + /** + * Get the service unavailable string + * + * @return string service unavailable + */ + public function getServiceUnavailable() + { + return 'Der Dienst `%s\' ist nicht verfügbar (%s).'; + } +} + +?> diff --git a/vendor/apereo/phpcas/source/CAS/Languages/Greek.php b/vendor/apereo/phpcas/source/CAS/Languages/Greek.php new file mode 100644 index 0000000000..888ce24160 --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/Languages/Greek.php @@ -0,0 +1,115 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +/** + * Greek language class + * + * @class CAS_Languages_Greek + * @category Authentication + * @package PhpCAS + * @author Vangelis Haniotakis + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + * + * @sa @link internalLang Internationalization @endlink + * @ingroup internalLang + */ +class CAS_Languages_Greek implements CAS_Languages_LanguageInterface +{ + /** + * Get the using server string + * + * @return string using server + */ + public function getUsingServer() + { + return 'χρησιμοποιείται ο εξυπηρετητής'; + } + + /** + * Get authentication wanted string + * + * @return string authentication wanted + */ + public function getAuthenticationWanted() + { + return 'Απαιτείται η ταυτοποίηση CAS!'; + } + + /** + * Get logout string + * + * @return string logout + */ + public function getLogout() + { + return 'Απαιτείται η αποσύνδεση από CAS!'; + } + + /** + * Get the should have been redirected string + * + * @return string should habe been redirected + */ + public function getShouldHaveBeenRedirected() + { + return 'Θα έπρεπε να είχατε ανακατευθυνθεί στον εξυπηρετητή CAS. Κάντε κλίκ εδώ για να συνεχίσετε.'; + } + + /** + * Get authentication failed string + * + * @return string authentication failed + */ + public function getAuthenticationFailed() + { + return 'Η ταυτοποίηση CAS απέτυχε!'; + } + + /** + * Get the your were not authenticated string + * + * @return string not authenticated + */ + public function getYouWereNotAuthenticated() + { + return '

Δεν ταυτοποιηθήκατε.

Μπορείτε να ξαναπροσπαθήσετε, κάνοντας κλίκ εδώ.

Εαν το πρόβλημα επιμείνει, ελάτε σε επαφή με τον διαχειριστή.

'; + } + + /** + * Get the service unavailable string + * + * @return string service unavailable + */ + public function getServiceUnavailable() + { + return 'Η υπηρεσία `%s\' δεν είναι διαθέσιμη (%s).'; + } +} +?> diff --git a/vendor/apereo/phpcas/source/CAS/Languages/Japanese.php b/vendor/apereo/phpcas/source/CAS/Languages/Japanese.php new file mode 100644 index 0000000000..a15bf17b1f --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/Languages/Japanese.php @@ -0,0 +1,113 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +/** + * Japanese language class. Now Encoding is UTF-8. + * + * @class CAS_Languages_Japanese + * @category Authentication + * @package PhpCAS + * @author fnorif + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + * + **/ +class CAS_Languages_Japanese implements CAS_Languages_LanguageInterface +{ + /** + * Get the using server string + * + * @return string using server + */ + public function getUsingServer() + { + return 'サーバーを使っています。'; + } + + /** + * Get authentication wanted string + * + * @return string authentication wanted + */ + public function getAuthenticationWanted() + { + return 'CASによる認証を行います。'; + } + + /** + * Get logout string + * + * @return string logout + */ + public function getLogout() + { + return 'CASからログアウトします!'; + } + + /** + * Get the should have been redirected string + * + * @return string should habe been redirected + */ + public function getShouldHaveBeenRedirected() + { + return 'CASサーバに行く必要があります。自動的に転送されない場合は こちら をクリックして続行します。'; + } + + /** + * Get authentication failed string + * + * @return string authentication failed + */ + public function getAuthenticationFailed() + { + return 'CASによる認証に失敗しました。'; + } + + /** + * Get the your were not authenticated string + * + * @return string not authenticated + */ + public function getYouWereNotAuthenticated() + { + return '

認証できませんでした。

もう一度リクエストを送信する場合はこちらをクリック。

問題が解決しない場合は このサイトの管理者に問い合わせてください。

'; + } + + /** + * Get the service unavailable string + * + * @return string service unavailable + */ + public function getServiceUnavailable() + { + return 'サービス `%s\' は利用できません (%s)。'; + } +} +?> diff --git a/vendor/apereo/phpcas/source/CAS/Languages/LanguageInterface.php b/vendor/apereo/phpcas/source/CAS/Languages/LanguageInterface.php new file mode 100644 index 0000000000..5de93aa7b2 --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/Languages/LanguageInterface.php @@ -0,0 +1,96 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +/** + * Language Interface class for all internationalization files + * + * @class CAS_Languages_LanguageInterface + * @category Authentication + * @package PhpCAS + * @author Joachim Fritschi + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + * + * @sa @link internalLang Internationalization @endlink + * @ingroup internalLang + */ + +interface CAS_Languages_LanguageInterface +{ + /** + * Get the using server string + * + * @return string using server + */ + public function getUsingServer(); + + /** + * Get authentication wanted string + * + * @return string authentication wanted + */ + public function getAuthenticationWanted(); + + /** + * Get logout string + * + * @return string logout + */ + public function getLogout(); + + /** + * Get the should have been redirected string + * + * @return string should habe been redirected + */ + public function getShouldHaveBeenRedirected(); + + /** + * Get authentication failed string + * + * @return string authentication failed + */ + public function getAuthenticationFailed(); + + /** + * Get the your were not authenticated string + * + * @return string not authenticated + */ + public function getYouWereNotAuthenticated(); + + /** + * Get the service unavailable string + * + * @return string service unavailable + */ + public function getServiceUnavailable(); + +} +?> \ No newline at end of file diff --git a/vendor/apereo/phpcas/source/CAS/Languages/Spanish.php b/vendor/apereo/phpcas/source/CAS/Languages/Spanish.php new file mode 100644 index 0000000000..5675a41d80 --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/Languages/Spanish.php @@ -0,0 +1,117 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +/** + * Spanish language class + * + * @class CAS_Languages_Spanish + * @category Authentication + * @package PhpCAS + * @author Iván-Benjamín García Torà + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + * + + * @sa @link internalLang Internationalization @endlink + * @ingroup internalLang + */ +class CAS_Languages_Spanish implements CAS_Languages_LanguageInterface +{ + + /** + * Get the using server string + * + * @return string using server + */ + public function getUsingServer() + { + return 'usando servidor'; + } + + /** + * Get authentication wanted string + * + * @return string authentication wanted + */ + public function getAuthenticationWanted() + { + return '¡Autentificación CAS necesaria!'; + } + + /** + * Get logout string + * + * @return string logout + */ + public function getLogout() + { + return '¡Salida CAS necesaria!'; + } + + /** + * Get the should have been redirected string + * + * @return string should habe been redirected + */ + public function getShouldHaveBeenRedirected() + { + return 'Ya debería haber sido redireccionado al servidor CAS. Haga click aquí para continuar.'; + } + + /** + * Get authentication failed string + * + * @return string authentication failed + */ + public function getAuthenticationFailed() + { + return '¡Autentificación CAS fallida!'; + } + + /** + * Get the your were not authenticated string + * + * @return string not authenticated + */ + public function getYouWereNotAuthenticated() + { + return '

No estás autentificado.

Puedes volver a intentarlo haciendo click aquí.

Si el problema persiste debería contactar con el administrador de este sitio.

'; + } + + /** + * Get the service unavailable string + * + * @return string service unavailable + */ + public function getServiceUnavailable() + { + return 'El servicio `%s\' no está disponible (%s).'; + } +} +?> diff --git a/vendor/apereo/phpcas/source/CAS/OutOfSequenceBeforeAuthenticationCallException.php b/vendor/apereo/phpcas/source/CAS/OutOfSequenceBeforeAuthenticationCallException.php new file mode 100644 index 0000000000..ef83097958 --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/OutOfSequenceBeforeAuthenticationCallException.php @@ -0,0 +1,56 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +/** + * This class defines Exceptions that should be thrown when the sequence of + * operations is invalid. In this case it should be thrown when an + * authentication call has not yet happened. + * + * @class CAS_OutOfSequenceBeforeAuthenticationCallException + * @category Authentication + * @package PhpCAS + * @author Joachim Fritschi + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ +class CAS_OutOfSequenceBeforeAuthenticationCallException +extends CAS_OutOfSequenceException +implements CAS_Exception +{ + /** + * Return standard error meessage + * + * @return void + */ + public function __construct () + { + parent::__construct('An authentication call hasn\'t happened yet.'); + } +} diff --git a/vendor/apereo/phpcas/source/CAS/OutOfSequenceBeforeClientException.php b/vendor/apereo/phpcas/source/CAS/OutOfSequenceBeforeClientException.php new file mode 100644 index 0000000000..f1ea7e2447 --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/OutOfSequenceBeforeClientException.php @@ -0,0 +1,58 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +/** + * This class defines Exceptions that should be thrown when the sequence of + * operations is invalid. In this case it should be thrown when the client() or + * proxy() call has not yet happened and no client or proxy object exists. + * + * @class CAS_OutOfSequenceBeforeClientException + * @category Authentication + * @package PhpCAS + * @author Joachim Fritschi + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ +class CAS_OutOfSequenceBeforeClientException +extends CAS_OutOfSequenceException +implements CAS_Exception +{ + /** + * Return standard error message + * + * @return void + */ + public function __construct () + { + parent::__construct( + 'this method cannot be called before phpCAS::client() or phpCAS::proxy()' + ); + } +} diff --git a/vendor/apereo/phpcas/source/CAS/OutOfSequenceBeforeProxyException.php b/vendor/apereo/phpcas/source/CAS/OutOfSequenceBeforeProxyException.php new file mode 100644 index 0000000000..8038542ed1 --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/OutOfSequenceBeforeProxyException.php @@ -0,0 +1,59 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +/** + * This class defines Exceptions that should be thrown when the sequence of + * operations is invalid. In this case it should be thrown when the proxy() call + * has not yet happened and no proxy object exists. + * + * @class CAS_OutOfSequenceBeforeProxyException + * @category Authentication + * @package PhpCAS + * @author Joachim Fritschi + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ +class CAS_OutOfSequenceBeforeProxyException +extends CAS_OutOfSequenceException +implements CAS_Exception +{ + + /** + * Return standard error message + * + * @return void + */ + public function __construct () + { + parent::__construct( + 'this method cannot be called before phpCAS::proxy()' + ); + } +} diff --git a/vendor/apereo/phpcas/source/CAS/OutOfSequenceException.php b/vendor/apereo/phpcas/source/CAS/OutOfSequenceException.php new file mode 100644 index 0000000000..d101811b60 --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/OutOfSequenceException.php @@ -0,0 +1,49 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +/** + * This class defines Exceptions that should be thrown when the sequence of + * operations is invalid. Examples are: + * - Requesting the response before executing a request. + * - Changing the URL of a request after executing the request. + * + * @class CAS_OutOfSequenceException + * @category Authentication + * @package PhpCAS + * @author Adam Franco + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ +class CAS_OutOfSequenceException +extends BadMethodCallException +implements CAS_Exception +{ + +} diff --git a/vendor/apereo/phpcas/source/CAS/PGTStorage/AbstractStorage.php b/vendor/apereo/phpcas/source/CAS/PGTStorage/AbstractStorage.php new file mode 100644 index 0000000000..0f34711189 --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/PGTStorage/AbstractStorage.php @@ -0,0 +1,222 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +/** + * Basic class for PGT storage + * The CAS_PGTStorage_AbstractStorage class is a generic class for PGT storage. + * This class should not be instanciated itself but inherited by specific PGT + * storage classes. + * + * @class CAS_PGTStorage_AbstractStorage + * @category Authentication + * @package PhpCAS + * @author Pascal Aubry + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + * + * @ingroup internalPGTStorage + */ + +abstract class CAS_PGTStorage_AbstractStorage +{ + /** + * @addtogroup internalPGTStorage + * @{ + */ + + // ######################################################################## + // CONSTRUCTOR + // ######################################################################## + + /** + * The constructor of the class, should be called only by inherited classes. + * + * @param CAS_Client $cas_parent the CAS _client instance that creates the + * current object. + * + * @return void + * + * @protected + */ + function __construct($cas_parent) + { + phpCAS::traceBegin(); + if ( !$cas_parent->isProxy() ) { + phpCAS::error( + 'defining PGT storage makes no sense when not using a CAS proxy' + ); + } + phpCAS::traceEnd(); + } + + // ######################################################################## + // DEBUGGING + // ######################################################################## + + /** + * This virtual method returns an informational string giving the type of storage + * used by the object (used for debugging purposes). + * + * @return string + * + * @public + */ + function getStorageType() + { + phpCAS::error(__CLASS__.'::'.__FUNCTION__.'() should never be called'); + } + + /** + * This virtual method returns an informational string giving informations on the + * parameters of the storage.(used for debugging purposes). + * + * @return string + * + * @public + */ + function getStorageInfo() + { + phpCAS::error(__CLASS__.'::'.__FUNCTION__.'() should never be called'); + } + + // ######################################################################## + // ERROR HANDLING + // ######################################################################## + + /** + * string used to store an error message. Written by + * PGTStorage::setErrorMessage(), read by PGTStorage::getErrorMessage(). + * + * @hideinitializer + * @deprecated not used. + */ + var $_error_message=false; + + /** + * This method sets en error message, which can be read later by + * PGTStorage::getErrorMessage(). + * + * @param string $error_message an error message + * + * @return void + * + * @deprecated not used. + */ + function setErrorMessage($error_message) + { + $this->_error_message = $error_message; + } + + /** + * This method returns an error message set by PGTStorage::setErrorMessage(). + * + * @return string an error message when set by PGTStorage::setErrorMessage(), FALSE + * otherwise. + * + * @deprecated not used. + */ + function getErrorMessage() + { + return $this->_error_message; + } + + // ######################################################################## + // INITIALIZATION + // ######################################################################## + + /** + * a boolean telling if the storage has already been initialized. Written by + * PGTStorage::init(), read by PGTStorage::isInitialized(). + * + * @hideinitializer + */ + var $_initialized = false; + + /** + * This method tells if the storage has already been intialized. + * + * @return bool + * + * @protected + */ + function isInitialized() + { + return $this->_initialized; + } + + /** + * This virtual method initializes the object. + * + * @return void + */ + function init() + { + $this->_initialized = true; + } + + // ######################################################################## + // PGT I/O + // ######################################################################## + + /** + * This virtual method stores a PGT and its corresponding PGT Iuo. + * + * @param string $pgt the PGT + * @param string $pgt_iou the PGT iou + * + * @return void + * + * @note Should never be called. + * + */ + function write($pgt,$pgt_iou) + { + phpCAS::error(__CLASS__.'::'.__FUNCTION__.'() should never be called'); + } + + /** + * This virtual method reads a PGT corresponding to a PGT Iou and deletes + * the corresponding storage entry. + * + * @param string $pgt_iou the PGT iou + * + * @return string + * + * @note Should never be called. + */ + function read($pgt_iou) + { + phpCAS::error(__CLASS__.'::'.__FUNCTION__.'() should never be called'); + } + + /** @} */ + +} + +?> diff --git a/vendor/apereo/phpcas/source/CAS/PGTStorage/Db.php b/vendor/apereo/phpcas/source/CAS/PGTStorage/Db.php new file mode 100644 index 0000000000..383d11dc72 --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/PGTStorage/Db.php @@ -0,0 +1,440 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +define('CAS_PGT_STORAGE_DB_DEFAULT_TABLE', 'cas_pgts'); + +/** + * Basic class for PGT database storage + * The CAS_PGTStorage_Db class is a class for PGT database storage. + * + * @class CAS_PGTStorage_Db + * @category Authentication + * @package PhpCAS + * @author Daniel Frett + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + * + * @ingroup internalPGTStorageDb + */ + +class CAS_PGTStorage_Db extends CAS_PGTStorage_AbstractStorage +{ + /** + * @addtogroup internalCAS_PGTStorageDb + * @{ + */ + + /** + * the PDO object to use for database interactions + */ + private $_pdo; + + /** + * This method returns the PDO object to use for database interactions. + * + * @return PDO object + */ + private function _getPdo() + { + return $this->_pdo; + } + + /** + * database connection options to use when creating a new PDO object + */ + private $_dsn; + private $_username; + private $_password; + private $_driver_options; + + /** + * @var string the table to use for storing/retrieving pgt's + */ + private $_table; + + /** + * This method returns the table to use when storing/retrieving PGT's + * + * @return string the name of the pgt storage table. + */ + private function _getTable() + { + return $this->_table; + } + + // ######################################################################## + // DEBUGGING + // ######################################################################## + + /** + * This method returns an informational string giving the type of storage + * used by the object (used for debugging purposes). + * + * @return string an informational string. + */ + public function getStorageType() + { + return "db"; + } + + /** + * This method returns an informational string giving informations on the + * parameters of the storage.(used for debugging purposes). + * + * @return string an informational string. + * @public + */ + public function getStorageInfo() + { + return 'table=`'.$this->_getTable().'\''; + } + + // ######################################################################## + // CONSTRUCTOR + // ######################################################################## + + /** + * The class constructor. + * + * @param CAS_Client $cas_parent the CAS_Client instance that creates + * the object. + * @param string $dsn_or_pdo a dsn string to use for creating a PDO + * object or a PDO object + * @param string $username the username to use when connecting to + * the database + * @param string $password the password to use when connecting to + * the database + * @param string $table the table to use for storing and + * retrieving PGT's + * @param string $driver_options any driver options to use when + * connecting to the database + */ + public function __construct( + $cas_parent, $dsn_or_pdo, $username='', $password='', $table='', + $driver_options=null + ) { + phpCAS::traceBegin(); + // call the ancestor's constructor + parent::__construct($cas_parent); + + // set default values + if ( empty($table) ) { + $table = CAS_PGT_STORAGE_DB_DEFAULT_TABLE; + } + if ( !is_array($driver_options) ) { + $driver_options = array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION); + } + + // store the specified parameters + if ($dsn_or_pdo instanceof PDO) { + $this->_pdo = $dsn_or_pdo; + } else { + $this->_dsn = $dsn_or_pdo; + $this->_username = $username; + $this->_password = $password; + $this->_driver_options = $driver_options; + } + + // store the table name + $this->_table = $table; + + phpCAS::traceEnd(); + } + + // ######################################################################## + // INITIALIZATION + // ######################################################################## + + /** + * This method is used to initialize the storage. Halts on error. + * + * @return void + */ + public function init() + { + phpCAS::traceBegin(); + // if the storage has already been initialized, return immediatly + if ($this->isInitialized()) { + return; + } + + // initialize the base object + parent::init(); + + // create the PDO object if it doesn't exist already + if (!($this->_pdo instanceof PDO)) { + try { + $this->_pdo = new PDO( + $this->_dsn, $this->_username, $this->_password, + $this->_driver_options + ); + } + catch(PDOException $e) { + phpCAS::error('Database connection error: ' . $e->getMessage()); + } + } + + phpCAS::traceEnd(); + } + + // ######################################################################## + // PDO database interaction + // ######################################################################## + + /** + * attribute that stores the previous error mode for the PDO handle while + * processing a transaction + */ + private $_errMode; + + /** + * This method will enable the Exception error mode on the PDO object + * + * @return void + */ + private function _setErrorMode() + { + // get PDO object and enable exception error mode + $pdo = $this->_getPdo(); + $this->_errMode = $pdo->getAttribute(PDO::ATTR_ERRMODE); + $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + } + + /** + * this method will reset the error mode on the PDO object + * + * @return void + */ + private function _resetErrorMode() + { + // get PDO object and reset the error mode to what it was originally + $pdo = $this->_getPdo(); + $pdo->setAttribute(PDO::ATTR_ERRMODE, $this->_errMode); + } + + // ######################################################################## + // database queries + // ######################################################################## + // these queries are potentially unsafe because the person using this library + // can set the table to use, but there is no reliable way to escape SQL + // fieldnames in PDO yet + + /** + * This method returns the query used to create a pgt storage table + * + * @return string the create table SQL, no bind params in query + */ + protected function createTableSql() + { + return 'CREATE TABLE ' . $this->_getTable() + . ' (pgt_iou VARCHAR(255) NOT NULL PRIMARY KEY, pgt VARCHAR(255) NOT NULL)'; + } + + /** + * This method returns the query used to store a pgt + * + * @return string the store PGT SQL, :pgt and :pgt_iou are the bind params contained + * in the query + */ + protected function storePgtSql() + { + return 'INSERT INTO ' . $this->_getTable() + . ' (pgt_iou, pgt) VALUES (:pgt_iou, :pgt)'; + } + + /** + * This method returns the query used to retrieve a pgt. the first column + * of the first row should contain the pgt + * + * @return string the retrieve PGT SQL, :pgt_iou is the only bind param contained + * in the query + */ + protected function retrievePgtSql() + { + return 'SELECT pgt FROM ' . $this->_getTable() . ' WHERE pgt_iou = :pgt_iou'; + } + + /** + * This method returns the query used to delete a pgt. + * + * @return string the delete PGT SQL, :pgt_iou is the only bind param contained in + * the query + */ + protected function deletePgtSql() + { + return 'DELETE FROM ' . $this->_getTable() . ' WHERE pgt_iou = :pgt_iou'; + } + + // ######################################################################## + // PGT I/O + // ######################################################################## + + /** + * This method creates the database table used to store pgt's and pgtiou's + * + * @return void + */ + public function createTable() + { + phpCAS::traceBegin(); + + // initialize this PGTStorage object if it hasn't been initialized yet + if ( !$this->isInitialized() ) { + $this->init(); + } + + // initialize the PDO object for this method + $pdo = $this->_getPdo(); + $this->_setErrorMode(); + + try { + $pdo->beginTransaction(); + + $query = $pdo->query($this->createTableSQL()); + $query->closeCursor(); + + $pdo->commit(); + } + catch(PDOException $e) { + // attempt rolling back the transaction before throwing a phpCAS error + try { + $pdo->rollBack(); + } + catch(PDOException $e) { + } + phpCAS::error('error creating PGT storage table: ' . $e->getMessage()); + } + + // reset the PDO object + $this->_resetErrorMode(); + + phpCAS::traceEnd(); + } + + /** + * This method stores a PGT and its corresponding PGT Iou in the database. + * Echoes a warning on error. + * + * @param string $pgt the PGT + * @param string $pgt_iou the PGT iou + * + * @return void + */ + public function write($pgt, $pgt_iou) + { + phpCAS::traceBegin(); + + // initialize the PDO object for this method + $pdo = $this->_getPdo(); + $this->_setErrorMode(); + + try { + $pdo->beginTransaction(); + + $query = $pdo->prepare($this->storePgtSql()); + $query->bindValue(':pgt', $pgt, PDO::PARAM_STR); + $query->bindValue(':pgt_iou', $pgt_iou, PDO::PARAM_STR); + $query->execute(); + $query->closeCursor(); + + $pdo->commit(); + } + catch(PDOException $e) { + // attempt rolling back the transaction before throwing a phpCAS error + try { + $pdo->rollBack(); + } + catch(PDOException $e) { + } + phpCAS::error('error writing PGT to database: ' . $e->getMessage()); + } + + // reset the PDO object + $this->_resetErrorMode(); + + phpCAS::traceEnd(); + } + + /** + * This method reads a PGT corresponding to a PGT Iou and deletes the + * corresponding db entry. + * + * @param string $pgt_iou the PGT iou + * + * @return string|false the corresponding PGT, or FALSE on error + */ + public function read($pgt_iou) + { + phpCAS::traceBegin(); + $pgt = false; + + // initialize the PDO object for this method + $pdo = $this->_getPdo(); + $this->_setErrorMode(); + + try { + $pdo->beginTransaction(); + + // fetch the pgt for the specified pgt_iou + $query = $pdo->prepare($this->retrievePgtSql()); + $query->bindValue(':pgt_iou', $pgt_iou, PDO::PARAM_STR); + $query->execute(); + $pgt = $query->fetchColumn(0); + $query->closeCursor(); + + // delete the specified pgt_iou from the database + $query = $pdo->prepare($this->deletePgtSql()); + $query->bindValue(':pgt_iou', $pgt_iou, PDO::PARAM_STR); + $query->execute(); + $query->closeCursor(); + + $pdo->commit(); + } + catch(PDOException $e) { + // attempt rolling back the transaction before throwing a phpCAS error + try { + $pdo->rollBack(); + } + catch(PDOException $e) { + } + phpCAS::trace('error reading PGT from database: ' . $e->getMessage()); + } + + // reset the PDO object + $this->_resetErrorMode(); + + phpCAS::traceEnd(); + return $pgt; + } + + /** @} */ + +} + +?> diff --git a/vendor/apereo/phpcas/source/CAS/PGTStorage/File.php b/vendor/apereo/phpcas/source/CAS/PGTStorage/File.php new file mode 100644 index 0000000000..6504ec5990 --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/PGTStorage/File.php @@ -0,0 +1,261 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +/** + * The CAS_PGTStorage_File class is a class for PGT file storage. An instance of + * this class is returned by CAS_Client::SetPGTStorageFile(). + * + * @class CAS_PGTStorage_File + * @category Authentication + * @package PhpCAS + * @author Pascal Aubry + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + * + * + * @ingroup internalPGTStorageFile + */ + +class CAS_PGTStorage_File extends CAS_PGTStorage_AbstractStorage +{ + /** + * @addtogroup internalPGTStorageFile + * @{ + */ + + /** + * a string telling where PGT's should be stored on the filesystem. Written by + * PGTStorageFile::PGTStorageFile(), read by getPath(). + * + * @private + */ + var $_path; + + /** + * This method returns the name of the directory where PGT's should be stored + * on the filesystem. + * + * @return string the name of a directory (with leading and trailing '/') + * + * @private + */ + function getPath() + { + return $this->_path; + } + + // ######################################################################## + // DEBUGGING + // ######################################################################## + + /** + * This method returns an informational string giving the type of storage + * used by the object (used for debugging purposes). + * + * @return string an informational string. + * @public + */ + function getStorageType() + { + return "file"; + } + + /** + * This method returns an informational string giving informations on the + * parameters of the storage.(used for debugging purposes). + * + * @return string an informational string. + * @public + */ + function getStorageInfo() + { + return 'path=`'.$this->getPath().'\''; + } + + // ######################################################################## + // CONSTRUCTOR + // ######################################################################## + + /** + * The class constructor, called by CAS_Client::SetPGTStorageFile(). + * + * @param CAS_Client $cas_parent the CAS_Client instance that creates the object. + * @param string $path the path where the PGT's should be stored + * + * @return void + * + * @public + */ + function __construct($cas_parent,$path) + { + phpCAS::traceBegin(); + // call the ancestor's constructor + parent::__construct($cas_parent); + + if (empty($path)) { + $path = CAS_PGT_STORAGE_FILE_DEFAULT_PATH; + } + // check that the path is an absolute path + if (getenv("OS")=="Windows_NT" || strtoupper(substr(PHP_OS,0,3)) == 'WIN') { + + if (!preg_match('`^[a-zA-Z]:`', $path)) { + phpCAS::error('an absolute path is needed for PGT storage to file'); + } + + } else { + + if ( $path[0] != '/' ) { + phpCAS::error('an absolute path is needed for PGT storage to file'); + } + + // store the path (with a leading and trailing '/') + $path = preg_replace('|[/]*$|', '/', $path); + $path = preg_replace('|^[/]*|', '/', $path); + } + + $this->_path = $path; + phpCAS::traceEnd(); + } + + // ######################################################################## + // INITIALIZATION + // ######################################################################## + + /** + * This method is used to initialize the storage. Halts on error. + * + * @return void + * @public + */ + function init() + { + phpCAS::traceBegin(); + // if the storage has already been initialized, return immediatly + if ($this->isInitialized()) { + return; + } + // call the ancestor's method (mark as initialized) + parent::init(); + phpCAS::traceEnd(); + } + + // ######################################################################## + // PGT I/O + // ######################################################################## + + /** + * This method returns the filename corresponding to a PGT Iou. + * + * @param string $pgt_iou the PGT iou. + * + * @return string a filename + * @private + */ + function getPGTIouFilename($pgt_iou) + { + phpCAS::traceBegin(); + $filename = $this->getPath()."phpcas-".hash("sha256", $pgt_iou); +// $filename = $this->getPath().$pgt_iou.'.plain'; + phpCAS::trace("Sha256 filename:" . $filename); + phpCAS::traceEnd(); + return $filename; + } + + /** + * This method stores a PGT and its corresponding PGT Iou into a file. Echoes a + * warning on error. + * + * @param string $pgt the PGT + * @param string $pgt_iou the PGT iou + * + * @return void + * + * @public + */ + function write($pgt,$pgt_iou) + { + phpCAS::traceBegin(); + $fname = $this->getPGTIouFilename($pgt_iou); + if (!file_exists($fname)) { + touch($fname); + // Chmod will fail on windows + @chmod($fname, 0600); + if ($f=fopen($fname, "w")) { + if (fputs($f, $pgt) === false) { + phpCAS::error('could not write PGT to `'.$fname.'\''); + } + phpCAS::trace('Successful write of PGT to `'.$fname.'\''); + fclose($f); + } else { + phpCAS::error('could not open `'.$fname.'\''); + } + } else { + phpCAS::error('File exists: `'.$fname.'\''); + } + phpCAS::traceEnd(); + } + + /** + * This method reads a PGT corresponding to a PGT Iou and deletes the + * corresponding file. + * + * @param string $pgt_iou the PGT iou + * + * @return string|false the corresponding PGT, or FALSE on error + * + * @public + */ + function read($pgt_iou) + { + phpCAS::traceBegin(); + $pgt = false; + $fname = $this->getPGTIouFilename($pgt_iou); + if (file_exists($fname)) { + if (!($f=fopen($fname, "r"))) { + phpCAS::error('could not open `'.$fname.'\''); + } else { + if (($pgt=fgets($f)) === false) { + phpCAS::error('could not read PGT from `'.$fname.'\''); + } + phpCAS::trace('Successful read of PGT to `'.$fname.'\''); + fclose($f); + } + // delete the PGT file + @unlink($fname); + } else { + phpCAS::error('No such file `'.$fname.'\''); + } + phpCAS::traceEnd($pgt); + return $pgt; + } + + /** @} */ + +} +?> diff --git a/vendor/apereo/phpcas/source/CAS/ProxiedService.php b/vendor/apereo/phpcas/source/CAS/ProxiedService.php new file mode 100644 index 0000000000..d70ca9c128 --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/ProxiedService.php @@ -0,0 +1,72 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +/** + * This interface defines methods that allow proxy-authenticated service handlers + * to interact with phpCAS. + * + * Proxy service handlers must implement this interface as well as call + * phpCAS::initializeProxiedService($this) at some point in their implementation. + * + * While not required, proxy-authenticated service handlers are encouraged to + * implement the CAS_ProxiedService_Testable interface to facilitate unit testing. + * + * @class CAS_ProxiedService + * @category Authentication + * @package PhpCAS + * @author Adam Franco + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ +interface CAS_ProxiedService +{ + + /** + * Answer a service identifier (URL) for whom we should fetch a proxy ticket. + * + * @return string + * @throws Exception If no service url is available. + */ + public function getServiceUrl (); + + /** + * Register a proxy ticket with the ProxiedService that it can use when + * making requests. + * + * @param string $proxyTicket Proxy ticket string + * + * @return void + * @throws InvalidArgumentException If the $proxyTicket is invalid. + * @throws CAS_OutOfSequenceException If called after a proxy ticket has + * already been initialized/set. + */ + public function setProxyTicket ($proxyTicket); + +} +?> diff --git a/vendor/apereo/phpcas/source/CAS/ProxiedService/Abstract.php b/vendor/apereo/phpcas/source/CAS/ProxiedService/Abstract.php new file mode 100644 index 0000000000..fade9e70b7 --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/ProxiedService/Abstract.php @@ -0,0 +1,149 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +/** + * This class implements common methods for ProxiedService implementations included + * with phpCAS. + * + * @class CAS_ProxiedService_Abstract + * @category Authentication + * @package PhpCAS + * @author Adam Franco + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ +abstract class CAS_ProxiedService_Abstract +implements CAS_ProxiedService, CAS_ProxiedService_Testable +{ + + /** + * The proxy ticket that can be used when making service requests. + * @var string $_proxyTicket; + */ + private $_proxyTicket; + + /** + * Register a proxy ticket with the Proxy that it can use when making requests. + * + * @param string $proxyTicket proxy ticket + * + * @return void + * @throws InvalidArgumentException If the $proxyTicket is invalid. + * @throws CAS_OutOfSequenceException If called after a proxy ticket has + * already been initialized/set. + */ + public function setProxyTicket ($proxyTicket) + { + if (empty($proxyTicket)) { + throw new CAS_InvalidArgumentException( + 'Trying to initialize with an empty proxy ticket.' + ); + } + if (!empty($this->_proxyTicket)) { + throw new CAS_OutOfSequenceException( + 'Already initialized, cannot change the proxy ticket.' + ); + } + $this->_proxyTicket = $proxyTicket; + } + + /** + * Answer the proxy ticket to be used when making requests. + * + * @return string + * @throws CAS_OutOfSequenceException If called before a proxy ticket has + * already been initialized/set. + */ + protected function getProxyTicket () + { + if (empty($this->_proxyTicket)) { + throw new CAS_OutOfSequenceException( + 'No proxy ticket yet. Call $this->initializeProxyTicket() to aquire the proxy ticket.' + ); + } + + return $this->_proxyTicket; + } + + /** + * @var CAS_Client $_casClient; + */ + private $_casClient; + + /** + * Use a particular CAS_Client->initializeProxiedService() rather than the + * static phpCAS::initializeProxiedService(). + * + * This method should not be called in standard operation, but is needed for unit + * testing. + * + * @param CAS_Client $casClient cas client + * + * @return void + * @throws CAS_OutOfSequenceException If called after a proxy ticket has + * already been initialized/set. + */ + public function setCasClient (CAS_Client $casClient) + { + if (!empty($this->_proxyTicket)) { + throw new CAS_OutOfSequenceException( + 'Already initialized, cannot change the CAS_Client.' + ); + } + + $this->_casClient = $casClient; + } + + /** + * Fetch our proxy ticket. + * + * Descendent classes should call this method once their service URL is available + * to initialize their proxy ticket. + * + * @return void + * @throws CAS_OutOfSequenceException If called after a proxy ticket has + * already been initialized. + */ + protected function initializeProxyTicket() + { + if (!empty($this->_proxyTicket)) { + throw new CAS_OutOfSequenceException( + 'Already initialized, cannot initialize again.' + ); + } + // Allow usage of a particular CAS_Client for unit testing. + if (empty($this->_casClient)) { + phpCAS::initializeProxiedService($this); + } else { + $this->_casClient->initializeProxiedService($this); + } + } + +} +?> diff --git a/vendor/apereo/phpcas/source/CAS/ProxiedService/Exception.php b/vendor/apereo/phpcas/source/CAS/ProxiedService/Exception.php new file mode 100644 index 0000000000..5a1e69622a --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/ProxiedService/Exception.php @@ -0,0 +1,46 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +/** + * An Exception for problems communicating with a proxied service. + * + * @class CAS_ProxiedService_Exception + * @category Authentication + * @package PhpCAS + * @author Adam Franco + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ +class CAS_ProxiedService_Exception +extends Exception +implements CAS_Exception +{ + +} +?> diff --git a/vendor/apereo/phpcas/source/CAS/ProxiedService/Http.php b/vendor/apereo/phpcas/source/CAS/ProxiedService/Http.php new file mode 100644 index 0000000000..7c9824fabc --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/ProxiedService/Http.php @@ -0,0 +1,91 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +/** + * This interface defines methods that clients should use for configuring, sending, + * and receiving proxied HTTP requests. + * + * @class CAS_ProxiedService_Http + * @category Authentication + * @package PhpCAS + * @author Adam Franco + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ +interface CAS_ProxiedService_Http +{ + + /********************************************************* + * Configure the Request + *********************************************************/ + + /** + * Set the URL of the Request + * + * @param string $url Url to set + * + * @return void + * @throws CAS_OutOfSequenceException If called after the Request has been sent. + */ + public function setUrl ($url); + + /********************************************************* + * 2. Send the Request + *********************************************************/ + + /** + * Perform the request. + * + * @return bool TRUE on success, FALSE on failure. + * @throws CAS_OutOfSequenceException If called multiple times. + */ + public function send (); + + /********************************************************* + * 3. Access the response + *********************************************************/ + + /** + * Answer the headers of the response. + * + * @return array An array of header strings. + * @throws CAS_OutOfSequenceException If called before the Request has been sent. + */ + public function getResponseHeaders (); + + /** + * Answer the body of response. + * + * @return string + * @throws CAS_OutOfSequenceException If called before the Request has been sent. + */ + public function getResponseBody (); + +} +?> diff --git a/vendor/apereo/phpcas/source/CAS/ProxiedService/Http/Abstract.php b/vendor/apereo/phpcas/source/CAS/ProxiedService/Http/Abstract.php new file mode 100644 index 0000000000..61abfd84f4 --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/ProxiedService/Http/Abstract.php @@ -0,0 +1,360 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +/** + * This class implements common methods for ProxiedService implementations included + * with phpCAS. + * + * @class CAS_ProxiedService_Http_Abstract + * @category Authentication + * @package PhpCAS + * @author Adam Franco + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ +abstract class CAS_ProxiedService_Http_Abstract extends +CAS_ProxiedService_Abstract implements CAS_ProxiedService_Http +{ + /** + * The HTTP request mechanism talking to the target service. + * + * @var CAS_Request_RequestInterface $requestHandler + */ + protected $requestHandler; + + /** + * The storage mechanism for cookies set by the target service. + * + * @var CAS_CookieJar $_cookieJar + */ + private $_cookieJar; + + /** + * Constructor. + * + * @param CAS_Request_RequestInterface $requestHandler request handler object + * @param CAS_CookieJar $cookieJar cookieJar object + * + * @return void + */ + public function __construct(CAS_Request_RequestInterface $requestHandler, + CAS_CookieJar $cookieJar + ) { + $this->requestHandler = $requestHandler; + $this->_cookieJar = $cookieJar; + } + + /** + * The target service url. + * @var string $_url; + */ + private $_url; + + /** + * Answer a service identifier (URL) for whom we should fetch a proxy ticket. + * + * @return string + * @throws Exception If no service url is available. + */ + public function getServiceUrl() + { + if (empty($this->_url)) { + throw new CAS_ProxiedService_Exception( + 'No URL set via ' . get_class($this) . '->setUrl($url).' + ); + } + + return $this->_url; + } + + /********************************************************* + * Configure the Request + *********************************************************/ + + /** + * Set the URL of the Request + * + * @param string $url url to set + * + * @return void + * @throws CAS_OutOfSequenceException If called after the Request has been sent. + */ + public function setUrl($url) + { + if ($this->hasBeenSent()) { + throw new CAS_OutOfSequenceException( + 'Cannot set the URL, request already sent.' + ); + } + if (!is_string($url)) { + throw new CAS_InvalidArgumentException('$url must be a string.'); + } + + $this->_url = $url; + } + + /********************************************************* + * 2. Send the Request + *********************************************************/ + + /** + * Perform the request. + * + * @return void + * @throws CAS_OutOfSequenceException If called multiple times. + * @throws CAS_ProxyTicketException If there is a proxy-ticket failure. + * The code of the Exception will be one of: + * PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE + * PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE + * PHPCAS_SERVICE_PT_FAILURE + * @throws CAS_ProxiedService_Exception If there is a failure sending the + * request to the target service. + */ + public function send() + { + if ($this->hasBeenSent()) { + throw new CAS_OutOfSequenceException( + 'Cannot send, request already sent.' + ); + } + + phpCAS::traceBegin(); + + // Get our proxy ticket and append it to our URL. + $this->initializeProxyTicket(); + $url = $this->getServiceUrl(); + if (strstr($url, '?') === false) { + $url = $url . '?ticket=' . $this->getProxyTicket(); + } else { + $url = $url . '&ticket=' . $this->getProxyTicket(); + } + + try { + $this->makeRequest($url); + } catch (Exception $e) { + phpCAS::traceEnd(); + throw $e; + } + } + + /** + * Indicator of the number of requests (including redirects performed. + * + * @var int $_numRequests; + */ + private $_numRequests = 0; + + /** + * The response headers. + * + * @var array $_responseHeaders; + */ + private $_responseHeaders = array(); + + /** + * The response status code. + * + * @var int $_responseStatusCode; + */ + private $_responseStatusCode = ''; + + /** + * The response headers. + * + * @var string $_responseBody; + */ + private $_responseBody = ''; + + /** + * Build and perform a request, following redirects + * + * @param string $url url for the request + * + * @return void + * @throws CAS_ProxyTicketException If there is a proxy-ticket failure. + * The code of the Exception will be one of: + * PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE + * PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE + * PHPCAS_SERVICE_PT_FAILURE + * @throws CAS_ProxiedService_Exception If there is a failure sending the + * request to the target service. + */ + protected function makeRequest($url) + { + // Verify that we are not in a redirect loop + $this->_numRequests++; + if ($this->_numRequests > 4) { + $message = 'Exceeded the maximum number of redirects (3) in proxied service request.'; + phpCAS::trace($message); + throw new CAS_ProxiedService_Exception($message); + } + + // Create a new request. + $request = clone $this->requestHandler; + $request->setUrl($url); + + // Add any cookies to the request. + $request->addCookies($this->_cookieJar->getCookies($url)); + + // Add any other parts of the request needed by concrete classes + $this->populateRequest($request); + + // Perform the request. + phpCAS::trace('Performing proxied service request to \'' . $url . '\''); + if (!$request->send()) { + $message = 'Could not perform proxied service request to URL`' + . $url . '\'. ' . $request->getErrorMessage(); + phpCAS::trace($message); + throw new CAS_ProxiedService_Exception($message); + } + + // Store any cookies from the response; + $this->_cookieJar->storeCookies($url, $request->getResponseHeaders()); + + // Follow any redirects + if ($redirectUrl = $this->getRedirectUrl($request->getResponseHeaders()) + ) { + phpCAS::trace('Found redirect:' . $redirectUrl); + $this->makeRequest($redirectUrl); + } else { + + $this->_responseHeaders = $request->getResponseHeaders(); + $this->_responseBody = $request->getResponseBody(); + $this->_responseStatusCode = $request->getResponseStatusCode(); + } + } + + /** + * Add any other parts of the request needed by concrete classes + * + * @param CAS_Request_RequestInterface $request request interface object + * + * @return void + */ + abstract protected function populateRequest( + CAS_Request_RequestInterface $request + ); + + /** + * Answer a redirect URL if a redirect header is found, otherwise null. + * + * @param array $responseHeaders response header to extract a redirect from + * + * @return string|null + */ + protected function getRedirectUrl(array $responseHeaders) + { + // Check for the redirect after authentication + foreach ($responseHeaders as $header) { + if ( preg_match('/^(Location:|URI:)\s*([^\s]+.*)$/', $header, $matches) + ) { + return trim(array_pop($matches)); + } + } + return null; + } + + /********************************************************* + * 3. Access the response + *********************************************************/ + + /** + * Answer true if our request has been sent yet. + * + * @return bool + */ + protected function hasBeenSent() + { + return ($this->_numRequests > 0); + } + + /** + * Answer the headers of the response. + * + * @return array An array of header strings. + * @throws CAS_OutOfSequenceException If called before the Request has been sent. + */ + public function getResponseHeaders() + { + if (!$this->hasBeenSent()) { + throw new CAS_OutOfSequenceException( + 'Cannot access response, request not sent yet.' + ); + } + + return $this->_responseHeaders; + } + + /** + * Answer HTTP status code of the response + * + * @return int + * @throws CAS_OutOfSequenceException If called before the Request has been sent. + */ + public function getResponseStatusCode() + { + if (!$this->hasBeenSent()) { + throw new CAS_OutOfSequenceException( + 'Cannot access response, request not sent yet.' + ); + } + + return $this->_responseStatusCode; + } + + /** + * Answer the body of response. + * + * @return string + * @throws CAS_OutOfSequenceException If called before the Request has been sent. + */ + public function getResponseBody() + { + if (!$this->hasBeenSent()) { + throw new CAS_OutOfSequenceException( + 'Cannot access response, request not sent yet.' + ); + } + + return $this->_responseBody; + } + + /** + * Answer the cookies from the response. This may include cookies set during + * redirect responses. + * + * @return array An array containing cookies. E.g. array('name' => 'val'); + */ + public function getCookies() + { + return $this->_cookieJar->getCookies($this->getServiceUrl()); + } + +} +?> diff --git a/vendor/apereo/phpcas/source/CAS/ProxiedService/Http/Get.php b/vendor/apereo/phpcas/source/CAS/ProxiedService/Http/Get.php new file mode 100644 index 0000000000..78e35de16f --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/ProxiedService/Http/Get.php @@ -0,0 +1,85 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +/** + * This class is used to make proxied service requests via the HTTP GET method. + * + * Usage Example: + * + * try { + * $service = phpCAS::getProxiedService(PHPCAS_PROXIED_SERVICE_HTTP_GET); + * $service->setUrl('http://www.example.com/path/'); + * $service->send(); + * if ($service->getResponseStatusCode() == 200) + * return $service->getResponseBody(); + * else + * // The service responded with an error code 404, 500, etc. + * throw new Exception('The service responded with an error.'); + * + * } catch (CAS_ProxyTicketException $e) { + * if ($e->getCode() == PHPCAS_SERVICE_PT_FAILURE) + * return "Your login has timed out. You need to log in again."; + * else + * // Other proxy ticket errors are from bad request format + * // (shouldn't happen) or CAS server failure (unlikely) + * // so lets just stop if we hit those. + * throw $e; + * } catch (CAS_ProxiedService_Exception $e) { + * // Something prevented the service request from being sent or received. + * // We didn't even get a valid error response (404, 500, etc), so this + * // might be caused by a network error or a DNS resolution failure. + * // We could handle it in some way, but for now we will just stop. + * throw $e; + * } + * + * @class CAS_ProxiedService_Http_Get + * @category Authentication + * @package PhpCAS + * @author Adam Franco + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ +class CAS_ProxiedService_Http_Get +extends CAS_ProxiedService_Http_Abstract +{ + + /** + * Add any other parts of the request needed by concrete classes + * + * @param CAS_Request_RequestInterface $request request interface + * + * @return void + */ + protected function populateRequest (CAS_Request_RequestInterface $request) + { + // do nothing, since the URL has already been sent and that is our + // only data. + } +} +?> diff --git a/vendor/apereo/phpcas/source/CAS/ProxiedService/Http/Post.php b/vendor/apereo/phpcas/source/CAS/ProxiedService/Http/Post.php new file mode 100644 index 0000000000..7d4ecd3c03 --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/ProxiedService/Http/Post.php @@ -0,0 +1,152 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +/** + * This class is used to make proxied service requests via the HTTP POST method. + * + * Usage Example: + * + * try { + * $service = phpCAS::getProxiedService(PHPCAS_PROXIED_SERVICE_HTTP_POST); + * $service->setUrl('http://www.example.com/path/'); + * $service->setContentType('text/xml'); + * $service->setBody('example.search'); + * $service->send(); + * if ($service->getResponseStatusCode() == 200) + * return $service->getResponseBody(); + * else + * // The service responded with an error code 404, 500, etc. + * throw new Exception('The service responded with an error.'); + * + * } catch (CAS_ProxyTicketException $e) { + * if ($e->getCode() == PHPCAS_SERVICE_PT_FAILURE) + * return "Your login has timed out. You need to log in again."; + * else + * // Other proxy ticket errors are from bad request format + * // (shouldn't happen) or CAS server failure (unlikely) so lets just + * // stop if we hit those. + * throw $e; + * } catch (CAS_ProxiedService_Exception $e) { + * // Something prevented the service request from being sent or received. + * // We didn't even get a valid error response (404, 500, etc), so this + * // might be caused by a network error or a DNS resolution failure. + * // We could handle it in some way, but for now we will just stop. + * throw $e; + * } + * + * @class CAS_ProxiedService_Http_Post + * @category Authentication + * @package PhpCAS + * @author Adam Franco + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ +class CAS_ProxiedService_Http_Post +extends CAS_ProxiedService_Http_Abstract +{ + + /** + * The content-type of this request + * + * @var string $_contentType + */ + private $_contentType; + + /** + * The body of the this request + * + * @var string $_body + */ + private $_body; + + /** + * Set the content type of this POST request. + * + * @param string $contentType content type + * + * @return void + * @throws CAS_OutOfSequenceException If called after the Request has been sent. + */ + public function setContentType ($contentType) + { + if ($this->hasBeenSent()) { + throw new CAS_OutOfSequenceException( + 'Cannot set the content type, request already sent.' + ); + } + + $this->_contentType = $contentType; + } + + /** + * Set the body of this POST request. + * + * @param string $body body to set + * + * @return void + * @throws CAS_OutOfSequenceException If called after the Request has been sent. + */ + public function setBody ($body) + { + if ($this->hasBeenSent()) { + throw new CAS_OutOfSequenceException( + 'Cannot set the body, request already sent.' + ); + } + + $this->_body = $body; + } + + /** + * Add any other parts of the request needed by concrete classes + * + * @param CAS_Request_RequestInterface $request request interface class + * + * @return void + */ + protected function populateRequest (CAS_Request_RequestInterface $request) + { + if (empty($this->_contentType) && !empty($this->_body)) { + throw new CAS_ProxiedService_Exception( + "If you pass a POST body, you must specify a content type via " + .get_class($this).'->setContentType($contentType).' + ); + } + + $request->makePost(); + if (!empty($this->_body)) { + $request->addHeader('Content-Type: '.$this->_contentType); + $request->addHeader('Content-Length: '.strlen($this->_body)); + $request->setPostBody($this->_body); + } + } + + +} +?> diff --git a/vendor/apereo/phpcas/source/CAS/ProxiedService/Imap.php b/vendor/apereo/phpcas/source/CAS/ProxiedService/Imap.php new file mode 100644 index 0000000000..385aae73b3 --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/ProxiedService/Imap.php @@ -0,0 +1,281 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +/** + * Provides access to a proxy-authenticated IMAP stream + * + * @class CAS_ProxiedService_Imap + * @category Authentication + * @package PhpCAS + * @author Adam Franco + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ +class CAS_ProxiedService_Imap +extends CAS_ProxiedService_Abstract +{ + + /** + * The username to send via imap_open. + * + * @var string $_username; + */ + private $_username; + + /** + * Constructor. + * + * @param string $username Username + * + * @return void + */ + public function __construct ($username) + { + if (!is_string($username) || !strlen($username)) { + throw new CAS_InvalidArgumentException('Invalid username.'); + } + + $this->_username = $username; + } + + /** + * The target service url. + * @var string $_url; + */ + private $_url; + + /** + * Answer a service identifier (URL) for whom we should fetch a proxy ticket. + * + * @return string + * @throws Exception If no service url is available. + */ + public function getServiceUrl () + { + if (empty($this->_url)) { + throw new CAS_ProxiedService_Exception( + 'No URL set via '.get_class($this).'->getServiceUrl($url).' + ); + } + + return $this->_url; + } + + /********************************************************* + * Configure the Stream + *********************************************************/ + + /** + * Set the URL of the service to pass to CAS for proxy-ticket retrieval. + * + * @param string $url Url to set + * + * @return void + * @throws CAS_OutOfSequenceException If called after the stream has been opened. + */ + public function setServiceUrl ($url) + { + if ($this->hasBeenOpened()) { + throw new CAS_OutOfSequenceException( + 'Cannot set the URL, stream already opened.' + ); + } + if (!is_string($url) || !strlen($url)) { + throw new CAS_InvalidArgumentException('Invalid url.'); + } + + $this->_url = $url; + } + + /** + * The mailbox to open. See the $mailbox parameter of imap_open(). + * + * @var string $_mailbox + */ + private $_mailbox; + + /** + * Set the mailbox to open. See the $mailbox parameter of imap_open(). + * + * @param string $mailbox Mailbox to set + * + * @return void + * @throws CAS_OutOfSequenceException If called after the stream has been opened. + */ + public function setMailbox ($mailbox) + { + if ($this->hasBeenOpened()) { + throw new CAS_OutOfSequenceException( + 'Cannot set the mailbox, stream already opened.' + ); + } + if (!is_string($mailbox) || !strlen($mailbox)) { + throw new CAS_InvalidArgumentException('Invalid mailbox.'); + } + + $this->_mailbox = $mailbox; + } + + /** + * A bit mask of options to pass to imap_open() as the $options parameter. + * + * @var int $_options + */ + private $_options = null; + + /** + * Set the options for opening the stream. See the $options parameter of + * imap_open(). + * + * @param int $options Options for the stream + * + * @return void + * @throws CAS_OutOfSequenceException If called after the stream has been opened. + */ + public function setOptions ($options) + { + if ($this->hasBeenOpened()) { + throw new CAS_OutOfSequenceException( + 'Cannot set options, stream already opened.' + ); + } + if (!is_int($options)) { + throw new CAS_InvalidArgumentException('Invalid options.'); + } + + $this->_options = $options; + } + + /********************************************************* + * 2. Open the stream + *********************************************************/ + + /** + * Open the IMAP stream (similar to imap_open()). + * + * @return resource Returns an IMAP stream on success + * @throws CAS_OutOfSequenceException If called multiple times. + * @throws CAS_ProxyTicketException If there is a proxy-ticket failure. + * The code of the Exception will be one of: + * PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE + * PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE + * PHPCAS_SERVICE_PT_FAILURE + * @throws CAS_ProxiedService_Exception If there is a failure sending the + * request to the target service. + */ + public function open () + { + if ($this->hasBeenOpened()) { + throw new CAS_OutOfSequenceException('Stream already opened.'); + } + if (empty($this->_mailbox)) { + throw new CAS_ProxiedService_Exception( + 'You must specify a mailbox via '.get_class($this) + .'->setMailbox($mailbox)' + ); + } + + phpCAS::traceBegin(); + + // Get our proxy ticket and append it to our URL. + $this->initializeProxyTicket(); + phpCAS::trace('opening IMAP mailbox `'.$this->_mailbox.'\'...'); + $this->_stream = @imap_open( + $this->_mailbox, $this->_username, $this->getProxyTicket(), + $this->_options + ); + if ($this->_stream) { + phpCAS::trace('ok'); + } else { + phpCAS::trace('could not open mailbox'); + // @todo add localization integration. + $message = 'IMAP Error: '.$this->_url.' '. var_export(imap_errors(), true); + phpCAS::trace($message); + throw new CAS_ProxiedService_Exception($message); + } + + phpCAS::traceEnd(); + return $this->_stream; + } + + /** + * Answer true if our request has been sent yet. + * + * @return bool + */ + protected function hasBeenOpened () + { + return !empty($this->_stream); + } + + /********************************************************* + * 3. Access the result + *********************************************************/ + /** + * The IMAP stream + * + * @var resource $_stream + */ + private $_stream; + + /** + * Answer the IMAP stream + * + * @return resource + * @throws CAS_OutOfSequenceException if stream is not opened yet + */ + public function getStream () + { + if (!$this->hasBeenOpened()) { + throw new CAS_OutOfSequenceException( + 'Cannot access stream, not opened yet.' + ); + } + return $this->_stream; + } + + /** + * CAS_Client::serviceMail() needs to return the proxy ticket for some reason, + * so this method provides access to it. + * + * @return string + * @throws CAS_OutOfSequenceException If called before the stream has been + * opened. + */ + public function getImapProxyTicket () + { + if (!$this->hasBeenOpened()) { + throw new CAS_OutOfSequenceException( + 'Cannot access errors, stream not opened yet.' + ); + } + return $this->getProxyTicket(); + } +} +?> diff --git a/vendor/apereo/phpcas/source/CAS/ProxiedService/Testable.php b/vendor/apereo/phpcas/source/CAS/ProxiedService/Testable.php new file mode 100644 index 0000000000..51f0767627 --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/ProxiedService/Testable.php @@ -0,0 +1,75 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +/** + * This interface defines methods that allow proxy-authenticated service handlers + * to be tested in unit tests. + * + * Classes implementing this interface SHOULD store the CAS_Client passed and + * initialize themselves with that client rather than via the static phpCAS + * method. For example: + * + * / ** + * * Fetch our proxy ticket. + * * / + * protected function initializeProxyTicket() { + * // Allow usage of a particular CAS_Client for unit testing. + * if (is_null($this->casClient)) + * phpCAS::initializeProxiedService($this); + * else + * $this->casClient->initializeProxiedService($this); + * } + * + * @class CAS_ProxiedService_Testabel + * @category Authentication + * @package PhpCAS + * @author Adam Franco + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ +interface CAS_ProxiedService_Testable +{ + + /** + * Use a particular CAS_Client->initializeProxiedService() rather than the + * static phpCAS::initializeProxiedService(). + * + * This method should not be called in standard operation, but is needed for unit + * testing. + * + * @param CAS_Client $casClient Cas client object + * + * @return void + * @throws CAS_OutOfSequenceException If called after a proxy ticket has + * already been initialized/set. + */ + public function setCasClient (CAS_Client $casClient); + +} +?> diff --git a/vendor/apereo/phpcas/source/CAS/ProxyChain.php b/vendor/apereo/phpcas/source/CAS/ProxyChain.php new file mode 100644 index 0000000000..2594d141e5 --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/ProxyChain.php @@ -0,0 +1,127 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +/** + * A normal proxy-chain definition that lists each level of the chain as either + * a string or regular expression. + * + * @class CAS_ProxyChain + * @category Authentication + * @package PhpCAS + * @author Adam Franco + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +class CAS_ProxyChain +implements CAS_ProxyChain_Interface +{ + + protected $chain = array(); + + /** + * A chain is an array of strings or regexp strings that will be matched + * against. Regexp will be matched with preg_match and strings will be + * matched from the beginning. A string must fully match the beginning of + * an proxy url. So you can define a full domain as acceptable or go further + * down. + * Proxies have to be defined in reverse from the service to the user. If a + * user hits service A get proxied via B to service C the list of acceptable + * proxies on C would be array(B,A); + * + * @param array $chain A chain of proxies + */ + public function __construct(array $chain) + { + // Ensure that we have an indexed array + $this->chain = array_values($chain); + } + + /** + * Match a list of proxies. + * + * @param array $list The list of proxies in front of this service. + * + * @return bool + */ + public function matches(array $list) + { + $list = array_values($list); // Ensure that we have an indexed array + if ($this->isSizeValid($list)) { + $mismatch = false; + foreach ($this->chain as $i => $search) { + $proxy_url = $list[$i]; + if (preg_match('/^\/.*\/[ixASUXu]*$/s', $search)) { + if (preg_match($search, $proxy_url)) { + phpCAS::trace( + "Found regexp " . $search . " matching " . $proxy_url + ); + } else { + phpCAS::trace( + "No regexp match " . $search . " != " . $proxy_url + ); + $mismatch = true; + break; + } + } else { + if (strncasecmp($search, $proxy_url, strlen($search)) == 0) { + phpCAS::trace( + "Found string " . $search . " matching " . $proxy_url + ); + } else { + phpCAS::trace( + "No match " . $search . " != " . $proxy_url + ); + $mismatch = true; + break; + } + } + } + if (!$mismatch) { + phpCAS::trace("Proxy chain matches"); + return true; + } + } else { + phpCAS::trace("Proxy chain skipped: size mismatch"); + } + return false; + } + + /** + * Validate the size of the the list as compared to our chain. + * + * @param array $list List of proxies + * + * @return bool + */ + protected function isSizeValid (array $list) + { + return (sizeof($this->chain) == sizeof($list)); + } +} diff --git a/vendor/apereo/phpcas/source/CAS/ProxyChain/AllowedList.php b/vendor/apereo/phpcas/source/CAS/ProxyChain/AllowedList.php new file mode 100644 index 0000000000..cafd0e743a --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/ProxyChain/AllowedList.php @@ -0,0 +1,119 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + + +/** + * ProxyChain is a container for storing chains of valid proxies that can + * be used to validate proxied requests to a service + * + * @class CAS_ProxyChain_AllowedList + * @category Authentication + * @package PhpCAS + * @author Adam Franco + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +class CAS_ProxyChain_AllowedList +{ + + private $_chains = array(); + + /** + * Check whether proxies are allowed by configuration + * + * @return bool + */ + public function isProxyingAllowed() + { + return (count($this->_chains) > 0); + } + + /** + * Add a chain of proxies to the list of possible chains + * + * @param CAS_ProxyChain_Interface $chain A chain of proxies + * + * @return void + */ + public function allowProxyChain(CAS_ProxyChain_Interface $chain) + { + $this->_chains[] = $chain; + } + + /** + * Check if the proxies found in the response match the allowed proxies + * + * @param array $proxies list of proxies to check + * + * @return bool whether the proxies match the allowed proxies + */ + public function isProxyListAllowed(array $proxies) + { + phpCAS::traceBegin(); + if (empty($proxies)) { + phpCAS::trace("No proxies were found in the response"); + phpCAS::traceEnd(true); + return true; + } elseif (!$this->isProxyingAllowed()) { + phpCAS::trace("Proxies are not allowed"); + phpCAS::traceEnd(false); + return false; + } else { + $res = $this->contains($proxies); + phpCAS::traceEnd($res); + return $res; + } + } + + /** + * Validate the proxies from the proxy ticket validation against the + * chains that were definded. + * + * @param array $list List of proxies from the proxy ticket validation. + * + * @return bool if any chain fully matches the supplied list + */ + public function contains(array $list) + { + phpCAS::traceBegin(); + $count = 0; + foreach ($this->_chains as $chain) { + phpCAS::trace("Checking chain ". $count++); + if ($chain->matches($list)) { + phpCAS::traceEnd(true); + return true; + } + } + phpCAS::trace("No proxy chain matches."); + phpCAS::traceEnd(false); + return false; + } +} +?> diff --git a/vendor/apereo/phpcas/source/CAS/ProxyChain/Any.php b/vendor/apereo/phpcas/source/CAS/ProxyChain/Any.php new file mode 100644 index 0000000000..0cd92f74e9 --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/ProxyChain/Any.php @@ -0,0 +1,64 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +/** + * A proxy-chain definition that will match any list of proxies. + * + * Use this class for quick testing or in certain production screnarios you + * might want to allow allow any other valid service to proxy your service. + * + * THIS CLASS IS HOWEVER NOT RECOMMENDED FOR PRODUCTION AND HAS SECURITY + * IMPLICATIONS: YOU ARE ALLOWING ANY SERVICE TO ACT ON BEHALF OF A USER + * ON THIS SERVICE. + * + * @class CAS_ProxyChain_Any + * @category Authentication + * @package PhpCAS + * @author Adam Franco + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ +class CAS_ProxyChain_Any +implements CAS_ProxyChain_Interface +{ + + /** + * Match a list of proxies. + * + * @param array $list The list of proxies in front of this service. + * + * @return bool + */ + public function matches(array $list) + { + phpCAS::trace("Using CAS_ProxyChain_Any. No proxy validation is performed."); + return true; + } + +} diff --git a/vendor/apereo/phpcas/source/CAS/ProxyChain/Interface.php b/vendor/apereo/phpcas/source/CAS/ProxyChain/Interface.php new file mode 100644 index 0000000000..d247115db3 --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/ProxyChain/Interface.php @@ -0,0 +1,53 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +/** + * An interface for classes that define a list of allowed proxies in front of + * the current application. + * + * @class CAS_ProxyChain_Interface + * @category Authentication + * @package PhpCAS + * @author Adam Franco + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ +interface CAS_ProxyChain_Interface +{ + + /** + * Match a list of proxies. + * + * @param array $list The list of proxies in front of this service. + * + * @return bool + */ + public function matches(array $list); + +} \ No newline at end of file diff --git a/vendor/apereo/phpcas/source/CAS/ProxyChain/Trusted.php b/vendor/apereo/phpcas/source/CAS/ProxyChain/Trusted.php new file mode 100644 index 0000000000..7fa6129677 --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/ProxyChain/Trusted.php @@ -0,0 +1,59 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +/** + * A proxy-chain definition that defines a chain up to a trusted proxy and + * delegates the resposibility of validating the rest of the chain to that + * trusted proxy. + * + * @class CAS_ProxyChain_Trusted + * @category Authentication + * @package PhpCAS + * @author Adam Franco + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ +class CAS_ProxyChain_Trusted +extends CAS_ProxyChain +implements CAS_ProxyChain_Interface +{ + + /** + * Validate the size of the the list as compared to our chain. + * + * @param array $list list of proxies + * + * @return bool + */ + protected function isSizeValid (array $list) + { + return (sizeof($this->chain) <= sizeof($list)); + } + +} diff --git a/vendor/apereo/phpcas/source/CAS/ProxyTicketException.php b/vendor/apereo/phpcas/source/CAS/ProxyTicketException.php new file mode 100644 index 0000000000..723304666d --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/ProxyTicketException.php @@ -0,0 +1,71 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + * + */ + +/** + * An Exception for errors related to fetching or validating proxy tickets. + * + * @class CAS_ProxyTicketException + * @category Authentication + * @package PhpCAS + * @author Adam Franco + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ +class CAS_ProxyTicketException +extends BadMethodCallException +implements CAS_Exception +{ + + /** + * Constructor + * + * @param string $message Message text + * @param int $code Error code + * + * @return void + */ + public function __construct ($message, $code = PHPCAS_SERVICE_PT_FAILURE) + { + // Warn if the code is not in our allowed list + $ptCodes = array( + PHPCAS_SERVICE_PT_FAILURE, + PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE, + PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE, + ); + if (!in_array($code, $ptCodes)) { + trigger_error( + 'Invalid code '.$code + .' passed. Must be one of PHPCAS_SERVICE_PT_FAILURE, PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE, or PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE.' + ); + } + + parent::__construct($message, $code); + } +} diff --git a/vendor/apereo/phpcas/source/CAS/Request/AbstractRequest.php b/vendor/apereo/phpcas/source/CAS/Request/AbstractRequest.php new file mode 100644 index 0000000000..130024bf15 --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/Request/AbstractRequest.php @@ -0,0 +1,380 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +/** + * Provides support for performing web-requests via curl + * + * @class CAS_Request_AbstractRequest + * @category Authentication + * @package PhpCAS + * @author Adam Franco + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ +abstract class CAS_Request_AbstractRequest +implements CAS_Request_RequestInterface +{ + + protected $url = null; + protected $cookies = array(); + protected $headers = array(); + protected $isPost = false; + protected $postBody = null; + protected $caCertPath = null; + protected $validateCN = true; + private $_sent = false; + private $_responseHeaders = array(); + private $_responseBody = null; + private $_errorMessage = ''; + + /********************************************************* + * Configure the Request + *********************************************************/ + + /** + * Set the URL of the Request + * + * @param string $url Url to set + * + * @return void + * @throws CAS_OutOfSequenceException If called after the Request has been sent. + */ + public function setUrl ($url) + { + if ($this->_sent) { + throw new CAS_OutOfSequenceException( + 'Request has already been sent cannot '.__METHOD__ + ); + } + + $this->url = $url; + } + + /** + * Add a cookie to the request. + * + * @param string $name Name of entry + * @param string $value value of entry + * + * @return void + * @throws CAS_OutOfSequenceException If called after the Request has been sent. + */ + public function addCookie ($name, $value) + { + if ($this->_sent) { + throw new CAS_OutOfSequenceException( + 'Request has already been sent cannot '.__METHOD__ + ); + } + + $this->cookies[$name] = $value; + } + + /** + * Add an array of cookies to the request. + * The cookie array is of the form + * array('cookie_name' => 'cookie_value', 'cookie_name2' => cookie_value2') + * + * @param array $cookies cookies to add + * + * @return void + * @throws CAS_OutOfSequenceException If called after the Request has been sent. + */ + public function addCookies (array $cookies) + { + if ($this->_sent) { + throw new CAS_OutOfSequenceException( + 'Request has already been sent cannot '.__METHOD__ + ); + } + + $this->cookies = array_merge($this->cookies, $cookies); + } + + /** + * Add a header string to the request. + * + * @param string $header Header to add + * + * @return void + * @throws CAS_OutOfSequenceException If called after the Request has been sent. + */ + public function addHeader ($header) + { + if ($this->_sent) { + throw new CAS_OutOfSequenceException( + 'Request has already been sent cannot '.__METHOD__ + ); + } + + $this->headers[] = $header; + } + + /** + * Add an array of header strings to the request. + * + * @param array $headers headers to add + * + * @return void + * @throws CAS_OutOfSequenceException If called after the Request has been sent. + */ + public function addHeaders (array $headers) + { + if ($this->_sent) { + throw new CAS_OutOfSequenceException( + 'Request has already been sent cannot '.__METHOD__ + ); + } + + $this->headers = array_merge($this->headers, $headers); + } + + /** + * Make the request a POST request rather than the default GET request. + * + * @return void + * @throws CAS_OutOfSequenceException If called after the Request has been sent. + */ + public function makePost () + { + if ($this->_sent) { + throw new CAS_OutOfSequenceException( + 'Request has already been sent cannot '.__METHOD__ + ); + } + + $this->isPost = true; + } + + /** + * Add a POST body to the request + * + * @param string $body body to add + * + * @return void + * @throws CAS_OutOfSequenceException If called after the Request has been sent. + */ + public function setPostBody ($body) + { + if ($this->_sent) { + throw new CAS_OutOfSequenceException( + 'Request has already been sent cannot '.__METHOD__ + ); + } + if (!$this->isPost) { + throw new CAS_OutOfSequenceException( + 'Cannot add a POST body to a GET request, use makePost() first.' + ); + } + + $this->postBody = $body; + } + + /** + * Specify the path to an SSL CA certificate to validate the server with. + * + * @param string $caCertPath path to cert + * @param bool $validate_cn valdiate CN of certificate + * + * @return void + * @throws CAS_OutOfSequenceException If called after the Request has been sent. + */ + public function setSslCaCert ($caCertPath,$validate_cn=true) + { + if ($this->_sent) { + throw new CAS_OutOfSequenceException( + 'Request has already been sent cannot '.__METHOD__ + ); + } + $this->caCertPath = $caCertPath; + $this->validateCN = $validate_cn; + } + + /********************************************************* + * 2. Send the Request + *********************************************************/ + + /** + * Perform the request. + * + * @return bool TRUE on success, FALSE on failure. + * @throws CAS_OutOfSequenceException If called multiple times. + */ + public function send () + { + if ($this->_sent) { + throw new CAS_OutOfSequenceException( + 'Request has already been sent cannot send again.' + ); + } + if (is_null($this->url) || !$this->url) { + throw new CAS_OutOfSequenceException( + 'A url must be specified via setUrl() before the request can be sent.' + ); + } + $this->_sent = true; + return $this->sendRequest(); + } + + /** + * Send the request and store the results. + * + * @return bool TRUE on success, FALSE on failure. + */ + abstract protected function sendRequest (); + + /** + * Store the response headers. + * + * @param array $headers headers to store + * + * @return void + */ + protected function storeResponseHeaders (array $headers) + { + $this->_responseHeaders = array_merge($this->_responseHeaders, $headers); + } + + /** + * Store a single response header to our array. + * + * @param string $header header to store + * + * @return void + */ + protected function storeResponseHeader ($header) + { + $this->_responseHeaders[] = $header; + } + + /** + * Store the response body. + * + * @param string $body body to store + * + * @return void + */ + protected function storeResponseBody ($body) + { + $this->_responseBody = $body; + } + + /** + * Add a string to our error message. + * + * @param string $message message to add + * + * @return void + */ + protected function storeErrorMessage ($message) + { + $this->_errorMessage .= $message; + } + + /********************************************************* + * 3. Access the response + *********************************************************/ + + /** + * Answer the headers of the response. + * + * @return array An array of header strings. + * @throws CAS_OutOfSequenceException If called before the Request has been sent. + */ + public function getResponseHeaders () + { + if (!$this->_sent) { + throw new CAS_OutOfSequenceException( + 'Request has not been sent yet. Cannot '.__METHOD__ + ); + } + return $this->_responseHeaders; + } + + /** + * Answer HTTP status code of the response + * + * @return int + * @throws CAS_OutOfSequenceException If called before the Request has been sent. + * @throws CAS_Request_Exception if the response did not contain a status code + */ + public function getResponseStatusCode () + { + if (!$this->_sent) { + throw new CAS_OutOfSequenceException( + 'Request has not been sent yet. Cannot '.__METHOD__ + ); + } + + if (!preg_match( + '/HTTP\/[0-9.]+\s+([0-9]+)\s*(.*)/', + $this->_responseHeaders[0], $matches + ) + ) { + throw new CAS_Request_Exception( + 'Bad response, no status code was found in the first line.' + ); + } + + return intval($matches[1]); + } + + /** + * Answer the body of response. + * + * @return string + * @throws CAS_OutOfSequenceException If called before the Request has been sent. + */ + public function getResponseBody () + { + if (!$this->_sent) { + throw new CAS_OutOfSequenceException( + 'Request has not been sent yet. Cannot '.__METHOD__ + ); + } + + return $this->_responseBody; + } + + /** + * Answer a message describing any errors if the request failed. + * + * @return string + * @throws CAS_OutOfSequenceException If called before the Request has been sent. + */ + public function getErrorMessage () + { + if (!$this->_sent) { + throw new CAS_OutOfSequenceException( + 'Request has not been sent yet. Cannot '.__METHOD__ + ); + } + return $this->_errorMessage; + } +} diff --git a/vendor/apereo/phpcas/source/CAS/Request/CurlMultiRequest.php b/vendor/apereo/phpcas/source/CAS/Request/CurlMultiRequest.php new file mode 100644 index 0000000000..919c9561d1 --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/Request/CurlMultiRequest.php @@ -0,0 +1,147 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +/** + * This interface defines a class library for performing multiple web requests + * in batches. Implementations of this interface may perform requests serially + * or in parallel. + * + * @class CAS_Request_CurlMultiRequest + * @category Authentication + * @package PhpCAS + * @author Adam Franco + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ +class CAS_Request_CurlMultiRequest +implements CAS_Request_MultiRequestInterface +{ + private $_requests = array(); + private $_sent = false; + + /********************************************************* + * Add Requests + *********************************************************/ + + /** + * Add a new Request to this batch. + * Note, implementations will likely restrict requests to their own concrete + * class hierarchy. + * + * @param CAS_Request_RequestInterface $request reqest to add + * + * @return void + * @throws CAS_OutOfSequenceException If called after the Request has been sent. + * @throws CAS_InvalidArgumentException If passed a Request of the wrong + * implmentation. + */ + public function addRequest (CAS_Request_RequestInterface $request) + { + if ($this->_sent) { + throw new CAS_OutOfSequenceException( + 'Request has already been sent cannot '.__METHOD__ + ); + } + if (!$request instanceof CAS_Request_CurlRequest) { + throw new CAS_InvalidArgumentException( + 'As a CAS_Request_CurlMultiRequest, I can only work with CAS_Request_CurlRequest objects.' + ); + } + + $this->_requests[] = $request; + } + + /** + * Retrieve the number of requests added to this batch. + * + * @return int number of request elements + * @throws CAS_OutOfSequenceException if the request has already been sent + */ + public function getNumRequests() + { + if ($this->_sent) { + throw new CAS_OutOfSequenceException( + 'Request has already been sent cannot '.__METHOD__ + ); + } + return count($this->_requests); + } + + /********************************************************* + * 2. Send the Request + *********************************************************/ + + /** + * Perform the request. After sending, all requests will have their + * responses poulated. + * + * @return bool TRUE on success, FALSE on failure. + * @throws CAS_OutOfSequenceException If called multiple times. + */ + public function send () + { + if ($this->_sent) { + throw new CAS_OutOfSequenceException( + 'Request has already been sent cannot send again.' + ); + } + if (!count($this->_requests)) { + throw new CAS_OutOfSequenceException( + 'At least one request must be added via addRequest() before the multi-request can be sent.' + ); + } + + $this->_sent = true; + + // Initialize our handles and configure all requests. + $handles = array(); + $multiHandle = curl_multi_init(); + foreach ($this->_requests as $i => $request) { + $handle = $request->initAndConfigure(); + curl_setopt($handle, CURLOPT_RETURNTRANSFER, true); + $handles[$i] = $handle; + curl_multi_add_handle($multiHandle, $handle); + } + + // Execute the requests in parallel. + do { + curl_multi_exec($multiHandle, $running); + } while ($running > 0); + + // Populate all of the responses or errors back into the request objects. + foreach ($this->_requests as $i => $request) { + $buf = curl_multi_getcontent($handles[$i]); + $request->_storeResponseBody($buf); + curl_multi_remove_handle($multiHandle, $handles[$i]); + curl_close($handles[$i]); + } + + curl_multi_close($multiHandle); + } +} diff --git a/vendor/apereo/phpcas/source/CAS/Request/CurlRequest.php b/vendor/apereo/phpcas/source/CAS/Request/CurlRequest.php new file mode 100644 index 0000000000..70057712ed --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/Request/CurlRequest.php @@ -0,0 +1,200 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +/** + * Provides support for performing web-requests via curl + * + * @class CAS_Request_CurlRequest + * @category Authentication + * @package PhpCAS + * @author Adam Franco + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ +class CAS_Request_CurlRequest +extends CAS_Request_AbstractRequest +implements CAS_Request_RequestInterface +{ + + /** + * Set additional curl options + * + * @param array $options option to set + * + * @return void + */ + public function setCurlOptions (array $options) + { + $this->_curlOptions = $options; + } + private $_curlOptions = array(); + + /** + * Send the request and store the results. + * + * @return bool true on success, false on failure. + */ + protected function sendRequest () + { + phpCAS::traceBegin(); + + /********************************************************* + * initialize the CURL session + *********************************************************/ + $ch = $this->initAndConfigure(); + + /********************************************************* + * Perform the query + *********************************************************/ + $buf = curl_exec($ch); + if ( $buf === false ) { + phpCAS::trace('curl_exec() failed'); + $this->storeErrorMessage( + 'CURL error #'.curl_errno($ch).': '.curl_error($ch) + ); + $res = false; + } else { + $this->storeResponseBody($buf); + phpCAS::trace("Response Body: \n".$buf."\n"); + $res = true; + + } + // close the CURL session + curl_close($ch); + + phpCAS::traceEnd($res); + return $res; + } + + /** + * Internal method to initialize our cURL handle and configure the request. + * This method should NOT be used outside of the CurlRequest or the + * CurlMultiRequest. + * + * @return resource|false The cURL handle on success, false on failure + */ + public function initAndConfigure() + { + /********************************************************* + * initialize the CURL session + *********************************************************/ + $ch = curl_init($this->url); + + if (version_compare(PHP_VERSION, '5.1.3', '>=')) { + //only avaible in php5 + curl_setopt_array($ch, $this->_curlOptions); + } else { + foreach ($this->_curlOptions as $key => $value) { + curl_setopt($ch, $key, $value); + } + } + + /********************************************************* + * Set SSL configuration + *********************************************************/ + if ($this->caCertPath) { + if ($this->validateCN) { + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); + } else { + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); + } + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1); + curl_setopt($ch, CURLOPT_CAINFO, $this->caCertPath); + phpCAS::trace('CURL: Set CURLOPT_CAINFO ' . $this->caCertPath); + } else { + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); + } + + /********************************************************* + * Configure curl to capture our output. + *********************************************************/ + // return the CURL output into a variable + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + + // get the HTTP header with a callback + curl_setopt($ch, CURLOPT_HEADERFUNCTION, array($this, '_curlReadHeaders')); + + /********************************************************* + * Add cookie headers to our request. + *********************************************************/ + if (count($this->cookies)) { + $cookieStrings = array(); + foreach ($this->cookies as $name => $val) { + $cookieStrings[] = $name.'='.$val; + } + curl_setopt($ch, CURLOPT_COOKIE, implode(';', $cookieStrings)); + } + + /********************************************************* + * Add any additional headers + *********************************************************/ + if (count($this->headers)) { + curl_setopt($ch, CURLOPT_HTTPHEADER, $this->headers); + } + + /********************************************************* + * Flag and Body for POST requests + *********************************************************/ + if ($this->isPost) { + curl_setopt($ch, CURLOPT_POST, 1); + curl_setopt($ch, CURLOPT_POSTFIELDS, $this->postBody); + } + + return $ch; + } + + /** + * Store the response body. + * This method should NOT be used outside of the CurlRequest or the + * CurlMultiRequest. + * + * @param string $body body to stor + * + * @return void + */ + private function _storeResponseBody ($body) + { + $this->storeResponseBody($body); + } + + /** + * Internal method for capturing the headers from a curl request. + * + * @param resource $ch handle of curl + * @param string $header header + * + * @return int + */ + private function _curlReadHeaders ($ch, $header) + { + $this->storeResponseHeader($header); + return strlen($header); + } +} diff --git a/vendor/apereo/phpcas/source/CAS/Request/Exception.php b/vendor/apereo/phpcas/source/CAS/Request/Exception.php new file mode 100644 index 0000000000..14ff3c6b0d --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/Request/Exception.php @@ -0,0 +1,45 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +/** + * An Exception for problems performing requests + * + * @class CAS_Request_Exception + * @category Authentication + * @package PhpCAS + * @author Adam Franco + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ +class CAS_Request_Exception +extends Exception +implements CAS_Exception +{ + +} diff --git a/vendor/apereo/phpcas/source/CAS/Request/MultiRequestInterface.php b/vendor/apereo/phpcas/source/CAS/Request/MultiRequestInterface.php new file mode 100644 index 0000000000..f3298274db --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/Request/MultiRequestInterface.php @@ -0,0 +1,83 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +/** + * This interface defines a class library for performing multiple web requests + * in batches. Implementations of this interface may perform requests serially + * or in parallel. + * + * @class CAS_Request_MultiRequestInterface + * @category Authentication + * @package PhpCAS + * @author Adam Franco + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ +interface CAS_Request_MultiRequestInterface +{ + + /********************************************************* + * Add Requests + *********************************************************/ + + /** + * Add a new Request to this batch. + * Note, implementations will likely restrict requests to their own concrete + * class hierarchy. + * + * @param CAS_Request_RequestInterface $request request interface + * + * @return void + * @throws CAS_OutOfSequenceException If called after the Request has been + * sent. + * @throws CAS_InvalidArgumentException If passed a Request of the wrong + * implmentation. + */ + public function addRequest (CAS_Request_RequestInterface $request); + + /** + * Retrieve the number of requests added to this batch. + * + * @return int number of request elements + */ + public function getNumRequests (); + + /********************************************************* + * 2. Send the Request + *********************************************************/ + + /** + * Perform the request. After sending, all requests will have their + * responses poulated. + * + * @return bool TRUE on success, FALSE on failure. + * @throws CAS_OutOfSequenceException If called multiple times. + */ + public function send (); +} diff --git a/vendor/apereo/phpcas/source/CAS/Request/RequestInterface.php b/vendor/apereo/phpcas/source/CAS/Request/RequestInterface.php new file mode 100644 index 0000000000..cc11ba43d9 --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/Request/RequestInterface.php @@ -0,0 +1,179 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +/** + * This interface defines a class library for performing web requests. + * + * @class CAS_Request_RequestInterface + * @category Authentication + * @package PhpCAS + * @author Adam Franco + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ +interface CAS_Request_RequestInterface +{ + + /********************************************************* + * Configure the Request + *********************************************************/ + + /** + * Set the URL of the Request + * + * @param string $url url to set + * + * @return void + * @throws CAS_OutOfSequenceException If called after the Request has been sent. + */ + public function setUrl ($url); + + /** + * Add a cookie to the request. + * + * @param string $name name of cookie + * @param string $value value of cookie + * + * @return void + * @throws CAS_OutOfSequenceException If called after the Request has been sent. + */ + public function addCookie ($name, $value); + + /** + * Add an array of cookies to the request. + * The cookie array is of the form + * array('cookie_name' => 'cookie_value', 'cookie_name2' => cookie_value2') + * + * @param array $cookies cookies to add + * + * @return void + * @throws CAS_OutOfSequenceException If called after the Request has been sent. + */ + public function addCookies (array $cookies); + + /** + * Add a header string to the request. + * + * @param string $header header to add + * + * @return void + * @throws CAS_OutOfSequenceException If called after the Request has been sent. + */ + public function addHeader ($header); + + /** + * Add an array of header strings to the request. + * + * @param array $headers headers to add + * + * @return void + * @throws CAS_OutOfSequenceException If called after the Request has been sent. + */ + public function addHeaders (array $headers); + + /** + * Make the request a POST request rather than the default GET request. + * + * @return void + * @throws CAS_OutOfSequenceException If called after the Request has been sent. + */ + public function makePost (); + + /** + * Add a POST body to the request + * + * @param string $body body to add + * + * @return void + * @throws CAS_OutOfSequenceException If called after the Request has been sent. + */ + public function setPostBody ($body); + + + /** + * Specify the path to an SSL CA certificate to validate the server with. + * + * @param string $caCertPath path to cert file + * @param boolean $validate_cn validate CN of SSL certificate + * + * @return void + * @throws CAS_OutOfSequenceException If called after the Request has been sent. + */ + public function setSslCaCert ($caCertPath, $validate_cn = true); + + + + /********************************************************* + * 2. Send the Request + *********************************************************/ + + /** + * Perform the request. + * + * @return bool TRUE on success, FALSE on failure. + * @throws CAS_OutOfSequenceException If called multiple times. + */ + public function send (); + + /********************************************************* + * 3. Access the response + *********************************************************/ + + /** + * Answer the headers of the response. + * + * @return array An array of header strings. + * @throws CAS_OutOfSequenceException If called before the Request has been sent. + */ + public function getResponseHeaders (); + + /** + * Answer HTTP status code of the response + * + * @return int + * @throws CAS_OutOfSequenceException If called before the Request has been sent. + */ + public function getResponseStatusCode (); + + /** + * Answer the body of response. + * + * @return string + * @throws CAS_OutOfSequenceException If called before the Request has been sent. + */ + public function getResponseBody (); + + /** + * Answer a message describing any errors if the request failed. + * + * @return string + * @throws CAS_OutOfSequenceException If called before the Request has been sent. + */ + public function getErrorMessage (); +} diff --git a/vendor/apereo/phpcas/source/CAS/TypeMismatchException.php b/vendor/apereo/phpcas/source/CAS/TypeMismatchException.php new file mode 100644 index 0000000000..4a13c2df45 --- /dev/null +++ b/vendor/apereo/phpcas/source/CAS/TypeMismatchException.php @@ -0,0 +1,70 @@ + + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ + +/** + * Exception that denotes invalid arguments were passed. + * + * @class CAS_InvalidArgumentException + * @category Authentication + * @package PhpCAS + * @author Adam Franco + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ +class CAS_TypeMismatchException +extends CAS_InvalidArgumentException +{ + /** + * Constructor, provides a nice message. + * + * @param mixed $argument Argument + * @param string $argumentName Argument Name + * @param string $type Type + * @param string $message Error Message + * @param integer $code Code + * + * @return void + */ + public function __construct ( + $argument, $argumentName, $type, $message = '', $code = 0 + ) { + if (is_object($argument)) { + $foundType = get_class($argument).' object'; + } else { + $foundType = gettype($argument); + } + + parent::__construct( + 'type mismatched for parameter ' + . $argumentName . ' (should be \'' . $type .' \'), ' + . $foundType . ' given. ' . $message, $code + ); + } +} +?> diff --git a/vendor/autoload.php b/vendor/autoload.php index 6ce6ae5a8c..9f1dec3960 100644 --- a/vendor/autoload.php +++ b/vendor/autoload.php @@ -4,4 +4,4 @@ require_once __DIR__ . '/composer/autoload_real.php'; -return ComposerAutoloaderInit4f5ec3b37be240134637564819b99dd2::getLoader(); +return ComposerAutoloaderInit444c3f31864f68a3f466e2c19837e185::getLoader(); diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index d636b946d3..b646a79831 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -101,6 +101,50 @@ return array( 'Auth_Yadis_Yadis' => $vendorDir . '/openid/php-openid/Auth/Yadis/Yadis.php', 'Auth_Yadis_dom' => $vendorDir . '/openid/php-openid/Auth/Yadis/XML.php', 'Auth_Yadis_domxml' => $vendorDir . '/openid/php-openid/Auth/Yadis/XML.php', + 'CAS_AuthenticationException' => $vendorDir . '/apereo/phpcas/source/CAS/AuthenticationException.php', + 'CAS_Client' => $vendorDir . '/apereo/phpcas/source/CAS/Client.php', + 'CAS_CookieJar' => $vendorDir . '/apereo/phpcas/source/CAS/CookieJar.php', + 'CAS_Exception' => $vendorDir . '/apereo/phpcas/source/CAS/Exception.php', + 'CAS_GracefullTerminationException' => $vendorDir . '/apereo/phpcas/source/CAS/GracefullTerminationException.php', + 'CAS_InvalidArgumentException' => $vendorDir . '/apereo/phpcas/source/CAS/InvalidArgumentException.php', + 'CAS_Languages_Catalan' => $vendorDir . '/apereo/phpcas/source/CAS/Languages/Catalan.php', + 'CAS_Languages_ChineseSimplified' => $vendorDir . '/apereo/phpcas/source/CAS/Languages/ChineseSimplified.php', + 'CAS_Languages_English' => $vendorDir . '/apereo/phpcas/source/CAS/Languages/English.php', + 'CAS_Languages_French' => $vendorDir . '/apereo/phpcas/source/CAS/Languages/French.php', + 'CAS_Languages_German' => $vendorDir . '/apereo/phpcas/source/CAS/Languages/German.php', + 'CAS_Languages_Greek' => $vendorDir . '/apereo/phpcas/source/CAS/Languages/Greek.php', + 'CAS_Languages_Japanese' => $vendorDir . '/apereo/phpcas/source/CAS/Languages/Japanese.php', + 'CAS_Languages_LanguageInterface' => $vendorDir . '/apereo/phpcas/source/CAS/Languages/LanguageInterface.php', + 'CAS_Languages_Spanish' => $vendorDir . '/apereo/phpcas/source/CAS/Languages/Spanish.php', + 'CAS_OutOfSequenceBeforeAuthenticationCallException' => $vendorDir . '/apereo/phpcas/source/CAS/OutOfSequenceBeforeAuthenticationCallException.php', + 'CAS_OutOfSequenceBeforeClientException' => $vendorDir . '/apereo/phpcas/source/CAS/OutOfSequenceBeforeClientException.php', + 'CAS_OutOfSequenceBeforeProxyException' => $vendorDir . '/apereo/phpcas/source/CAS/OutOfSequenceBeforeProxyException.php', + 'CAS_OutOfSequenceException' => $vendorDir . '/apereo/phpcas/source/CAS/OutOfSequenceException.php', + 'CAS_PGTStorage_AbstractStorage' => $vendorDir . '/apereo/phpcas/source/CAS/PGTStorage/AbstractStorage.php', + 'CAS_PGTStorage_Db' => $vendorDir . '/apereo/phpcas/source/CAS/PGTStorage/Db.php', + 'CAS_PGTStorage_File' => $vendorDir . '/apereo/phpcas/source/CAS/PGTStorage/File.php', + 'CAS_ProxiedService' => $vendorDir . '/apereo/phpcas/source/CAS/ProxiedService.php', + 'CAS_ProxiedService_Abstract' => $vendorDir . '/apereo/phpcas/source/CAS/ProxiedService/Abstract.php', + 'CAS_ProxiedService_Exception' => $vendorDir . '/apereo/phpcas/source/CAS/ProxiedService/Exception.php', + 'CAS_ProxiedService_Http' => $vendorDir . '/apereo/phpcas/source/CAS/ProxiedService/Http.php', + 'CAS_ProxiedService_Http_Abstract' => $vendorDir . '/apereo/phpcas/source/CAS/ProxiedService/Http/Abstract.php', + 'CAS_ProxiedService_Http_Get' => $vendorDir . '/apereo/phpcas/source/CAS/ProxiedService/Http/Get.php', + 'CAS_ProxiedService_Http_Post' => $vendorDir . '/apereo/phpcas/source/CAS/ProxiedService/Http/Post.php', + 'CAS_ProxiedService_Imap' => $vendorDir . '/apereo/phpcas/source/CAS/ProxiedService/Imap.php', + 'CAS_ProxiedService_Testable' => $vendorDir . '/apereo/phpcas/source/CAS/ProxiedService/Testable.php', + 'CAS_ProxyChain' => $vendorDir . '/apereo/phpcas/source/CAS/ProxyChain.php', + 'CAS_ProxyChain_AllowedList' => $vendorDir . '/apereo/phpcas/source/CAS/ProxyChain/AllowedList.php', + 'CAS_ProxyChain_Any' => $vendorDir . '/apereo/phpcas/source/CAS/ProxyChain/Any.php', + 'CAS_ProxyChain_Interface' => $vendorDir . '/apereo/phpcas/source/CAS/ProxyChain/Interface.php', + 'CAS_ProxyChain_Trusted' => $vendorDir . '/apereo/phpcas/source/CAS/ProxyChain/Trusted.php', + 'CAS_ProxyTicketException' => $vendorDir . '/apereo/phpcas/source/CAS/ProxyTicketException.php', + 'CAS_Request_AbstractRequest' => $vendorDir . '/apereo/phpcas/source/CAS/Request/AbstractRequest.php', + 'CAS_Request_CurlMultiRequest' => $vendorDir . '/apereo/phpcas/source/CAS/Request/CurlMultiRequest.php', + 'CAS_Request_CurlRequest' => $vendorDir . '/apereo/phpcas/source/CAS/Request/CurlRequest.php', + 'CAS_Request_Exception' => $vendorDir . '/apereo/phpcas/source/CAS/Request/Exception.php', + 'CAS_Request_MultiRequestInterface' => $vendorDir . '/apereo/phpcas/source/CAS/Request/MultiRequestInterface.php', + 'CAS_Request_RequestInterface' => $vendorDir . '/apereo/phpcas/source/CAS/Request/RequestInterface.php', + 'CAS_TypeMismatchException' => $vendorDir . '/apereo/phpcas/source/CAS/TypeMismatchException.php', 'HTMLPurifier' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier.php', 'HTMLPurifier_Arborize' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Arborize.php', 'HTMLPurifier_AttrCollections' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrCollections.php', @@ -355,4 +399,95 @@ return array( 'Masterminds\\HTML5\\Serializer\\OutputRules' => $vendorDir . '/masterminds/html5/src/HTML5/Serializer/OutputRules.php', 'Masterminds\\HTML5\\Serializer\\RulesInterface' => $vendorDir . '/masterminds/html5/src/HTML5/Serializer/RulesInterface.php', 'Masterminds\\HTML5\\Serializer\\Traverser' => $vendorDir . '/masterminds/html5/src/HTML5/Serializer/Traverser.php', + 'Michelf\\Markdown' => $vendorDir . '/michelf/php-markdown/Michelf/Markdown.php', + 'Michelf\\MarkdownExtra' => $vendorDir . '/michelf/php-markdown/Michelf/MarkdownExtra.php', + 'Michelf\\MarkdownInterface' => $vendorDir . '/michelf/php-markdown/Michelf/MarkdownInterface.php', + 'ParagonIE\\ConstantTime\\Base32' => $vendorDir . '/paragonie/constant_time_encoding/src/Base32.php', + 'ParagonIE\\ConstantTime\\Base32Hex' => $vendorDir . '/paragonie/constant_time_encoding/src/Base32Hex.php', + 'ParagonIE\\ConstantTime\\Base64' => $vendorDir . '/paragonie/constant_time_encoding/src/Base64.php', + 'ParagonIE\\ConstantTime\\Base64DotSlash' => $vendorDir . '/paragonie/constant_time_encoding/src/Base64DotSlash.php', + 'ParagonIE\\ConstantTime\\Base64DotSlashOrdered' => $vendorDir . '/paragonie/constant_time_encoding/src/Base64DotSlashOrdered.php', + 'ParagonIE\\ConstantTime\\Base64UrlSafe' => $vendorDir . '/paragonie/constant_time_encoding/src/Base64UrlSafe.php', + 'ParagonIE\\ConstantTime\\Binary' => $vendorDir . '/paragonie/constant_time_encoding/src/Binary.php', + 'ParagonIE\\ConstantTime\\EncoderInterface' => $vendorDir . '/paragonie/constant_time_encoding/src/EncoderInterface.php', + 'ParagonIE\\ConstantTime\\Encoding' => $vendorDir . '/paragonie/constant_time_encoding/src/Encoding.php', + 'ParagonIE\\ConstantTime\\Hex' => $vendorDir . '/paragonie/constant_time_encoding/src/Hex.php', + 'ParagonIE\\ConstantTime\\RFC4648' => $vendorDir . '/paragonie/constant_time_encoding/src/RFC4648.php', + 'Stomp\\Broker\\ActiveMq\\ActiveMq' => $vendorDir . '/stomp-php/stomp-php/src/Broker/ActiveMq/ActiveMq.php', + 'Stomp\\Broker\\ActiveMq\\Mode\\ActiveMqMode' => $vendorDir . '/stomp-php/stomp-php/src/Broker/ActiveMq/Mode/ActiveMqMode.php', + 'Stomp\\Broker\\ActiveMq\\Mode\\DurableSubscription' => $vendorDir . '/stomp-php/stomp-php/src/Broker/ActiveMq/Mode/DurableSubscription.php', + 'Stomp\\Broker\\ActiveMq\\Options' => $vendorDir . '/stomp-php/stomp-php/src/Broker/ActiveMq/Options.php', + 'Stomp\\Broker\\Apollo\\Apollo' => $vendorDir . '/stomp-php/stomp-php/src/Broker/Apollo/Apollo.php', + 'Stomp\\Broker\\Apollo\\Mode\\QueueBrowser' => $vendorDir . '/stomp-php/stomp-php/src/Broker/Apollo/Mode/QueueBrowser.php', + 'Stomp\\Broker\\Apollo\\Mode\\SequenceQueueBrowser' => $vendorDir . '/stomp-php/stomp-php/src/Broker/Apollo/Mode/SequenceQueueBrowser.php', + 'Stomp\\Broker\\Exception\\UnsupportedBrokerException' => $vendorDir . '/stomp-php/stomp-php/src/Broker/Exception/UnsupportedBrokerException.php', + 'Stomp\\Broker\\OpenMq\\OpenMq' => $vendorDir . '/stomp-php/stomp-php/src/Broker/OpenMq/OpenMq.php', + 'Stomp\\Broker\\RabbitMq\\RabbitMq' => $vendorDir . '/stomp-php/stomp-php/src/Broker/RabbitMq/RabbitMq.php', + 'Stomp\\Client' => $vendorDir . '/stomp-php/stomp-php/src/Client.php', + 'Stomp\\Exception\\ConnectionException' => $vendorDir . '/stomp-php/stomp-php/src/Exception/ConnectionException.php', + 'Stomp\\Exception\\ErrorFrameException' => $vendorDir . '/stomp-php/stomp-php/src/Exception/ErrorFrameException.php', + 'Stomp\\Exception\\MissingReceiptException' => $vendorDir . '/stomp-php/stomp-php/src/Exception/MissingReceiptException.php', + 'Stomp\\Exception\\StompException' => $vendorDir . '/stomp-php/stomp-php/src/Exception/StompException.php', + 'Stomp\\Exception\\UnexpectedResponseException' => $vendorDir . '/stomp-php/stomp-php/src/Exception/UnexpectedResponseException.php', + 'Stomp\\Network\\Connection' => $vendorDir . '/stomp-php/stomp-php/src/Network/Connection.php', + 'Stomp\\Network\\Observer\\AbstractBeats' => $vendorDir . '/stomp-php/stomp-php/src/Network/Observer/AbstractBeats.php', + 'Stomp\\Network\\Observer\\ConnectionObserver' => $vendorDir . '/stomp-php/stomp-php/src/Network/Observer/ConnectionObserver.php', + 'Stomp\\Network\\Observer\\ConnectionObserverCollection' => $vendorDir . '/stomp-php/stomp-php/src/Network/Observer/ConnectionObserverCollection.php', + 'Stomp\\Network\\Observer\\Exception\\HeartbeatException' => $vendorDir . '/stomp-php/stomp-php/src/Network/Observer/Exception/HeartbeatException.php', + 'Stomp\\Network\\Observer\\HeartbeatEmitter' => $vendorDir . '/stomp-php/stomp-php/src/Network/Observer/HeartbeatEmitter.php', + 'Stomp\\Network\\Observer\\ServerAliveObserver' => $vendorDir . '/stomp-php/stomp-php/src/Network/Observer/ServerAliveObserver.php', + 'Stomp\\Protocol\\Protocol' => $vendorDir . '/stomp-php/stomp-php/src/Protocol/Protocol.php', + 'Stomp\\Protocol\\Version' => $vendorDir . '/stomp-php/stomp-php/src/Protocol/Version.php', + 'Stomp\\SimpleStomp' => $vendorDir . '/stomp-php/stomp-php/src/SimpleStomp.php', + 'Stomp\\StatefulStomp' => $vendorDir . '/stomp-php/stomp-php/src/StatefulStomp.php', + 'Stomp\\States\\ConsumerState' => $vendorDir . '/stomp-php/stomp-php/src/States/ConsumerState.php', + 'Stomp\\States\\ConsumerTransactionState' => $vendorDir . '/stomp-php/stomp-php/src/States/ConsumerTransactionState.php', + 'Stomp\\States\\Exception\\InvalidStateException' => $vendorDir . '/stomp-php/stomp-php/src/States/Exception/InvalidStateException.php', + 'Stomp\\States\\IStateful' => $vendorDir . '/stomp-php/stomp-php/src/States/IStateful.php', + 'Stomp\\States\\Meta\\Subscription' => $vendorDir . '/stomp-php/stomp-php/src/States/Meta/Subscription.php', + 'Stomp\\States\\Meta\\SubscriptionList' => $vendorDir . '/stomp-php/stomp-php/src/States/Meta/SubscriptionList.php', + 'Stomp\\States\\ProducerState' => $vendorDir . '/stomp-php/stomp-php/src/States/ProducerState.php', + 'Stomp\\States\\ProducerTransactionState' => $vendorDir . '/stomp-php/stomp-php/src/States/ProducerTransactionState.php', + 'Stomp\\States\\StateSetter' => $vendorDir . '/stomp-php/stomp-php/src/States/StateSetter.php', + 'Stomp\\States\\StateTemplate' => $vendorDir . '/stomp-php/stomp-php/src/States/StateTemplate.php', + 'Stomp\\States\\TransactionsTrait' => $vendorDir . '/stomp-php/stomp-php/src/States/TransactionsTrait.php', + 'Stomp\\Transport\\Bytes' => $vendorDir . '/stomp-php/stomp-php/src/Transport/Bytes.php', + 'Stomp\\Transport\\Frame' => $vendorDir . '/stomp-php/stomp-php/src/Transport/Frame.php', + 'Stomp\\Transport\\FrameFactory' => $vendorDir . '/stomp-php/stomp-php/src/Transport/FrameFactory.php', + 'Stomp\\Transport\\Map' => $vendorDir . '/stomp-php/stomp-php/src/Transport/Map.php', + 'Stomp\\Transport\\Message' => $vendorDir . '/stomp-php/stomp-php/src/Transport/Message.php', + 'Stomp\\Transport\\Parser' => $vendorDir . '/stomp-php/stomp-php/src/Transport/Parser.php', + 'Stomp\\Util\\IdGenerator' => $vendorDir . '/stomp-php/stomp-php/src/Util/IdGenerator.php', + 'XMPPHP\\BOSH' => $vendorDir . '/diogocomposer/xmpphp/XMPPHP/BOSH.php', + 'XMPPHP\\Exception' => $vendorDir . '/diogocomposer/xmpphp/XMPPHP/Exception.php', + 'XMPPHP\\Log' => $vendorDir . '/diogocomposer/xmpphp/XMPPHP/Log.php', + 'XMPPHP\\Roster' => $vendorDir . '/diogocomposer/xmpphp/XMPPHP/Roster.php', + 'XMPPHP\\XMLObj' => $vendorDir . '/diogocomposer/xmpphp/XMPPHP/XMLObj.php', + 'XMPPHP\\XMLStream' => $vendorDir . '/diogocomposer/xmpphp/XMPPHP/XMLStream.php', + 'XMPPHP\\XMPP' => $vendorDir . '/diogocomposer/xmpphp/XMPPHP/XMPP.php', + 'phpCAS' => $vendorDir . '/apereo/phpcas/source/CAS.php', + 'phpseclib\\Crypt\\AES' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/AES.php', + 'phpseclib\\Crypt\\Base' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/Base.php', + 'phpseclib\\Crypt\\Blowfish' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/Blowfish.php', + 'phpseclib\\Crypt\\DES' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/DES.php', + 'phpseclib\\Crypt\\Hash' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/Hash.php', + 'phpseclib\\Crypt\\RC2' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/RC2.php', + 'phpseclib\\Crypt\\RC4' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/RC4.php', + 'phpseclib\\Crypt\\RSA' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/RSA.php', + 'phpseclib\\Crypt\\Random' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/Random.php', + 'phpseclib\\Crypt\\Rijndael' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/Rijndael.php', + 'phpseclib\\Crypt\\TripleDES' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/TripleDES.php', + 'phpseclib\\Crypt\\Twofish' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/Twofish.php', + 'phpseclib\\File\\ANSI' => $vendorDir . '/phpseclib/phpseclib/phpseclib/File/ANSI.php', + 'phpseclib\\File\\ASN1' => $vendorDir . '/phpseclib/phpseclib/phpseclib/File/ASN1.php', + 'phpseclib\\File\\ASN1\\Element' => $vendorDir . '/phpseclib/phpseclib/phpseclib/File/ASN1/Element.php', + 'phpseclib\\File\\X509' => $vendorDir . '/phpseclib/phpseclib/phpseclib/File/X509.php', + 'phpseclib\\Math\\BigInteger' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Math/BigInteger.php', + 'phpseclib\\Net\\SCP' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Net/SCP.php', + 'phpseclib\\Net\\SFTP' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Net/SFTP.php', + 'phpseclib\\Net\\SFTP\\Stream' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Net/SFTP/Stream.php', + 'phpseclib\\Net\\SSH1' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Net/SSH1.php', + 'phpseclib\\Net\\SSH2' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Net/SSH2.php', + 'phpseclib\\System\\SSH\\Agent' => $vendorDir . '/phpseclib/phpseclib/phpseclib/System/SSH/Agent.php', + 'phpseclib\\System\\SSH\\Agent\\Identity' => $vendorDir . '/phpseclib/phpseclib/phpseclib/System/SSH/Agent/Identity.php', ); diff --git a/vendor/composer/autoload_files.php b/vendor/composer/autoload_files.php index f783461fd4..18d5e4a3c7 100644 --- a/vendor/composer/autoload_files.php +++ b/vendor/composer/autoload_files.php @@ -8,4 +8,5 @@ $baseDir = dirname($vendorDir); return array( '2cffec82183ee1cea088009cef9a6fc3' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier.composer.php', '757772e28a0943a9afe83def8db95bdf' => $vendorDir . '/mf2/mf2/Mf2/Parser.php', + 'decc78cc4436b1292c6c0d151b19445c' => $vendorDir . '/phpseclib/phpseclib/phpseclib/bootstrap.php', ); diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php index c06ae7e318..de5192bb91 100644 --- a/vendor/composer/autoload_psr4.php +++ b/vendor/composer/autoload_psr4.php @@ -6,5 +6,10 @@ $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); return array( + 'phpseclib\\' => array($vendorDir . '/phpseclib/phpseclib/phpseclib'), + 'XMPPHP\\' => array($vendorDir . '/diogocomposer/xmpphp/XMPPHP'), + 'Stomp\\' => array($vendorDir . '/stomp-php/stomp-php/src'), + 'ParagonIE\\ConstantTime\\' => array($vendorDir . '/paragonie/constant_time_encoding/src'), + 'Michelf\\' => array($vendorDir . '/michelf/php-markdown/Michelf'), 'Masterminds\\' => array($vendorDir . '/masterminds/html5/src'), ); diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php index 805be0804e..a49f27348e 100644 --- a/vendor/composer/autoload_real.php +++ b/vendor/composer/autoload_real.php @@ -2,7 +2,7 @@ // autoload_real.php @generated by Composer -class ComposerAutoloaderInit4f5ec3b37be240134637564819b99dd2 +class ComposerAutoloaderInit444c3f31864f68a3f466e2c19837e185 { private static $loader; @@ -19,9 +19,9 @@ class ComposerAutoloaderInit4f5ec3b37be240134637564819b99dd2 return self::$loader; } - spl_autoload_register(array('ComposerAutoloaderInit4f5ec3b37be240134637564819b99dd2', 'loadClassLoader'), true, true); + spl_autoload_register(array('ComposerAutoloaderInit444c3f31864f68a3f466e2c19837e185', 'loadClassLoader'), true, true); self::$loader = $loader = new \Composer\Autoload\ClassLoader(); - spl_autoload_unregister(array('ComposerAutoloaderInit4f5ec3b37be240134637564819b99dd2', 'loadClassLoader')); + spl_autoload_unregister(array('ComposerAutoloaderInit444c3f31864f68a3f466e2c19837e185', 'loadClassLoader')); $includePaths = require __DIR__ . '/include_paths.php'; $includePaths[] = get_include_path(); @@ -31,7 +31,7 @@ class ComposerAutoloaderInit4f5ec3b37be240134637564819b99dd2 if ($useStaticLoader) { require_once __DIR__ . '/autoload_static.php'; - call_user_func(\Composer\Autoload\ComposerStaticInit4f5ec3b37be240134637564819b99dd2::getInitializer($loader)); + call_user_func(\Composer\Autoload\ComposerStaticInit444c3f31864f68a3f466e2c19837e185::getInitializer($loader)); } else { $map = require __DIR__ . '/autoload_namespaces.php'; foreach ($map as $namespace => $path) { @@ -52,19 +52,19 @@ class ComposerAutoloaderInit4f5ec3b37be240134637564819b99dd2 $loader->register(true); if ($useStaticLoader) { - $includeFiles = Composer\Autoload\ComposerStaticInit4f5ec3b37be240134637564819b99dd2::$files; + $includeFiles = Composer\Autoload\ComposerStaticInit444c3f31864f68a3f466e2c19837e185::$files; } else { $includeFiles = require __DIR__ . '/autoload_files.php'; } foreach ($includeFiles as $fileIdentifier => $file) { - composerRequire4f5ec3b37be240134637564819b99dd2($fileIdentifier, $file); + composerRequire444c3f31864f68a3f466e2c19837e185($fileIdentifier, $file); } return $loader; } } -function composerRequire4f5ec3b37be240134637564819b99dd2($fileIdentifier, $file) +function composerRequire444c3f31864f68a3f466e2c19837e185($fileIdentifier, $file) { if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { require $file; diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index bb8e24e38f..8c6336129e 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -4,21 +4,59 @@ namespace Composer\Autoload; -class ComposerStaticInit4f5ec3b37be240134637564819b99dd2 +class ComposerStaticInit444c3f31864f68a3f466e2c19837e185 { public static $files = array ( '2cffec82183ee1cea088009cef9a6fc3' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier.composer.php', '757772e28a0943a9afe83def8db95bdf' => __DIR__ . '/..' . '/mf2/mf2/Mf2/Parser.php', + 'decc78cc4436b1292c6c0d151b19445c' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/bootstrap.php', ); public static $prefixLengthsPsr4 = array ( + 'p' => + array ( + 'phpseclib\\' => 10, + ), + 'X' => + array ( + 'XMPPHP\\' => 7, + ), + 'S' => + array ( + 'Stomp\\' => 6, + ), + 'P' => + array ( + 'ParagonIE\\ConstantTime\\' => 23, + ), 'M' => array ( + 'Michelf\\' => 8, 'Masterminds\\' => 12, ), ); public static $prefixDirsPsr4 = array ( + 'phpseclib\\' => + array ( + 0 => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib', + ), + 'XMPPHP\\' => + array ( + 0 => __DIR__ . '/..' . '/diogocomposer/xmpphp/XMPPHP', + ), + 'Stomp\\' => + array ( + 0 => __DIR__ . '/..' . '/stomp-php/stomp-php/src', + ), + 'ParagonIE\\ConstantTime\\' => + array ( + 0 => __DIR__ . '/..' . '/paragonie/constant_time_encoding/src', + ), + 'Michelf\\' => + array ( + 0 => __DIR__ . '/..' . '/michelf/php-markdown/Michelf', + ), 'Masterminds\\' => array ( 0 => __DIR__ . '/..' . '/masterminds/html5/src', @@ -131,6 +169,50 @@ class ComposerStaticInit4f5ec3b37be240134637564819b99dd2 'Auth_Yadis_Yadis' => __DIR__ . '/..' . '/openid/php-openid/Auth/Yadis/Yadis.php', 'Auth_Yadis_dom' => __DIR__ . '/..' . '/openid/php-openid/Auth/Yadis/XML.php', 'Auth_Yadis_domxml' => __DIR__ . '/..' . '/openid/php-openid/Auth/Yadis/XML.php', + 'CAS_AuthenticationException' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/AuthenticationException.php', + 'CAS_Client' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/Client.php', + 'CAS_CookieJar' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/CookieJar.php', + 'CAS_Exception' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/Exception.php', + 'CAS_GracefullTerminationException' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/GracefullTerminationException.php', + 'CAS_InvalidArgumentException' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/InvalidArgumentException.php', + 'CAS_Languages_Catalan' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/Languages/Catalan.php', + 'CAS_Languages_ChineseSimplified' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/Languages/ChineseSimplified.php', + 'CAS_Languages_English' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/Languages/English.php', + 'CAS_Languages_French' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/Languages/French.php', + 'CAS_Languages_German' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/Languages/German.php', + 'CAS_Languages_Greek' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/Languages/Greek.php', + 'CAS_Languages_Japanese' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/Languages/Japanese.php', + 'CAS_Languages_LanguageInterface' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/Languages/LanguageInterface.php', + 'CAS_Languages_Spanish' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/Languages/Spanish.php', + 'CAS_OutOfSequenceBeforeAuthenticationCallException' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/OutOfSequenceBeforeAuthenticationCallException.php', + 'CAS_OutOfSequenceBeforeClientException' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/OutOfSequenceBeforeClientException.php', + 'CAS_OutOfSequenceBeforeProxyException' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/OutOfSequenceBeforeProxyException.php', + 'CAS_OutOfSequenceException' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/OutOfSequenceException.php', + 'CAS_PGTStorage_AbstractStorage' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/PGTStorage/AbstractStorage.php', + 'CAS_PGTStorage_Db' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/PGTStorage/Db.php', + 'CAS_PGTStorage_File' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/PGTStorage/File.php', + 'CAS_ProxiedService' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/ProxiedService.php', + 'CAS_ProxiedService_Abstract' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/ProxiedService/Abstract.php', + 'CAS_ProxiedService_Exception' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/ProxiedService/Exception.php', + 'CAS_ProxiedService_Http' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/ProxiedService/Http.php', + 'CAS_ProxiedService_Http_Abstract' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/ProxiedService/Http/Abstract.php', + 'CAS_ProxiedService_Http_Get' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/ProxiedService/Http/Get.php', + 'CAS_ProxiedService_Http_Post' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/ProxiedService/Http/Post.php', + 'CAS_ProxiedService_Imap' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/ProxiedService/Imap.php', + 'CAS_ProxiedService_Testable' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/ProxiedService/Testable.php', + 'CAS_ProxyChain' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/ProxyChain.php', + 'CAS_ProxyChain_AllowedList' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/ProxyChain/AllowedList.php', + 'CAS_ProxyChain_Any' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/ProxyChain/Any.php', + 'CAS_ProxyChain_Interface' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/ProxyChain/Interface.php', + 'CAS_ProxyChain_Trusted' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/ProxyChain/Trusted.php', + 'CAS_ProxyTicketException' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/ProxyTicketException.php', + 'CAS_Request_AbstractRequest' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/Request/AbstractRequest.php', + 'CAS_Request_CurlMultiRequest' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/Request/CurlMultiRequest.php', + 'CAS_Request_CurlRequest' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/Request/CurlRequest.php', + 'CAS_Request_Exception' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/Request/Exception.php', + 'CAS_Request_MultiRequestInterface' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/Request/MultiRequestInterface.php', + 'CAS_Request_RequestInterface' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/Request/RequestInterface.php', + 'CAS_TypeMismatchException' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/TypeMismatchException.php', 'HTMLPurifier' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier.php', 'HTMLPurifier_Arborize' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Arborize.php', 'HTMLPurifier_AttrCollections' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrCollections.php', @@ -385,15 +467,106 @@ class ComposerStaticInit4f5ec3b37be240134637564819b99dd2 'Masterminds\\HTML5\\Serializer\\OutputRules' => __DIR__ . '/..' . '/masterminds/html5/src/HTML5/Serializer/OutputRules.php', 'Masterminds\\HTML5\\Serializer\\RulesInterface' => __DIR__ . '/..' . '/masterminds/html5/src/HTML5/Serializer/RulesInterface.php', 'Masterminds\\HTML5\\Serializer\\Traverser' => __DIR__ . '/..' . '/masterminds/html5/src/HTML5/Serializer/Traverser.php', + 'Michelf\\Markdown' => __DIR__ . '/..' . '/michelf/php-markdown/Michelf/Markdown.php', + 'Michelf\\MarkdownExtra' => __DIR__ . '/..' . '/michelf/php-markdown/Michelf/MarkdownExtra.php', + 'Michelf\\MarkdownInterface' => __DIR__ . '/..' . '/michelf/php-markdown/Michelf/MarkdownInterface.php', + 'ParagonIE\\ConstantTime\\Base32' => __DIR__ . '/..' . '/paragonie/constant_time_encoding/src/Base32.php', + 'ParagonIE\\ConstantTime\\Base32Hex' => __DIR__ . '/..' . '/paragonie/constant_time_encoding/src/Base32Hex.php', + 'ParagonIE\\ConstantTime\\Base64' => __DIR__ . '/..' . '/paragonie/constant_time_encoding/src/Base64.php', + 'ParagonIE\\ConstantTime\\Base64DotSlash' => __DIR__ . '/..' . '/paragonie/constant_time_encoding/src/Base64DotSlash.php', + 'ParagonIE\\ConstantTime\\Base64DotSlashOrdered' => __DIR__ . '/..' . '/paragonie/constant_time_encoding/src/Base64DotSlashOrdered.php', + 'ParagonIE\\ConstantTime\\Base64UrlSafe' => __DIR__ . '/..' . '/paragonie/constant_time_encoding/src/Base64UrlSafe.php', + 'ParagonIE\\ConstantTime\\Binary' => __DIR__ . '/..' . '/paragonie/constant_time_encoding/src/Binary.php', + 'ParagonIE\\ConstantTime\\EncoderInterface' => __DIR__ . '/..' . '/paragonie/constant_time_encoding/src/EncoderInterface.php', + 'ParagonIE\\ConstantTime\\Encoding' => __DIR__ . '/..' . '/paragonie/constant_time_encoding/src/Encoding.php', + 'ParagonIE\\ConstantTime\\Hex' => __DIR__ . '/..' . '/paragonie/constant_time_encoding/src/Hex.php', + 'ParagonIE\\ConstantTime\\RFC4648' => __DIR__ . '/..' . '/paragonie/constant_time_encoding/src/RFC4648.php', + 'Stomp\\Broker\\ActiveMq\\ActiveMq' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/Broker/ActiveMq/ActiveMq.php', + 'Stomp\\Broker\\ActiveMq\\Mode\\ActiveMqMode' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/Broker/ActiveMq/Mode/ActiveMqMode.php', + 'Stomp\\Broker\\ActiveMq\\Mode\\DurableSubscription' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/Broker/ActiveMq/Mode/DurableSubscription.php', + 'Stomp\\Broker\\ActiveMq\\Options' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/Broker/ActiveMq/Options.php', + 'Stomp\\Broker\\Apollo\\Apollo' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/Broker/Apollo/Apollo.php', + 'Stomp\\Broker\\Apollo\\Mode\\QueueBrowser' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/Broker/Apollo/Mode/QueueBrowser.php', + 'Stomp\\Broker\\Apollo\\Mode\\SequenceQueueBrowser' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/Broker/Apollo/Mode/SequenceQueueBrowser.php', + 'Stomp\\Broker\\Exception\\UnsupportedBrokerException' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/Broker/Exception/UnsupportedBrokerException.php', + 'Stomp\\Broker\\OpenMq\\OpenMq' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/Broker/OpenMq/OpenMq.php', + 'Stomp\\Broker\\RabbitMq\\RabbitMq' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/Broker/RabbitMq/RabbitMq.php', + 'Stomp\\Client' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/Client.php', + 'Stomp\\Exception\\ConnectionException' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/Exception/ConnectionException.php', + 'Stomp\\Exception\\ErrorFrameException' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/Exception/ErrorFrameException.php', + 'Stomp\\Exception\\MissingReceiptException' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/Exception/MissingReceiptException.php', + 'Stomp\\Exception\\StompException' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/Exception/StompException.php', + 'Stomp\\Exception\\UnexpectedResponseException' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/Exception/UnexpectedResponseException.php', + 'Stomp\\Network\\Connection' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/Network/Connection.php', + 'Stomp\\Network\\Observer\\AbstractBeats' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/Network/Observer/AbstractBeats.php', + 'Stomp\\Network\\Observer\\ConnectionObserver' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/Network/Observer/ConnectionObserver.php', + 'Stomp\\Network\\Observer\\ConnectionObserverCollection' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/Network/Observer/ConnectionObserverCollection.php', + 'Stomp\\Network\\Observer\\Exception\\HeartbeatException' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/Network/Observer/Exception/HeartbeatException.php', + 'Stomp\\Network\\Observer\\HeartbeatEmitter' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/Network/Observer/HeartbeatEmitter.php', + 'Stomp\\Network\\Observer\\ServerAliveObserver' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/Network/Observer/ServerAliveObserver.php', + 'Stomp\\Protocol\\Protocol' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/Protocol/Protocol.php', + 'Stomp\\Protocol\\Version' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/Protocol/Version.php', + 'Stomp\\SimpleStomp' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/SimpleStomp.php', + 'Stomp\\StatefulStomp' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/StatefulStomp.php', + 'Stomp\\States\\ConsumerState' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/States/ConsumerState.php', + 'Stomp\\States\\ConsumerTransactionState' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/States/ConsumerTransactionState.php', + 'Stomp\\States\\Exception\\InvalidStateException' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/States/Exception/InvalidStateException.php', + 'Stomp\\States\\IStateful' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/States/IStateful.php', + 'Stomp\\States\\Meta\\Subscription' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/States/Meta/Subscription.php', + 'Stomp\\States\\Meta\\SubscriptionList' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/States/Meta/SubscriptionList.php', + 'Stomp\\States\\ProducerState' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/States/ProducerState.php', + 'Stomp\\States\\ProducerTransactionState' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/States/ProducerTransactionState.php', + 'Stomp\\States\\StateSetter' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/States/StateSetter.php', + 'Stomp\\States\\StateTemplate' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/States/StateTemplate.php', + 'Stomp\\States\\TransactionsTrait' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/States/TransactionsTrait.php', + 'Stomp\\Transport\\Bytes' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/Transport/Bytes.php', + 'Stomp\\Transport\\Frame' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/Transport/Frame.php', + 'Stomp\\Transport\\FrameFactory' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/Transport/FrameFactory.php', + 'Stomp\\Transport\\Map' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/Transport/Map.php', + 'Stomp\\Transport\\Message' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/Transport/Message.php', + 'Stomp\\Transport\\Parser' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/Transport/Parser.php', + 'Stomp\\Util\\IdGenerator' => __DIR__ . '/..' . '/stomp-php/stomp-php/src/Util/IdGenerator.php', + 'XMPPHP\\BOSH' => __DIR__ . '/..' . '/diogocomposer/xmpphp/XMPPHP/BOSH.php', + 'XMPPHP\\Exception' => __DIR__ . '/..' . '/diogocomposer/xmpphp/XMPPHP/Exception.php', + 'XMPPHP\\Log' => __DIR__ . '/..' . '/diogocomposer/xmpphp/XMPPHP/Log.php', + 'XMPPHP\\Roster' => __DIR__ . '/..' . '/diogocomposer/xmpphp/XMPPHP/Roster.php', + 'XMPPHP\\XMLObj' => __DIR__ . '/..' . '/diogocomposer/xmpphp/XMPPHP/XMLObj.php', + 'XMPPHP\\XMLStream' => __DIR__ . '/..' . '/diogocomposer/xmpphp/XMPPHP/XMLStream.php', + 'XMPPHP\\XMPP' => __DIR__ . '/..' . '/diogocomposer/xmpphp/XMPPHP/XMPP.php', + 'phpCAS' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS.php', + 'phpseclib\\Crypt\\AES' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/AES.php', + 'phpseclib\\Crypt\\Base' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/Base.php', + 'phpseclib\\Crypt\\Blowfish' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/Blowfish.php', + 'phpseclib\\Crypt\\DES' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/DES.php', + 'phpseclib\\Crypt\\Hash' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/Hash.php', + 'phpseclib\\Crypt\\RC2' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/RC2.php', + 'phpseclib\\Crypt\\RC4' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/RC4.php', + 'phpseclib\\Crypt\\RSA' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/RSA.php', + 'phpseclib\\Crypt\\Random' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/Random.php', + 'phpseclib\\Crypt\\Rijndael' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/Rijndael.php', + 'phpseclib\\Crypt\\TripleDES' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/TripleDES.php', + 'phpseclib\\Crypt\\Twofish' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/Twofish.php', + 'phpseclib\\File\\ANSI' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/File/ANSI.php', + 'phpseclib\\File\\ASN1' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/File/ASN1.php', + 'phpseclib\\File\\ASN1\\Element' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/File/ASN1/Element.php', + 'phpseclib\\File\\X509' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/File/X509.php', + 'phpseclib\\Math\\BigInteger' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Math/BigInteger.php', + 'phpseclib\\Net\\SCP' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Net/SCP.php', + 'phpseclib\\Net\\SFTP' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Net/SFTP.php', + 'phpseclib\\Net\\SFTP\\Stream' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Net/SFTP/Stream.php', + 'phpseclib\\Net\\SSH1' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Net/SSH1.php', + 'phpseclib\\Net\\SSH2' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Net/SSH2.php', + 'phpseclib\\System\\SSH\\Agent' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/System/SSH/Agent.php', + 'phpseclib\\System\\SSH\\Agent\\Identity' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/System/SSH/Agent/Identity.php', ); public static function getInitializer(ClassLoader $loader) { return \Closure::bind(function () use ($loader) { - $loader->prefixLengthsPsr4 = ComposerStaticInit4f5ec3b37be240134637564819b99dd2::$prefixLengthsPsr4; - $loader->prefixDirsPsr4 = ComposerStaticInit4f5ec3b37be240134637564819b99dd2::$prefixDirsPsr4; - $loader->prefixesPsr0 = ComposerStaticInit4f5ec3b37be240134637564819b99dd2::$prefixesPsr0; - $loader->classMap = ComposerStaticInit4f5ec3b37be240134637564819b99dd2::$classMap; + $loader->prefixLengthsPsr4 = ComposerStaticInit444c3f31864f68a3f466e2c19837e185::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInit444c3f31864f68a3f466e2c19837e185::$prefixDirsPsr4; + $loader->prefixesPsr0 = ComposerStaticInit444c3f31864f68a3f466e2c19837e185::$prefixesPsr0; + $loader->classMap = ComposerStaticInit444c3f31864f68a3f466e2c19837e185::$classMap; }, null, ClassLoader::class); } diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index c0e2383c3b..20a413de43 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -1,4 +1,134 @@ [ + { + "name": "apereo/phpcas", + "version": "1.3.7", + "version_normalized": "1.3.7.0", + "source": { + "type": "git", + "url": "https://github.com/apereo/phpCAS.git", + "reference": "b5b29102c3a42f570c4a3e852f3cf67cae6d6082" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/apereo/phpCAS/zipball/b5b29102c3a42f570c4a3e852f3cf67cae6d6082", + "reference": "b5b29102c3a42f570c4a3e852f3cf67cae6d6082", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "~3.7.10" + }, + "time": "2019-04-22T19:48:16+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "classmap": [ + "source/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Joachim Fritschi", + "homepage": "https://wiki.jasig.org/display/~fritschi" + }, + { + "name": "Adam Franco", + "homepage": "https://wiki.jasig.org/display/~adamfranco" + } + ], + "description": "Provides a simple API for authenticating users against a CAS server", + "homepage": "https://wiki.jasig.org/display/CASC/phpCAS", + "keywords": [ + "apereo", + "cas", + "jasig" + ] + }, + { + "name": "diogocomposer/xmpphp", + "version": "v3.0.0", + "version_normalized": "3.0.0.0", + "source": { + "type": "git", + "url": "https://github.com/diogogithub/xmpphp.git", + "reference": "c7cdcc588aa47893ab41a1670c5dfe649674a4b0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/diogogithub/xmpphp/zipball/c7cdcc588aa47893ab41a1670c5dfe649674a4b0", + "reference": "c7cdcc588aa47893ab41a1670c5dfe649674a4b0", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "ext-xml": "*", + "php": ">=7.0.0" + }, + "time": "2019-06-19T02:32:32+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "XMPPHP\\": "XMPPHP" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-2.0+" + ], + "authors": [ + { + "name": "Ivan Borzenkov", + "email": "ivan.borzenkov@gmail.com" + }, + { + "name": "bandroidx", + "email": "bandroidx@gmail.com" + }, + { + "name": "BirknerAlex", + "email": "alex.birkner@gmail.com" + }, + { + "name": "Stephan Wentz", + "email": "stephan@wentz.it" + }, + { + "name": "Nathan Fritz", + "email": "fritzy@netflint.net" + }, + { + "name": "Christian Weiske", + "email": "cweiske@cweiske.de" + }, + { + "name": "Vito Tafuni", + "email": "vitotafuni@gmail.com" + }, + { + "name": "Diogo Cordeiro", + "email": "diogo@fc.up.pt" + } + ], + "description": "XMPP PHP Library", + "keywords": [ + "jabber", + "xmpp", + "xmpphp" + ] + }, { "name": "ezyang/htmlpurifier", "version": "v4.10.0", @@ -175,6 +305,54 @@ "semantic" ] }, + { + "name": "michelf/php-markdown", + "version": "1.8.0", + "version_normalized": "1.8.0.0", + "source": { + "type": "git", + "url": "https://github.com/michelf/php-markdown.git", + "reference": "01ab082b355bf188d907b9929cd99b2923053495" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/michelf/php-markdown/zipball/01ab082b355bf188d907b9929cd99b2923053495", + "reference": "01ab082b355bf188d907b9929cd99b2923053495", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "time": "2018-01-15T00:49:33+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Michelf\\": "Michelf/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Michel Fortin", + "email": "michel.fortin@michelf.ca", + "homepage": "https://michelf.ca/", + "role": "Developer" + }, + { + "name": "John Gruber", + "homepage": "https://daringfireball.net/" + } + ], + "description": "PHP Markdown", + "homepage": "https://michelf.ca/projects/php-markdown/", + "keywords": [ + "markdown" + ] + }, { "name": "openid/php-openid", "version": "2.3.0", @@ -225,5 +403,225 @@ "auth", "yadis" ] + }, + { + "name": "paragonie/constant_time_encoding", + "version": "v1.0.4", + "version_normalized": "1.0.4.0", + "source": { + "type": "git", + "url": "https://github.com/paragonie/constant_time_encoding.git", + "reference": "2132f0f293d856026d7d11bd81b9f4a23a1dc1f6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/2132f0f293d856026d7d11bd81b9f4a23a1dc1f6", + "reference": "2132f0f293d856026d7d11bd81b9f4a23a1dc1f6", + "shasum": "" + }, + "require": { + "php": "^5.3|^7" + }, + "require-dev": { + "paragonie/random_compat": "^1.4|^2", + "phpunit/phpunit": "4.*|5.*", + "vimeo/psalm": "^0.3|^1" + }, + "time": "2018-04-30T17:57:16+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "ParagonIE\\ConstantTime\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com", + "role": "Maintainer" + }, + { + "name": "Steve 'Sc00bz' Thomas", + "email": "steve@tobtu.com", + "homepage": "https://www.tobtu.com", + "role": "Original Developer" + } + ], + "description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)", + "keywords": [ + "base16", + "base32", + "base32_decode", + "base32_encode", + "base64", + "base64_decode", + "base64_encode", + "bin2hex", + "encoding", + "hex", + "hex2bin", + "rfc4648" + ] + }, + { + "name": "phpseclib/phpseclib", + "version": "2.0.19", + "version_normalized": "2.0.19.0", + "source": { + "type": "git", + "url": "https://github.com/phpseclib/phpseclib.git", + "reference": "d2085db7b7394baa071a69c8f9159723c250f2ba" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/d2085db7b7394baa071a69c8f9159723c250f2ba", + "reference": "d2085db7b7394baa071a69c8f9159723c250f2ba", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phing/phing": "~2.7", + "phpunit/phpunit": "^4.8.35|^5.7|^6.0", + "sami/sami": "~2.0", + "squizlabs/php_codesniffer": "~2.0" + }, + "suggest": { + "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.", + "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.", + "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.", + "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations." + }, + "time": "2019-06-20T03:34:11+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "phpseclib/bootstrap.php" + ], + "psr-4": { + "phpseclib\\": "phpseclib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jim Wigginton", + "email": "terrafrost@php.net", + "role": "Lead Developer" + }, + { + "name": "Patrick Monnerat", + "email": "pm@datasphere.ch", + "role": "Developer" + }, + { + "name": "Andreas Fischer", + "email": "bantu@phpbb.com", + "role": "Developer" + }, + { + "name": "Hans-Jürgen Petrich", + "email": "petrich@tronic-media.com", + "role": "Developer" + }, + { + "name": "Graham Campbell", + "email": "graham@alt-three.com", + "role": "Developer" + } + ], + "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.", + "homepage": "http://phpseclib.sourceforge.net", + "keywords": [ + "BigInteger", + "aes", + "asn.1", + "asn1", + "blowfish", + "crypto", + "cryptography", + "encryption", + "rsa", + "security", + "sftp", + "signature", + "signing", + "ssh", + "twofish", + "x.509", + "x509" + ] + }, + { + "name": "stomp-php/stomp-php", + "version": "4.5.1", + "version_normalized": "4.5.1.0", + "source": { + "type": "git", + "url": "https://github.com/stomp-php/stomp-php.git", + "reference": "4c5f0a95330085a86fd852b8ad0b1fbb4e8a4158" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/stomp-php/stomp-php/zipball/4c5f0a95330085a86fd852b8ad0b1fbb4e8a4158", + "reference": "4c5f0a95330085a86fd852b8ad0b1fbb4e8a4158", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7" + }, + "time": "2019-04-09T08:25:54+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Stomp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Dejan Bosnanac", + "email": "dejan@nighttale.net", + "homepage": "http://www.nighttale.net" + }, + { + "name": "Sören Rohweder", + "email": "s.rohweder@blage.net", + "homepage": "http://www.monofone.de" + }, + { + "name": "Jens Radtke", + "email": "swefl@fin-sn.de", + "homepage": "http://www.fin-sn.de" + } + ], + "description": "stomp support for PHP", + "homepage": "http://github.com/stomp-php/stomp-php", + "keywords": [ + "activeMQ", + "apollomq", + "jms", + "messaging", + "rabbitmq", + "stomp" + ] } ] diff --git a/vendor/diogocomposer/xmpphp/.gitignore b/vendor/diogocomposer/xmpphp/.gitignore new file mode 100644 index 0000000000..a67d42b32f --- /dev/null +++ b/vendor/diogocomposer/xmpphp/.gitignore @@ -0,0 +1,6 @@ +composer.phar +/vendor/ + +# Commit your application's lock file https://getcomposer.org/doc/01-basic-usage.md#commit-your-composer-lock-file-to-version-control +# You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file +# composer.lock diff --git a/vendor/diogocomposer/xmpphp/LICENSE b/vendor/diogocomposer/xmpphp/LICENSE new file mode 100644 index 0000000000..3f908447b1 --- /dev/null +++ b/vendor/diogocomposer/xmpphp/LICENSE @@ -0,0 +1,352 @@ +XMPPHP: The PHP XMPP Library +Copyright (C) 2008 Nathanael C. Fritz + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + +Exceptions: + +As a special exception to this license, the "Enhanced Jabber Integration" +project, which is a plugin for vBulletin, may use and distribute XMPPHP +without extending the GPL license to the parent package. + +If you would like an exception for your free software, please contact the +copyright holder. diff --git a/vendor/diogocomposer/xmpphp/README.md b/vendor/diogocomposer/xmpphp/README.md new file mode 100644 index 0000000000..ec10b5155a --- /dev/null +++ b/vendor/diogocomposer/xmpphp/README.md @@ -0,0 +1,20 @@ +README +====== + +About XMPPHP +------------ + +XMPPHP is an elegant PHP library for XMPP (aka Jabber, Google Talk, etc). + +* Homepage: [http://code.google.com/p/xmpphp] +* Chatroom: [xmpphp@conference.psi-im.org] (XMPP MUC) +* Author: Nathan Fritz, jabber id: fritzy [at] netflint.net +* Co-Author: Stephan Wentz, jabber id: stephan [at] wentz.it +* This fork: https://github.com/diogogithub/xmpphp +* Maintainer of this fork: Diogo Cordeiro + +Requirements +------------ + +* PHP 7.0 +* SSL Support Compiled diff --git a/vendor/diogocomposer/xmpphp/XMPPHP/BOSH.php b/vendor/diogocomposer/xmpphp/XMPPHP/BOSH.php new file mode 100644 index 0000000000..140ff7c823 --- /dev/null +++ b/vendor/diogocomposer/xmpphp/XMPPHP/BOSH.php @@ -0,0 +1,409 @@ + + * @author Stephan Wentz + * @author Michael Garvin + * @author Alexander Birkner (https://github.com/BirknerAlex) + * @author zorn-v (https://github.com/zorn-v/xmpphp/) + * @author GNU social + * @copyright 2008 Nathanael C. Fritz + */ + +namespace XMPPHP; + +use SimpleXMLElement; + +/** XMPPHP_XMLStream */ +require_once __DIR__ . "/XMPP.php"; + +/** + * XMPPHP BOSH + * + * @property int lat + * @package XMPPHP + * @author Nathanael C. Fritz + * @author Stephan Wentz + * @author Michael Garvin + * @copyright 2008 Nathanael C. Fritz + * @version $Id$ + */ +class BOSH extends XMPP +{ + /** + * @var integer + */ + protected $rid; + + /** + * @var string + */ + protected $sid; + + /** + * @var string + */ + protected $http_server; + + /** + * @var array + */ + protected $http_buffer = array(); + + /** + * @var string + */ + protected $session = false; + + /** + * @var integer + */ + protected $inactivity; + + /** + * Connect + * + * @param $server + * @param $wait + * @param $session + * @throws Exception + * @throws Exception + */ + public function connect($server = null, $wait = '1', $session = false) + { + + if (is_null($server)) { + + // If we aren't given the server http url, try and guess it + $port_string = ($this->port AND $this->port != 80) ? ':' . $this->port : ''; + $this->http_server = 'http://' . $this->host . $port_string . '/http-bind/'; + } else { + $this->http_server = $server; + } + + $this->use_encryption = false; + $this->session = $session; + $this->rid = 3001; + $this->sid = null; + $this->inactivity = 0; + + if ($session) { + $this->loadSession(); + } + + if (!$this->sid) { + + $body = $this->__buildBody(); + $body->addAttribute('hold', '1'); + $body->addAttribute('to', $this->server); + $body->addAttribute('route', 'xmpp:' . $this->host . ':' . $this->port); + $body->addAttribute('secure', 'true'); + $body->addAttribute('xmpp:version', '1.0', 'urn:xmpp:xbosh'); + $body->addAttribute('wait', strval($wait)); + $body->addAttribute('ack', '1'); + $body->addAttribute('xmlns:xmpp', 'urn:xmpp:xbosh'); + $buff = ''; + xml_parse($this->parser, $buff, false); + $response = $this->__sendBody($body); + $rxml = new SimpleXMLElement($response); + $this->sid = $rxml['sid']; + $this->inactivity = $rxml['inactivity']; + } else { + $buff = ''; + xml_parse($this->parser, $buff, false); + } + } + + /** + * Load session + * + */ + public function loadSession() + { + + if ($this->session == 'ON_FILE') { + + // Session not started so use session_file + $session_file = $this->getSessionFile(); + + // manage multiple accesses + if (!file_exists($session_file)) { + file_put_contents($session_file, ''); + } + $session_file_fp = fopen($session_file, 'r'); + flock($session_file_fp, LOCK_EX); + $session_serialized = file_get_contents($session_file, null, null, 6); + flock($session_file_fp, LOCK_UN); + fclose($session_file_fp); + + $this->log->log('SESSION: reading ' . $session_serialized . ' from ' . $session_file, Log::LEVEL_VERBOSE); + if ($session_serialized != '') { + $_SESSION['XMPPHP_BOSH'] = unserialize($session_serialized); + } + } + + if (isset($_SESSION['XMPPHP_BOSH']['inactivity'])) { + $this->inactivity = $_SESSION['XMPPHP_BOSH']['inactivity']; + } + + $this->lat = (time() - (isset($_SESSION['XMPPHP_BOSH']['lat']))) ? $_SESSION['XMPPHP_BOSH']['lat'] : 0; + + if ($this->lat < $this->inactivity) { + + if (isset($_SESSION['XMPPHP_BOSH']['RID'])) { + $this->rid = $_SESSION['XMPPHP_BOSH']['RID']; + } + if (isset($_SESSION['XMPPHP_BOSH']['SID'])) { + $this->sid = $_SESSION['XMPPHP_BOSH']['SID']; + } + if (isset($_SESSION['XMPPHP_BOSH']['authed'])) { + $this->authed = $_SESSION['XMPPHP_BOSH']['authed']; + } + if (isset($_SESSION['XMPPHP_BOSH']['basejid'])) { + $this->basejid = $_SESSION['XMPPHP_BOSH']['basejid']; + } + if (isset($_SESSION['XMPPHP_BOSH']['fulljid'])) { + $this->fulljid = $_SESSION['XMPPHP_BOSH']['fulljid']; + } + } + } + + /** + * Get the session file + * + */ + public function getSessionFile() + { + return sys_get_temp_dir() . '/' . $this->user . '_' . $this->server . '_session'; + } + + /** + * Build body + * + * @param $sub + * @return SimpleXMLElement|string + */ + public function __buildBody($sub = null) + { + + $xml = ''; + $xml = new SimpleXMLElement($xml); + $xml->addAttribute('content', 'text/xml; charset=utf-8'); + $xml->addAttribute('rid', $this->rid); + $this->rid++; + if ($this->sid) { + $xml->addAttribute('sid', $this->sid); + } + + $xml->addAttribute('xml:lang', 'en'); + + if ($sub !== null) { + + // Ok, so simplexml is lame + $parent = dom_import_simplexml($xml); + $content = dom_import_simplexml($sub); + $child = $parent->ownerDocument->importNode($content, true); + $parent->appendChild($child); + $xml = simplexml_import_dom($parent); + } + + return $xml; + } + + /** + * Send body + * + * @param $body + * @param $recv + * @return bool|string + * @throws Exception + * @throws Exception + */ + public function __sendBody($body = null, $recv = true) + { + + if (!$body) { + $body = $this->__buildBody(); + } + + $output = ''; + $header = array('Accept-Encoding: gzip, deflate', 'Content-Type: text/xml; charset=utf-8'); + $ch = curl_init(); + + curl_setopt($ch, CURLOPT_URL, $this->http_server); + curl_setopt($ch, CURLOPT_HEADER, 0); + curl_setopt($ch, CURLOPT_POST, 1); + curl_setopt($ch, CURLOPT_POSTFIELDS, $body->asXML()); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, $header); + curl_setopt($ch, CURLOPT_VERBOSE, 0); + + if ($recv) { + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + $output = curl_exec($ch); + if (curl_getinfo($ch, CURLINFO_HTTP_CODE) != '200') { + throw new Exception('Wrong response from server!'); + } + + $this->http_buffer[] = $output; + } + curl_close($ch); + + return $output; + } + + /** + * Process + * + * @param $null1 + * @param $null2 + * + * null params are not used and just to statify Strict Function Declaration + * @return bool + * @throws Exception + * @throws Exception + */ + public function __process($null1 = null, $null2 = null) + { + + if ($this->http_buffer) { + $this->__parseBuffer(); + } else { + $this->__sendBody(); + $this->__parseBuffer(); + } + + $this->saveSession(); + + return true; + } + + public function __parseBuffer() + { + + while ($this->http_buffer) { + + $idx = key($this->http_buffer); + $buffer = $this->http_buffer[$idx]; + unset($this->http_buffer[$idx]); + + if ($buffer) { + + $xml = new SimpleXMLElement($buffer); + $children = $xml->xpath('child::node()'); + + foreach ($children as $child) { + $buff = $child->asXML(); + $this->log->log('RECV: ' . $buff, Log::LEVEL_VERBOSE); + xml_parse($this->parser, $buff, false); + } + } + } + } + + /** + * Save session + * + */ + public function saveSession() + { + + $_SESSION['XMPPHP_BOSH']['RID'] = (string)$this->rid; + $_SESSION['XMPPHP_BOSH']['SID'] = (string)$this->sid; + $_SESSION['XMPPHP_BOSH']['authed'] = (boolean)$this->authed; + $_SESSION['XMPPHP_BOSH']['basejid'] = (string)$this->basejid; + $_SESSION['XMPPHP_BOSH']['fulljid'] = (string)$this->fulljid; + $_SESSION['XMPPHP_BOSH']['inactivity'] = (string)$this->inactivity; + $_SESSION['XMPPHP_BOSH']['lat'] = (string)time(); + + if ($this->session == 'ON_FILE') { + + $session_file = $this->getSessionFile(); + $session_file_fp = fopen($session_file, 'r'); + flock($session_file_fp, LOCK_EX); + // log->log('SEND: ' . $msg, Log::LEVEL_VERBOSE); + $msg = new SimpleXMLElement($msg); + $this->__sendBody($this->__buildBody($msg), true); + } + + /** + * Reset + * + * @throws Exception + */ + public function reset() + { + + $this->xml_depth = 0; + unset($this->xmlobj); + $this->xmlobj = array(); + $this->setupParser(); + $body = $this->__buildBody(); + $body->addAttribute('to', $this->host); + $body->addAttribute('xmpp:restart', 'true', 'urn:xmpp:xbosh'); + $buff = ''; + $response = $this->__sendBody($body); + $this->been_reset = true; + xml_parse($this->parser, $buff, false); + } + + /** + * Disconnect + * + * @throws Exception + */ + public function disconnect() + { + + parent::disconnect(); + + if ($this->session == 'ON_FILE') { + unlink($this->getSessionFile()); + } else { + $keys = array('RID', 'SID', 'authed', 'basejid', 'fulljid', 'inactivity', 'lat'); + foreach ($keys as $key) { + unset($_SESSION['XMPPHP_BOSH'][$key]); + } + } + } +} diff --git a/vendor/diogocomposer/xmpphp/XMPPHP/Exception.php b/vendor/diogocomposer/xmpphp/XMPPHP/Exception.php new file mode 100644 index 0000000000..525bdd962a --- /dev/null +++ b/vendor/diogocomposer/xmpphp/XMPPHP/Exception.php @@ -0,0 +1,49 @@ + + * @author Stephan Wentz + * @author Michael Garvin + * @author Alexander Birkner (https://github.com/BirknerAlex) + * @author zorn-v (https://github.com/zorn-v/xmpphp/) + * @author GNU social + * @copyright 2008 Nathanael C. Fritz + */ + +namespace XMPPHP; + +use Exception as ObjectException; + +/** + * XMPPHP Exception + * + * @package XMPPHP + * @author Nathanael C. Fritz + * @author Stephan Wentz + * @author Michael Garvin + * @copyright 2008 Nathanael C. Fritz + * @version $Id$ + */ +class Exception extends ObjectException +{ +} diff --git a/vendor/diogocomposer/xmpphp/XMPPHP/Log.php b/vendor/diogocomposer/xmpphp/XMPPHP/Log.php new file mode 100644 index 0000000000..7b511d5014 --- /dev/null +++ b/vendor/diogocomposer/xmpphp/XMPPHP/Log.php @@ -0,0 +1,129 @@ + + * @author Stephan Wentz + * @author Michael Garvin + * @author Alexander Birkner (https://github.com/BirknerAlex) + * @author zorn-v (https://github.com/zorn-v/xmpphp/) + * @author GNU social + * @copyright 2008 Nathanael C. Fritz + */ + +namespace XMPPHP; + +/** + * XMPPHP Log + * + * @package XMPPHP + * @author Nathanael C. Fritz + * @author Stephan Wentz + * @author Michael Garvin + * @copyright 2008 Nathanael C. Fritz + * @version $Id$ + */ +class Log +{ + const LEVEL_ERROR = 0; + const LEVEL_WARNING = 1; + const LEVEL_INFO = 2; + const LEVEL_DEBUG = 3; + const LEVEL_VERBOSE = 4; + + /** + * @var array + */ + protected $data = array(); + + /** + * @var array + */ + protected $names = array('ERROR', 'WARNING', 'INFO', 'DEBUG', 'VERBOSE'); + + /** + * @var integer + */ + protected $runlevel; + + /** + * @var boolean + */ + protected $printout; + + /** + * Constructor + * + * @param boolean $printout + * @param int $runlevel + */ + public function __construct($printout = false, $runlevel = self::LEVEL_INFO) + { + $this->printout = (boolean)$printout; + $this->runlevel = (int)$runlevel; + } + + /** + * Add a message to the log data array + * If printout in this instance is set to true, directly output the message + * + * @param string $msg + * @param integer $runlevel + */ + public function log($msg, $runlevel = self::LEVEL_INFO) + { + $time = time(); + #$this->data[] = array($this->runlevel, $msg, $time); + if ($this->printout and $runlevel <= $this->runlevel) { + $this->writeLine($msg, $runlevel, $time); + } + } + + protected function writeLine($msg, $runlevel, $time) + { + //echo date('Y-m-d H:i:s', $time)." [".$this->names[$runlevel]."]: ".$msg."\n"; + echo $time . " [" . $this->names[$runlevel] . "]: " . $msg . "\n"; + flush(); + } + + /** + * Output the complete log. + * Log will be cleared if $clear = true + * + * @param boolean $clear + * @param integer $runlevel + */ + public function printout($clear = true, $runlevel = null) + { + if ($runlevel === null) { + $runlevel = $this->runlevel; + } + foreach ($this->data as $data) { + if ($runlevel <= $data[0]) { + $this->writeLine($data[1], $runlevel, $data[2]); + } + } + if ($clear) { + $this->data = array(); + } + } +} diff --git a/vendor/diogocomposer/xmpphp/XMPPHP/Roster.php b/vendor/diogocomposer/xmpphp/XMPPHP/Roster.php new file mode 100644 index 0000000000..799c549140 --- /dev/null +++ b/vendor/diogocomposer/xmpphp/XMPPHP/Roster.php @@ -0,0 +1,183 @@ + + * @author Stephan Wentz + * @author Michael Garvin + * @author Alexander Birkner (https://github.com/BirknerAlex) + * @author zorn-v (https://github.com/zorn-v/xmpphp/) + * @author GNU social + * @copyright 2008 Nathanael C. Fritz + */ + +namespace XMPPHP; + +/** + * XMPPHP Roster + * + * @package XMPPHP + * @author Nathanael C. Fritz + * @author Stephan Wentz + * @author Michael Garvin + * @copyright 2008 Nathanael C. Fritz + * @version $Id$ + */ +class Roster +{ + /** + * Roster array, handles contacts and presence. Indexed by jid. + * Contains array with potentially two indexes 'contact' and 'presence' + * @var array + */ + protected $roster_array = array(); + + /** + * Constructor + * @param array $roster_array + */ + public function __construct($roster_array = array()) + { + if ($this->verifyRoster($roster_array)) { + $this->roster_array = $roster_array; //Allow for pre-population with existing roster + } else { + $this->roster_array = array(); + } + } + + /** + * + * Check that a given roster array is of a valid structure (empty is still valid) + * + * @param array $roster_array + * @return bool + */ + protected function verifyRoster($roster_array) + { + #TODO once we know *what* a valid roster array looks like + return true; + } + + /** + * + * Retrieve contact via jid + * + * @param string $jid + * @return mixed + */ + public function getContact($jid) + { + if ($this->isContact($jid)) { + return $this->roster_array[$jid]['contact']; + } + } + + /** + * + * Discover if a contact exists in the roster via jid + * + * @param string $jid + * @return bool + */ + public function isContact($jid) + { + return (array_key_exists($jid, $this->roster_array)); + } + + /** + * + * Set presence + * + * @param string $presence + * @param integer $priority + * @param string $show + * @param string $status + */ + public function setPresence($presence, $priority, $show, $status) + { + $presence = explode('/', $presence, 2); + $jid = $presence[0]; + $resource = isset($presence[1]) ? $presence[1] : ''; + if ($show != 'unavailable') { + if (!$this->isContact($jid)) { + $this->addContact($jid, 'not-in-roster'); + } + $this->roster_array[$jid]['presence'][$resource] = array('priority' => $priority, 'show' => $show, 'status' => $status); + } else { //Nuke unavailable resources to save memory + unset($this->roster_array[$jid]['resource'][$resource]); + unset($this->roster_array[$jid]['presence'][$resource]); + } + } + + /** + * + * Add given contact to roster + * + * @param string $jid + * @param string $subscription + * @param string $name + * @param array $groups + */ + public function addContact($jid, $subscription, $name = '', $groups = array()) + { + $contact = array('jid' => $jid, 'subscription' => $subscription, 'name' => $name, 'groups' => $groups); + if ($this->isContact($jid)) { + $this->roster_array[$jid]['contact'] = $contact; + } else { + $this->roster_array[$jid] = array('contact' => $contact); + } + } + + /* + * + * Return best presence for jid + * + * @param string $jid + */ + + public function getPresence($jid) + { + $split = explode('/', $jid, 2); + $jid = $split[0]; + if ($this->isContact($jid)) { + $current = array('resource' => '', 'active' => '', 'priority' => -129, 'show' => '', 'status' => ''); //Priorities can only be -128 = 127 + foreach ($this->roster_array[$jid]['presence'] as $resource => $presence) { + //Highest available priority or just highest priority + if ($presence['priority'] > $current['priority'] and (($presence['show'] == "chat" or $presence['show'] == "available") or ($current['show'] != "chat" or $current['show'] != "available"))) { + $current = $presence; + $current['resource'] = $resource; + } + } + return $current; + } + } + + /** + * + * Get roster + * + */ + public function getRoster() + { + return $this->roster_array; + } +} diff --git a/vendor/diogocomposer/xmpphp/XMPPHP/XMLObj.php b/vendor/diogocomposer/xmpphp/XMPPHP/XMLObj.php new file mode 100644 index 0000000000..de359ae96a --- /dev/null +++ b/vendor/diogocomposer/xmpphp/XMPPHP/XMLObj.php @@ -0,0 +1,174 @@ + + * @author Stephan Wentz + * @author Michael Garvin + * @author Alexander Birkner (https://github.com/BirknerAlex) + * @author zorn-v (https://github.com/zorn-v/xmpphp/) + * @author GNU social + * @copyright 2008 Nathanael C. Fritz + */ + +namespace XMPPHP; + +/** + * XMPPHP XMLObject + * + * @package XMPPHP + * @author Nathanael C. Fritz + * @author Stephan Wentz + * @author Michael Garvin + * @copyright 2008 Nathanael C. Fritz + * @version $Id$ + */ +class XMLObj +{ + /** + * Tag name + * + * @var string + */ + public $name; + + /** + * Namespace + * + * @var string + */ + public $ns; + + /** + * Attributes + * + * @var array + */ + public $attrs = array(); + + /** + * Subs? + * + * @var array + */ + public $subs = array(); + + /** + * Node data + * + * @var string + */ + public $data = ''; + + /** + * Constructor + * + * @param string $name + * @param string $ns + * @param array $attrs + * @param string $data + */ + public function __construct($name, $ns = '', $attrs = array(), $data = '') + { + $this->name = strtolower($name); + $this->ns = $ns; + if (is_array($attrs) && count($attrs)) { + foreach ($attrs as $key => $value) { + $this->attrs[strtolower($key)] = $value; + } + } + $this->data = $data; + } + + /** + * Dump this XML Object to output. + * + * @param integer $depth + */ + public function printObj($depth = 0) + { + print str_repeat("\t", $depth) . $this->name . " " . $this->ns . ' ' . $this->data; + print "\n"; + foreach ($this->subs as $sub) { + $sub->printObj($depth + 1); + } + } + + /** + * Return this XML Object in xml notation + * + * @param string $str + * @return string + */ + public function toString($str = '') + { + $str .= "<{$this->name} xmlns='{$this->ns}' "; + foreach ($this->attrs as $key => $value) { + if ($key != 'xmlns') { + $value = htmlspecialchars($value); + $str .= "$key='$value' "; + } + } + $str .= ">"; + foreach ($this->subs as $sub) { + $str .= $sub->toString(); + } + $body = htmlspecialchars($this->data); + $str .= "$bodyname}>"; + return $str; + } + + /** + * Has this XML Object the given sub? + * + * @param string $name + * @param null $ns + * @return boolean + */ + public function hasSub($name, $ns = null) + { + foreach ($this->subs as $sub) { + if (($name == "*" or $sub->name == $name) and ($ns == null or $sub->ns == $ns)) { + return true; + } + } + return false; + } + + /** + * Return a sub + * + * @param string $name + * @param string $attrs + * @param string $ns + * @return mixed + */ + public function sub($name, $attrs = null, $ns = null) + { + #TODO attrs is ignored + foreach ($this->subs as $sub) { + if ($sub->name == $name and ($ns == null or $sub->ns == $ns)) { + return $sub; + } + } + } +} diff --git a/vendor/diogocomposer/xmpphp/XMPPHP/XMLStream.php b/vendor/diogocomposer/xmpphp/XMPPHP/XMLStream.php new file mode 100644 index 0000000000..615e7ca12d --- /dev/null +++ b/vendor/diogocomposer/xmpphp/XMPPHP/XMLStream.php @@ -0,0 +1,804 @@ + + * @author Stephan Wentz + * @author Michael Garvin + * @author Alexander Birkner (https://github.com/BirknerAlex) + * @author zorn-v (https://github.com/zorn-v/xmpphp/) + * @author GNU social + * @copyright 2008 Nathanael C. Fritz + */ + +namespace XMPPHP; + +/** Exception */ +require_once __DIR__ . DIRECTORY_SEPARATOR . 'Exception.php'; + +/** XMLObj */ +require_once __DIR__ . DIRECTORY_SEPARATOR . 'XMLObj.php'; + +/** Log */ +require_once __DIR__ . DIRECTORY_SEPARATOR . 'Log.php'; + + +/** + * XMPPHP XMLStream + * + * @package XMPPHP + * @author Nathanael C. Fritz + * @author Stephan Wentz + * @author Michael Garvin + * @copyright 2008 Nathanael C. Fritz + * @version $Id$ + */ +class XMLStream +{ + /** + * @var resource + */ + protected $socket; + /** + * @var resource + */ + protected $parser; + /** + * @var string + */ + protected $buffer; + /** + * @var integer + */ + protected $xml_depth = 0; + /** + * @var string + */ + protected $host; + /** + * @var integer + */ + protected $port; + /** + * @var string + */ + protected $stream_start = ''; + /** + * @var string + */ + protected $stream_end = ''; + /** + * @var boolean + */ + protected $disconnected = false; + /** + * @var boolean + */ + protected $sent_disconnect = false; + /** + * @var array + */ + protected $ns_map = array(); + /** + * @var array + */ + protected $current_ns = array(); + /** + * @var array + */ + protected $xmlobj = null; + /** + * @var array + */ + protected $nshandlers = array(); + /** + * @var array + */ + protected $xpathhandlers = array(); + /** + * @var array + */ + protected $idhandlers = array(); + /** + * @var array + */ + protected $eventhandlers = array(); + /** + * @var integer + */ + protected $lastid = 0; + /** + * @var string + */ + protected $default_ns; + /** + * @var string[] + */ + protected $until = []; + /** + * @var int[] + */ + protected $until_count = []; + /** + * @var array + */ + protected $until_happened = false; + /** + * @var array + */ + protected $until_payload = array(); + /** + * @var Log + */ + protected $log; + /** + * @var boolean + */ + protected $reconnect = true; + /** + * @var boolean + */ + protected $been_reset = false; + /** + * @var boolean + */ + protected $is_server; + /** + * @var float + */ + protected $last_send = 0; + /** + * @var boolean + */ + protected $use_ssl = false; + /** + * @var integer + */ + protected $reconnectTimeout = 30; + + /** + * Constructor + * + * @param string $host + * @param string $port + * @param boolean $printlog + * @param string $loglevel + * @param boolean $is_server + */ + public function __construct($host = null, $port = null, $printlog = false, $loglevel = null, $is_server = false) + { + $this->reconnect = !$is_server; + $this->is_server = $is_server; + $this->host = $host; + $this->port = $port; + $this->setupParser(); + $this->log = new Log($printlog, $loglevel); + } + + /** + * Setup the XML parser + */ + public function setupParser() + { + $this->parser = xml_parser_create('UTF-8'); + xml_parser_set_option($this->parser, XML_OPTION_SKIP_WHITE, 1); + xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, 'UTF-8'); + xml_set_object($this->parser, $this); + xml_set_element_handler($this->parser, 'startXML', 'endXML'); + xml_set_character_data_handler($this->parser, 'charXML'); + } + + /** + * Destructor + * Cleanup connection + */ + public function __destruct() + { + if (!$this->disconnected && $this->socket) { + $this->disconnect(); + } + } + + /** + * Disconnect from XMPP Host + */ + public function disconnect() + { + $this->log->log("Disconnecting...", Log::LEVEL_VERBOSE); + if (false == (bool)$this->socket) { + return; + } + $this->reconnect = false; + $this->send($this->stream_end); + $this->sent_disconnect = true; + $this->processUntil('end_stream', 5); + $this->disconnected = true; + } + + /** + * Send to socket + * + * @param string $msg + * @param null $timeout + * @return bool|int + * @throws Exception + */ + public function send($msg, $timeout = NULL) + { + + if (is_null($timeout)) { + $secs = NULL; + $usecs = NULL; + } else if ($timeout == 0) { + $secs = 0; + $usecs = 0; + } else { + $maximum = $timeout * 1000000; + $usecs = $maximum % 1000000; + $secs = floor(($maximum - $usecs) / 1000000); + } + + $read = array(); + $write = array($this->socket); + $except = array(); + + $select = @stream_select($read, $write, $except, $secs, $usecs); + + if ($select === False) { + $this->log->log("ERROR sending message; reconnecting."); + $this->doReconnect(); + # TODO: retry send here + return false; + } elseif ($select > 0) { + $this->log->log("Socket is ready; send it.", Log::LEVEL_VERBOSE); + } else { + $this->log->log("Socket is not ready; break.", Log::LEVEL_ERROR); + return false; + } + + $sentbytes = @fwrite($this->socket, $msg); + $this->log->log("SENT: " . mb_substr($msg, 0, $sentbytes, '8bit'), Log::LEVEL_VERBOSE); + if ($sentbytes === FALSE) { + $this->log->log("ERROR sending message; reconnecting.", Log::LEVEL_ERROR); + $this->doReconnect(); + return false; + } + $this->log->log("Successfully sent $sentbytes bytes.", Log::LEVEL_VERBOSE); + return $sentbytes; + } + + /** + * Reconnect XMPP Host + * @throws Exception + */ + public function doReconnect() + { + if (!$this->is_server) { + $this->log->log("Reconnecting ($this->reconnectTimeout)...", Log::LEVEL_WARNING); + $this->connect($this->reconnectTimeout, false, false); + $this->reset(); + $this->event('reconnect'); + } + } + + /** + * Connect to XMPP Host + * + * @param integer $timeout + * @param boolean $persistent + * @param boolean $sendinit + * @throws Exception + * @throws Exception + */ + public function connect($timeout = 30, $persistent = false, $sendinit = true) + { + $this->sent_disconnect = false; + $starttime = time(); + + do { + $this->disconnected = false; + $this->sent_disconnect = false; + if ($persistent) { + $conflag = STREAM_CLIENT_CONNECT | STREAM_CLIENT_PERSISTENT; + } else { + $conflag = STREAM_CLIENT_CONNECT; + } + $conntype = 'tcp'; + if ($this->use_ssl) $conntype = 'ssl'; + $this->log->log("Connecting to $conntype://{$this->host}:{$this->port}"); + $this->socket = @stream_socket_client("$conntype://{$this->host}:{$this->port}", $errno, $errstr, $timeout, $conflag); + if (!$this->socket) { + $this->log->log("Could not connect.", Log::LEVEL_ERROR); + $this->disconnected = true; + # Take it easy for a few seconds + sleep(min($timeout, 5)); + } + } while (!$this->socket && (time() - $starttime) < $timeout); + + if ($this->socket) { + stream_set_blocking($this->socket, 1); + if ($sendinit) $this->send($this->stream_start); + } else { + throw new Exception("Could not connect before timeout."); + } + } + + /** + * Reset connection + */ + public function reset() + { + $this->xml_depth = 0; + unset($this->xmlobj); + $this->xmlobj = array(); + $this->setupParser(); + if (!$this->is_server) { + $this->send($this->stream_start); + } + $this->been_reset = true; + } + + /** + * Event? + * + * @param string $name + * @param string $payload + */ + public function event($name, $payload = null) + { + $this->log->log("EVENT: $name", Log::LEVEL_DEBUG); + foreach ($this->eventhandlers as $handler) { + if ($name == $handler[0]) { + if ($handler[2] === null) { + $handler[2] = $this; + } + $handler[2]->{$handler[1]}($payload); + } + } + foreach ($this->until as $key => $until) { + if (is_array($until)) { + if (in_array($name, $until)) { + $this->until_payload[$key][] = array($name, $payload); + if (!isset($this->until_count[$key])) { + $this->until_count[$key] = 0; + } + $this->until_count[$key] += 1; + #$this->until[$key] = false; + } + } + } + } + + /** + * Process until a specified event or a timeout occurs + * + * @param string|array $event + * @param integer $timeout + * @return string + * @throws Exception + */ + public function processUntil($event, $timeout = -1) + { + $start = time(); + if (!is_array($event)) $event = array($event); + $this->until[] = $event; + end($this->until); + $event_key = key($this->until); + reset($this->until); + $this->until_count[$event_key] = 0; + while (!$this->disconnected and $this->until_count[$event_key] < 1 and (time() - $start < $timeout or $timeout == -1)) { + $this->__process(); + } + if (array_key_exists($event_key, $this->until_payload)) { + $payload = $this->until_payload[$event_key]; + unset($this->until_payload[$event_key]); + unset($this->until_count[$event_key]); + unset($this->until[$event_key]); + } else { + $payload = array(); + } + return $payload; + } + + /** + * Core reading tool + * 0 -> only read if data is immediately ready + * NULL -> wait forever and ever + * integer -> process for this amount of time + * @param int $maximum + * @return bool + * @throws Exception + */ + + private function __process($maximum = 5) + { + + $remaining = $maximum; + + do { + $starttime = (microtime(true) * 1000000); + $read = array($this->socket); + $write = array(); + $except = array(); + if (is_null($maximum)) { + $secs = NULL; + $usecs = NULL; + } else if ($maximum == 0) { + $secs = 0; + $usecs = 0; + } else { + $usecs = $remaining % 1000000; + $secs = floor(($remaining - $usecs) / 1000000); + } + $updated = @stream_select($read, $write, $except, $secs, $usecs); + if ($updated === false) { + $this->log->log("Error on stream_select()", Log::LEVEL_VERBOSE); + if ($this->reconnect) { + $this->doReconnect(); + } else { + fclose($this->socket); + $this->socket = NULL; + return false; + } + } else if ($updated > 0) { + # XXX: Is this big enough? + $buff = @fread($this->socket, 4096); + if (!$buff) { + if ($this->reconnect) { + $this->doReconnect(); + } else { + fclose($this->socket); + $this->socket = NULL; + return false; + } + } + $this->log->log("RECV: $buff", Log::LEVEL_VERBOSE); + xml_parse($this->parser, $buff, false); + } // Otherwise, + // $updated == 0 means no changes during timeout. + + $endtime = (microtime(true) * 1000000); + $time_past = $endtime - $starttime; + $remaining = $remaining - $time_past; + } while (is_null($maximum) || $remaining > 0); + return true; + } + + /** + * Return the log instance + * + * @return Log + */ + public function getLog() + { + return $this->log; + } + + /** + * Get next ID + * + * @return integer + */ + public function getId() + { + $this->lastid++; + return $this->lastid; + } + + /** + * Set SSL + * @param bool $use + */ + public function useSSL($use = true) + { + $this->use_ssl = $use; + } + + /** + * Add ID Handler + * + * @param integer $id + * @param string $pointer + * @param string $obj + */ + public function addIdHandler($id, $pointer, $obj = null) + { + $this->idhandlers[$id] = array($pointer, $obj); + } + + /** + * Add Handler + * + * @param string $name + * @param string $ns + * @param string $pointer + * @param string $obj + * @param integer $depth + */ + public function addHandler($name, $ns, $pointer, $obj = null, $depth = 1) + { + #TODO deprication warning + $this->nshandlers[] = array($name, $ns, $pointer, $obj, $depth); + } + + /** + * Add XPath Handler + * + * @param string $xpath + * @param string $pointer + * @param + */ + public function addXPathHandler($xpath, $pointer, $obj = null) + { + if (preg_match_all("/\(?{[^\}]+}\)?(\/?)[^\/]+/", $xpath, $regs)) { + $ns_tags = $regs[0]; + } else { + $ns_tags = array($xpath); + } + foreach ($ns_tags as $ns_tag) { + list($l, $r) = explode("}", $ns_tag); + if ($r != null) { + $xpart = array(substr($l, 1), $r); + } else { + $xpart = array(null, $l); + } + $xpath_array[] = $xpart; + } + $this->xpathhandlers[] = array($xpath_array, $pointer, $obj); + } + + /** + * Add Event Handler + * + * @param $name + * @param string $pointer + * @param string $obj + */ + public function addEventHandler($name, $pointer, $obj) + { + $this->eventhandlers[] = array($name, $pointer, $obj); + } + + public function setReconnectTimeout($timeout) + { + $this->reconnectTimeout = $timeout; + } + + /** + * Are we are disconnected? + * + * @return boolean + */ + public function isDisconnected() + { + return $this->disconnected; + } + + /** + * Process + * + */ + public function process() + { + $this->__process(NULL); + } + + /** + * Process until a timeout occurs + * + * @param integer $timeout + * @return string + * @throws Exception + */ + public function processTime($timeout = NULL) + { + if (is_null($timeout)) { + return $this->__process(NULL); + } else { + return $this->__process($timeout * 1000000); + } + } + + /** + * Obsolete? + * @param $socket + */ + public function Xapply_socket($socket) + { + $this->socket = $socket; + } + + /** + * XML start callback + * + * @param resource $parser + * @param string $name + * @param $attr + * @see xml_set_element_handler + */ + public function startXML($parser, $name, $attr) + { + if ($this->been_reset) { + $this->been_reset = false; + $this->xml_depth = 0; + } + $this->xml_depth++; + if (array_key_exists('XMLNS', $attr)) { + $this->current_ns[$this->xml_depth] = $attr['XMLNS']; + } else { + $this->current_ns[$this->xml_depth] = $this->current_ns[$this->xml_depth - 1]; + if (!$this->current_ns[$this->xml_depth]) $this->current_ns[$this->xml_depth] = $this->default_ns; + } + $ns = $this->current_ns[$this->xml_depth]; + foreach ($attr as $key => $value) { + if (strstr($key, ":")) { + $key = explode(':', $key); + $key = $key[1]; + $this->ns_map[$key] = $value; + } + } + if (!strstr($name, ":") === false) { + $name = explode(':', $name); + $ns = $this->ns_map[$name[0]]; + $name = $name[1]; + } + $obj = new XMLObj($name, $ns, $attr); + if ($this->xml_depth > 1) { + $this->xmlobj[$this->xml_depth - 1]->subs[] = $obj; + } + $this->xmlobj[$this->xml_depth] = $obj; + } + + /** + * XML end callback + * + * @param resource $parser + * @param string $name + * @throws Exception + * @see xml_set_element_handler + * + */ + public function endXML($parser, $name) + { + #$this->log->log("Ending $name", Log::LEVEL_DEBUG); + #print "$name\n"; + if ($this->been_reset) { + $this->been_reset = false; + $this->xml_depth = 0; + } + $this->xml_depth--; + if ($this->xml_depth == 1) { + #clean-up old objects + #$found = false; #FIXME This didn't appear to be in use --Gar + foreach ($this->xpathhandlers as $handler) { + if (is_array($this->xmlobj) && array_key_exists(2, $this->xmlobj)) { + $searchxml = $this->xmlobj[2]; + $nstag = array_shift($handler[0]); + if (($nstag[0] == null or $searchxml->ns == $nstag[0]) and ($nstag[1] == "*" or $nstag[1] == $searchxml->name)) { + foreach ($handler[0] as $nstag) { + if ($searchxml !== null and $searchxml->hasSub($nstag[1], $ns = $nstag[0])) { + $searchxml = $searchxml->sub($nstag[1], $ns = $nstag[0]); + } else { + $searchxml = null; + break; + } + } + if ($searchxml !== null) { + if ($handler[2] === null) $handler[2] = $this; + $this->log->log("Calling {$handler[1]}", Log::LEVEL_DEBUG); + $handler[2]->{$handler[1]}($this->xmlobj[2]); + } + } + } + } + foreach ($this->nshandlers as $handler) { + if ($handler[4] != 1 and array_key_exists(2, $this->xmlobj) and $this->xmlobj[2]->hasSub($handler[0])) { + $searchxml = $this->xmlobj[2]->sub($handler[0]); + } elseif (is_array($this->xmlobj) and array_key_exists(2, $this->xmlobj)) { + $searchxml = $this->xmlobj[2]; + } + if ($searchxml !== null and $searchxml->name == $handler[0] and ($searchxml->ns == $handler[1] or (!$handler[1] and $searchxml->ns == $this->default_ns))) { + if ($handler[3] === null) $handler[3] = $this; + $this->log->log("Calling {$handler[2]}", Log::LEVEL_DEBUG); + $handler[3]->{$handler[2]}($this->xmlobj[2]); + } + } + foreach ($this->idhandlers as $id => $handler) { + if (array_key_exists('id', $this->xmlobj[2]->attrs) and $this->xmlobj[2]->attrs['id'] == $id) { + if ($handler[1] === null) $handler[1] = $this; + $handler[1]->{$handler[0]}($this->xmlobj[2]); + #id handlers are only used once + unset($this->idhandlers[$id]); + break; + } + } + if (is_array($this->xmlobj)) { + $this->xmlobj = array_slice($this->xmlobj, 0, 1); + if (isset($this->xmlobj[0]) && $this->xmlobj[0] instanceof XMLObj) { + $this->xmlobj[0]->subs = null; + } + } + unset($this->xmlobj[2]); + } + if ($this->xml_depth == 0 and !$this->been_reset) { + if (!$this->disconnected) { + if (!$this->sent_disconnect) { + $this->send($this->stream_end); + } + $this->disconnected = true; + $this->sent_disconnect = true; + fclose($this->socket); + if ($this->reconnect) { + $this->doReconnect(); + } + } + $this->event('end_stream'); + } + } + + /** + * XML character callback + * @param resource $parser + * @param string $data + * @see xml_set_character_data_handler + * + */ + public function charXML($parser, $data) + { + if (array_key_exists($this->xml_depth, $this->xmlobj)) { + $this->xmlobj[$this->xml_depth]->data .= $data; + } + } + + /** + * Read from socket + */ + public function read() + { + $buff = @fread($this->socket, 1024); + if (!$buff) { + if ($this->reconnect) { + $this->doReconnect(); + } else { + fclose($this->socket); + return false; + } + } + $this->log->log("RECV: $buff", Log::LEVEL_VERBOSE); + xml_parse($this->parser, $buff, false); + } + + public function time() + { + list($usec, $sec) = explode(" ", microtime()); + return (float)$sec + (float)$usec; + } + + public function readyToProcess() + { + $read = array($this->socket); + $write = array(); + $except = array(); + $updated = @stream_select($read, $write, $except, 0); + return (($updated !== false) && ($updated > 0)); + } +} diff --git a/vendor/diogocomposer/xmpphp/XMPPHP/XMPP.php b/vendor/diogocomposer/xmpphp/XMPPHP/XMPP.php new file mode 100644 index 0000000000..55b58db0fd --- /dev/null +++ b/vendor/diogocomposer/xmpphp/XMPPHP/XMPP.php @@ -0,0 +1,477 @@ + + * @author Stephan Wentz + * @author Michael Garvin + * @author Alexander Birkner (https://github.com/BirknerAlex) + * @author zorn-v (https://github.com/zorn-v/xmpphp/) + * @author GNU social + * @copyright 2008 Nathanael C. Fritz + */ + +namespace XMPPHP; + +/** XMPPHP_XMLStream */ +require_once __DIR__ . DIRECTORY_SEPARATOR . 'XMLStream.php'; +require_once __DIR__ . DIRECTORY_SEPARATOR . 'Roster.php'; + + +/** + * XMPPHP XMPP + * + * @package XMPPHP + * @author Nathanael C. Fritz + * @author Stephan Wentz + * @author Michael Garvin + * @copyright 2008 Nathanael C. Fritz + * @version $Id$ + */ +class XMPP extends XMLStream +{ + /** + * @var string + */ + public $server; + + /** + * @var string + */ + public $user; + /** + * @var boolean + */ + public $track_presence = true; + /** + * @var object + */ + public $roster; + /** + * @var string + */ + protected $password; + /** + * @var string + */ + protected $resource; + /** + * @var string + */ + protected $fulljid; + /** + * @var string + */ + protected $basejid; + /** + * @var boolean + */ + protected $authed = false; + protected $session_started = false; + /** + * @var boolean + */ + protected $auto_subscribe = false; + /** + * @var boolean + */ + protected $use_encryption = true; + + /** + * Constructor + * + * @param string $host + * @param integer $port + * @param string $user + * @param string $password + * @param string $resource + * @param string $server + * @param boolean $printlog + * @param string $loglevel + */ + public function __construct($host, $port, $user, $password, $resource, $server = null, $printlog = false, $loglevel = null) + { + parent::__construct($host, $port, $printlog, $loglevel); + + $this->user = $user; + $this->password = $password; + $this->resource = $resource; + if (!$server) { + $server = $host; + } + $this->server = $server; + $this->basejid = $this->user . '@' . $this->host; + + $this->roster = new Roster(); + $this->track_presence = true; + + $this->stream_start = ''; + $this->stream_end = ''; + $this->default_ns = 'jabber:client'; + + $this->addXPathHandler('{http://etherx.jabber.org/streams}features', 'features_handler'); + $this->addXPathHandler('{urn:ietf:params:xml:ns:xmpp-sasl}success', 'sasl_success_handler'); + $this->addXPathHandler('{urn:ietf:params:xml:ns:xmpp-sasl}failure', 'sasl_failure_handler'); + $this->addXPathHandler('{urn:ietf:params:xml:ns:xmpp-tls}proceed', 'tls_proceed_handler'); + $this->addXPathHandler('{jabber:client}message', 'message_handler'); + $this->addXPathHandler('{jabber:client}presence', 'presence_handler'); + $this->addXPathHandler('iq/{jabber:iq:roster}query', 'roster_iq_handler'); + } + + /** + * Turn encryption on/ff + * + * @param boolean $useEncryption + */ + public function useEncryption($useEncryption = true) + { + $this->use_encryption = $useEncryption; + } + + /** + * Turn on auto-authorization of subscription requests. + * + * @param boolean $autoSubscribe + */ + public function autoSubscribe($autoSubscribe = true) + { + $this->auto_subscribe = $autoSubscribe; + } + + /** + * Send XMPP Message + * + * @param string $to + * @param string $body + * @param string $type + * @param string $subject + * @param null $payload + * @throws Exception + */ + public function message($to, $body, $type = 'chat', $subject = null, $payload = null) + { + if ($this->disconnected) { + throw new Exception('You need to connect first'); + } + + if (empty($type)) { + $type = 'chat'; + } + + $to = htmlspecialchars($to); + $body = htmlspecialchars($body); + $subject = htmlspecialchars($subject); + $subject = ($subject) ? '' . $subject . '' : ''; + $payload = ($payload) ? $payload : ''; + $sprintf = '%s%s%s'; + $output = sprintf($sprintf, $this->fulljid, $to, $type, $subject, $body, $payload); + $this->send($output); + } + + /** + * Set Presence + * + * @param string $status + * @param string $show + * @param string $to + * @param string $type + * @param null $priority + * @throws Exception + */ + public function presence($status = null, $show = 'available', $to = null, $type = 'available', $priority = null) + { + if ($this->disconnected) { + throw new Exception('You need to connect first'); + } + + if ($type == 'available') { + $type = ''; + } + $to = htmlspecialchars($to); + $status = htmlspecialchars($status); + if ($show == 'unavailable') { + $type = 'unavailable'; + } + + $out = "send($out); + } + + /** + * Send Auth request + * + * @param string $jid + */ + public function subscribe($jid) + { + $this->send(""); + #$this->send(""); + } + + /** + * Message handler + * + * @param string $xml + */ + public function message_handler($xml) + { + if (isset($xml->attrs['type'])) { + $payload['type'] = $xml->attrs['type']; + } else { + $payload['type'] = 'chat'; + } + $body = $xml->sub('body'); + $payload['from'] = $xml->attrs['from']; + $payload['body'] = is_object($body) ? $body->data : false; // $xml->sub('body')->data; + $payload['xml'] = $xml; + $this->log->log("Message: {$payload['body']}", Log::LEVEL_DEBUG); + $this->event('message', $payload); + } + + /** + * Presence handler + * + * @param string $xml + */ + public function presence_handler($xml) + { + $payload['type'] = (isset($xml->attrs['type'])) ? $xml->attrs['type'] : 'available'; + $payload['show'] = (isset($xml->sub('show')->data)) ? $xml->sub('show')->data : $payload['type']; + $payload['from'] = $xml->attrs['from']; + $payload['status'] = (isset($xml->sub('status')->data)) ? $xml->sub('status')->data : ''; + $payload['priority'] = (isset($xml->sub('priority')->data)) ? intval($xml->sub('priority')->data) : 0; + $payload['xml'] = $xml; + if ($this->track_presence) { + $this->roster->setPresence($payload['from'], $payload['priority'], $payload['show'], $payload['status']); + } + $this->log->log("Presence: {$payload['from']} [{$payload['show']}] {$payload['status']}", Log::LEVEL_DEBUG); + if (array_key_exists('type', $xml->attrs) and $xml->attrs['type'] == 'subscribe') { + if ($this->auto_subscribe) { + $this->send(""); + $this->send(""); + } + $this->event('subscription_requested', $payload); + } elseif (array_key_exists('type', $xml->attrs) and $xml->attrs['type'] == 'subscribed') { + $this->event('subscription_accepted', $payload); + } else { + $this->event('presence', $payload); + } + } + + /** + * Retrieves the roster + * + */ + public function getRoster() + { + $id = $this->getID(); + $this->send(""); + } + + /** + * Retrieves the vcard + * @param null $jid + */ + public function getVCard($jid = null) + { + $id = $this->getID(); + $this->addIdHandler($id, 'vcard_get_handler'); + if ($jid) { + $this->send(""); + } else { + $this->send(""); + } + } + + /** + * Features handler + * + * @param string $xml + */ + protected function features_handler($xml) + { + if ($xml->hasSub('starttls') and $this->use_encryption) { + $this->send(""); + } elseif ($xml->hasSub('bind') and $this->authed) { + $id = $this->getId(); + $this->addIdHandler($id, 'resource_bind_handler'); + $this->send("{$this->resource}"); + } else { + $this->log->log("Attempting Auth..."); + if ($this->password) { + $this->send("" . base64_encode("\x00" . $this->user . "\x00" . $this->password) . ""); + } else { + $this->send(""); + } + } + } + + /** + * SASL success handler + * + * @param string $xml + */ + protected function sasl_success_handler($xml) + { + $this->log->log("Auth success!"); + $this->authed = true; + $this->reset(); + } + + /** + * SASL feature handler + * + * @param string $xml + * @throws Exception + */ + protected function sasl_failure_handler($xml) + { + $this->log->log("Auth failed!", Log::LEVEL_ERROR); + $this->disconnect(); + + throw new Exception('Auth failed!'); + } + + /** + * Resource bind handler + * + * @param string $xml + */ + protected function resource_bind_handler($xml) + { + if ($xml->attrs['type'] == 'result') { + $this->log->log("Bound to " . $xml->sub('bind')->sub('jid')->data); + $this->fulljid = $xml->sub('bind')->sub('jid')->data; + $jidarray = explode('/', $this->fulljid); + $this->jid = $jidarray[0]; + } + $id = $this->getId(); + $this->addIdHandler($id, 'session_start_handler'); + $this->send(""); + } + + /** + * Roster iq handler + * Gets all packets matching XPath "iq/{jabber:iq:roster}query' + * + * @param string $xml + */ + protected function roster_iq_handler($xml) + { + $status = "result"; + $xmlroster = $xml->sub('query'); + foreach ($xmlroster->subs as $item) { + $groups = array(); + if ($item->name == 'item') { + $jid = $item->attrs['jid']; //REQUIRED + $name = $item->attrs['name']; //MAY + $subscription = $item->attrs['subscription']; + foreach ($item->subs as $subitem) { + if ($subitem->name == 'group') { + $groups[] = $subitem->data; + } + } + $contacts[] = array($jid, $subscription, $name, $groups); //Store for action if no errors happen + } else { + $status = "error"; + } + } + if ($status == "result") { //No errors, add contacts + foreach ($contacts as $contact) { + $this->roster->addContact($contact[0], $contact[1], $contact[2], $contact[3]); + } + } + if ($xml->attrs['type'] == 'set') { + $this->send("attrs['id']}\" to=\"{$xml->attrs['from']}\" />"); + } + } + + /** + * Session start handler + * + * @param string $xml + */ + protected function session_start_handler($xml) + { + $this->log->log("Session started"); + $this->session_started = true; + $this->event('session_start'); + } + + /** + * TLS proceed handler + * + * @param string $xml + */ + protected function tls_proceed_handler($xml) + { + $this->log->log("Starting TLS encryption"); + stream_socket_enable_crypto($this->socket, true, STREAM_CRYPTO_METHOD_SSLv23_CLIENT); + $this->reset(); + } + + /** + * VCard retrieval handler + * + * @param XMLObj $xml + */ + protected function vcard_get_handler($xml) + { + $vcard_array = array(); + $vcard = $xml->sub('vcard'); + // go through all of the sub elements and add them to the vcard array + foreach ($vcard->subs as $sub) { + if ($sub->subs) { + $vcard_array[$sub->name] = array(); + foreach ($sub->subs as $sub_child) { + $vcard_array[$sub->name][$sub_child->name] = $sub_child->data; + } + } else { + $vcard_array[$sub->name] = $sub->data; + } + } + $vcard_array['from'] = $xml->attrs['from']; + $this->event('vcard', $vcard_array); + } +} diff --git a/vendor/diogocomposer/xmpphp/composer.json b/vendor/diogocomposer/xmpphp/composer.json new file mode 100644 index 0000000000..35a8e66b6c --- /dev/null +++ b/vendor/diogocomposer/xmpphp/composer.json @@ -0,0 +1,49 @@ +{ + "name": "diogocomposer/xmpphp", + "description": "XMPP PHP Library", + "type": "library", + "keywords": ["jabber", "xmpphp", "xmpp"], + "license": "GPL-2.0+", + "authors": [ + { + "name": "Nathan Fritz", + "email": "fritzy@netflint.net" + }, + { + "name": "Stephan Wentz", + "email": "stephan@wentz.it" + }, + { + "name": "Christian Weiske", + "email": "cweiske@cweiske.de" + }, + { + "name": "Vito Tafuni", + "email": "vitotafuni@gmail.com" + }, + { + "name": "Ivan Borzenkov", + "email": "ivan.borzenkov@gmail.com" + }, + { + "name": "bandroidx", + "email": "bandroidx@gmail.com" + }, + { + "name": "BirknerAlex", + "email": "alex.birkner@gmail.com" + }, + { + "name": "Diogo Cordeiro", + "email": "diogo@fc.up.pt" + } + ], + "autoload": { + "psr-4": { "XMPPHP\\": "XMPPHP" } + }, + "require": { + "php": ">=7.0.0", + "ext-mbstring": "*", + "ext-xml": "*" + } +} diff --git a/vendor/diogocomposer/xmpphp/examples/cli_longrun_example.php b/vendor/diogocomposer/xmpphp/examples/cli_longrun_example.php new file mode 100644 index 0000000000..c997264fb0 --- /dev/null +++ b/vendor/diogocomposer/xmpphp/examples/cli_longrun_example.php @@ -0,0 +1,141 @@ + 'talk.google.com', + 'port' => 5222, + 'username' => 'username', + 'password' => 'password', + 'proto' => 'xmpphp', + 'domain' => 'gmail.com', + 'printlog' => true, + 'loglevel' => XMPPHP\Log::LEVEL_VERBOSE, +); + +// Easy and simple for access to variables with their names +extract($conf); + +$conn = new XMPPHP\XMPP($server, $port, $username, $password, $proto, $domain, $printlog, $loglevel); +$conn->autoSubscribe(); + +$vcard_request = array(); + +try { + $conn->connect(); + + while (!$conn->isDisconnected()) { + $events = array('message', 'presence', 'end_stream', 'session_start', 'vcard'); + $payloads = $conn->processUntil($events); + + foreach ($payloads as $result) { + list($event, $data) = $result; + + if (isset($data)) { + extract($data); + } + + switch ($event) { + + case 'message': + + if (!$body) { + break; + } + + echo str_repeat('-', 80); + echo "Message from: $from"; + + if (isset($subject)) { + echo "Subject: $subject"; + } + + echo $body; + echo str_repeat('-', 80); + + $cmd = explode(' ', $body); + $body = "Mi no entender! '$body'"; + $conn->message($from, $body, $type); + + if (isset($cmd[0])) { + if ($cmd[0] == 'quit') { + $conn->disconnect(); + } + + if ($cmd[0] == 'break') { + $conn->send(''); + } + + if ($cmd[0] == 'vcard') { + if (!isset($cmd[1])) { + $cmd[1] = $conn->user; + } + + // Take a note which user requested which vcard + $vcard_request[$from] = $cmd[1]; + // Request the vcard + $conn->getVCard($cmd[1]); + } + } + break; + + case 'presence': + + echo "Presence: $from [$show] $status\n"; + break; + + case 'session_start': + + echo "Session start\n"; + $conn->getRoster(); + $conn->presence('Quasar!'); + break; + + case 'vcard': + + $deliver = array_keys($vcard_request, $from); + $msg = ''; + + foreach ($data as $key => $item) { + $msg .= $key . ': '; + + if (is_array($item)) { + $msg .= "\n"; + foreach ($item as $subkey => $subitem) { + $msg .= ' ' . $subkey . ':' . $subitem . "\n"; + } + } else { + $msg .= $item . "\n"; + } + } + + foreach ($deliver as $sendjid) { + unset($vcard_request[$sendjid]); + $conn->message($sendjid, $msg, 'chat'); + } + break; + } + } + } +} catch (XMPPHP\Exception $e) { + die($e->getMessage()); +} diff --git a/vendor/diogocomposer/xmpphp/examples/cli_longrun_example_bosh.php b/vendor/diogocomposer/xmpphp/examples/cli_longrun_example_bosh.php new file mode 100644 index 0000000000..5a93e756aa --- /dev/null +++ b/vendor/diogocomposer/xmpphp/examples/cli_longrun_example_bosh.php @@ -0,0 +1,104 @@ + 'server.tld', + 'port' => 5280, + 'username' => 'username', + 'password' => 'password', + 'proto' => 'xmpphp', + 'domain' => 'server.tld', + 'printlog' => true, + 'loglevel' => XMPPHP\Log::LEVEL_VERBOSE, +); + +// Easy and simple for access to variables with their names +extract($conf); + +$conn = new XMPPHP\BOSH($server, $port, $username, $password, $proto, $domain, $printlog, $loglevel); +$conn->autoSubscribe(); + +try { + $conn->connect('http://server.tld:5280/xmpp-httpbind'); + + while (!$conn->isDisconnected()) { + $events = array('message', 'presence', 'end_stream', 'session_start'); + $payloads = $conn->processUntil($events); + + foreach ($payloads as $result) { + list($event, $data) = $result; + + if (isset($data)) { + extract($data); + } + + switch ($event) { + + case 'message': + + if (!$body) { + break; + } + + echo str_repeat('-', 80); + echo "Message from: $from"; + + if (isset($subject)) { + echo "Subject: $subject"; + } + + echo $body; + echo str_repeat('-', 80); + + $cmd = explode(' ', $body); + $body = "Mi no entender! '$body'"; + $conn->message($from, $body, $type); + + if (isset($cmd[0])) { + if ($cmd[0] == 'quit') { + $conn->disconnect(); + } + + if ($cmd[0] == 'break') { + $conn->send(''); + } + } + break; + + case 'presence': + + echo "Presence: $from [$show] $status\n"; + break; + + case 'session_start': + + echo "Session start\n"; + $conn->getRoster(); + $conn->presence('Quasar!'); + break; + } + } + } +} catch (XMPPHP\Exception $e) { + die($e->getMessage()); +} diff --git a/vendor/diogocomposer/xmpphp/examples/sendmessage_example.php b/vendor/diogocomposer/xmpphp/examples/sendmessage_example.php new file mode 100644 index 0000000000..b71290d0c7 --- /dev/null +++ b/vendor/diogocomposer/xmpphp/examples/sendmessage_example.php @@ -0,0 +1,47 @@ + 'talk.google.com', + 'port' => 5222, + 'username' => 'username', + 'password' => 'password', + 'proto' => 'xmpphp', + 'domain' => 'gmail.com', + 'printlog' => true, + 'loglevel' => XMPPHP\Log::LEVEL_VERBOSE, +); + +// Easy and simple for access to variables with their names +extract($conf); + +$XMPP = new XMPPHP\XMPP($server, $port, $username, $password, $proto, $domain, $printlog, $loglevel); + +try { + $XMPP->connect(); + $XMPP->processUntil('session_start', 10); + $XMPP->presence(); + $XMPP->message('target.user@jabber.domain.com', 'Hello, how are you?', 'chat'); + $XMPP->disconnect(); +} catch (XMPPHP\Exception $e) { + die($e->getMessage()); +} diff --git a/vendor/diogocomposer/xmpphp/examples/webclient_example.php b/vendor/diogocomposer/xmpphp/examples/webclient_example.php new file mode 100644 index 0000000000..147281d141 --- /dev/null +++ b/vendor/diogocomposer/xmpphp/examples/webclient_example.php @@ -0,0 +1,117 @@ + 'talk.google.com', + 'port' => 5222, + 'username' => 'username', + 'password' => 'password', + 'proto' => 'xmpphp', + 'domain' => 'gmail.com', + 'printlog' => true, + 'loglevel' => XMPPHP\Log::LEVEL_VERBOSE, +); + +// Easy and simple for access to variables with their names +extract($conf); + +$conn = new XMPPHP\XMPP($server, $port, $username, $password, $proto, $domain, $printlog, $loglevel); +$conn->autoSubscribe(); + +try { + if (isset($_SESSION['messages'])) { + foreach ($_SESSION['messages'] as $message) { + echo $message; + flush(); + } + } else { + $_SESSION['messages'] = array(); + } + + $conn->connect('http://server.tld:5280/xmpp-httpbind', 1, true); + $events = array('message', 'presence', 'end_stream', 'session_start', 'vcard'); + $payloads = $conn->processUntil($events); + + foreach ($payloads as $result) { + list($event, $data) = $result; + + if (isset($data)) { + extract($data); + } + + switch ($event) { + + case 'message': + + if (!$body) { + break; + } + + $cmd = explode(' ', $body); + $msg = str_repeat('-', 80); + $msg .= "\nMessage from: $from\n"; + + if (isset($subject)) { + $msg .= "Subject: $subject\n"; + } + + $msg .= $body . "\n"; + $msg .= str_repeat('-', 80); + echo "
$msg
"; + + if (isset($cmd[0])) { + if ($cmd[0] == 'quit') { + $conn->disconnect(); + } + + if ($cmd[0] == 'break') { + $conn->send(''); + } + } + $_SESSION['messages'][] = $msg; + flush(); + break; + + case 'presence': + + echo "Presence: $from [$show] $status\n"; + break; + + case 'session_start': + + echo "Session start\n"; + $conn->getRoster(); + $conn->presence('Quasar!'); + break; + } + } +} catch (XMPPHP\Exception $e) { + die($e->getMessage()); +} + +$conn->saveSession(); + +echo ''; diff --git a/vendor/diogocomposer/xmpphp/tests/AllTests.php b/vendor/diogocomposer/xmpphp/tests/AllTests.php new file mode 100755 index 0000000000..c8ad98c536 --- /dev/null +++ b/vendor/diogocomposer/xmpphp/tests/AllTests.php @@ -0,0 +1,79 @@ + + * @author Stephan Wentz + * @author Michael Garvin + * @copyright 2008 Nathanael C. Fritz + */ + +// Get current working directory with trailing slash +define('TESTS_DIR', dirname(__FILE__) . DIRECTORY_SEPARATOR); + +// Get class directory with trailing slash +define('CLASS_DIR', dirname(TESTS_DIR) . DIRECTORY_SEPARATOR); + +/** XMPPHP_LogTest */ +require_once TESTS_DIR . 'XMPPHP' . DIRECTORY_SEPARATOR . 'LogTest.php'; + +/** XMPPHP_XMLObjTest */ +require_once TESTS_DIR . 'XMPPHP' . DIRECTORY_SEPARATOR . 'XMLObjTest.php'; + +/** XMPPHP_XMPPTest */ +require_once TESTS_DIR . 'XMPPHP' . DIRECTORY_SEPARATOR . 'XMPPTest.php'; + +if (!defined('PHPUnit_MAIN_METHOD')) { + define('PHPUnit_MAIN_METHOD', 'AllTests::main'); +} + +/** + * XMPPHP AllTests + * + * @package XMPPHP + * @author Nathanael C. Fritz + * @author Stephan Wentz + * @author Michael Garvin + * @copyright 2008 Nathanael C. Fritz + * @version $Id$ + */ +class AllTests +{ + public static function main() + { + PHPUnit_TextUI_TestRunner::run(self::suite()); + } + + public static function suite() + { + $suite = new PHPUnit_Framework_TestSuite(); + $suite->addTestSuite('XMPPHP_LogTest'); + $suite->addTestSuite('XMPPHP_XMLObjTest'); + $suite->addTestSuite('XMPPHP_XMPPTest'); + + return $suite; + } +} + +if (PHPUnit_MAIN_METHOD == 'AllTests::main') { + AllTests::main(); +} diff --git a/vendor/diogocomposer/xmpphp/tests/XMPPHP/LogTest.php b/vendor/diogocomposer/xmpphp/tests/XMPPHP/LogTest.php new file mode 100755 index 0000000000..240da1b028 --- /dev/null +++ b/vendor/diogocomposer/xmpphp/tests/XMPPHP/LogTest.php @@ -0,0 +1,188 @@ + + * @author Stephan Wentz + * @author Michael Garvin + * @copyright 2008 Nathanael C. Fritz + */ + +/** XMPPHP_Log */ +require_once CLASS_DIR . 'XMPPHP' . DIRECTORY_SEPARATOR . 'Log.php'; + +/** + * XMPPHP LogTest + * + * @package XMPPHP + * @author Nathanael C. Fritz + * @author Stephan Wentz + * @author Michael Garvin + * @copyright 2008 Nathanael C. Fritz + * @version $Id$ + */ +class XMPPHP_LogTest extends PHPUnit_Framework_TestCase +{ + public function testPrintoutNoOutput() + { + $log = new XMPPHP_Log(); + $msg = 'I am a test log message'; + + ob_start(); + $log->log('test'); + $result = ob_get_clean(); + + $this->assertEquals('', $result); + } + + public function testPrintoutOutput() + { + $log = new XMPPHP_Log(true); + $msg = 'I am a test log message'; + + ob_start(); + $log->log($msg); + $result = ob_get_clean(); + + $this->assertContains($msg, $result); + } + + public function testPrintoutNoOutputWithDefaultLevel() + { + $log = new XMPPHP_Log(true, XMPPHP_Log::LEVEL_ERROR); + $msg = 'I am a test log message'; + + ob_start(); + $log->log($msg); + $result = ob_get_clean(); + + $this->assertSame('', $result); + } + + public function testPrintoutOutputWithDefaultLevel() + { + $log = new XMPPHP_Log(true, XMPPHP_Log::LEVEL_INFO); + $msg = 'I am a test log message'; + + ob_start(); + $log->log($msg); + $result = ob_get_clean(); + + $this->assertContains($msg, $result); + } + + public function testPrintoutNoOutputWithCustomLevel() + { + $log = new XMPPHP_Log(true, XMPPHP_Log::LEVEL_INFO); + $msg = 'I am a test log message'; + + ob_start(); + $log->log($msg, XMPPHP_Log::LEVEL_DEBUG); + $result = ob_get_clean(); + + $this->assertSame('', $result); + } + + public function testPrintoutOutputWithCustomLevel() + { + $log = new XMPPHP_Log(true, XMPPHP_Log::LEVEL_INFO); + $msg = 'I am a test log message'; + + ob_start(); + $log->log($msg, XMPPHP_Log::LEVEL_INFO); + $result = ob_get_clean(); + + $this->assertContains($msg, $result); + } + + public function testExplicitPrintout() + { + $log = new XMPPHP_Log(false); + $msg = 'I am a test log message'; + + ob_start(); + $log->log($msg); + $result = ob_get_clean(); + + $this->assertSame('', $result); + } + + public function testExplicitPrintoutResult() + { + $log = new XMPPHP_Log(false); + $msg = 'I am a test log message'; + + ob_start(); + $log->log($msg); + $result = ob_get_clean(); + + $this->assertSame('', $result); + + ob_start(); + $log->printout(); + $result = ob_get_clean(); + + $this->assertContains($msg, $result); + } + + public function testExplicitPrintoutClear() + { + $log = new XMPPHP_Log(false); + $msg = 'I am a test log message'; + + ob_start(); + $log->log($msg); + $result = ob_get_clean(); + + $this->assertSame('', $result); + + ob_start(); + $log->printout(); + $result = ob_get_clean(); + + $this->assertContains($msg, $result); + + ob_start(); + $log->printout(); + $result = ob_get_clean(); + + $this->assertSame('', $result); + } + + public function testExplicitPrintoutLevel() + { + $log = new XMPPHP_Log(false, XMPPHP_Log::LEVEL_ERROR); + $msg = 'I am a test log message'; + + ob_start(); + $log->log($msg); + $result = ob_get_clean(); + + $this->assertSame('', $result); + + ob_start(); + $log->printout(true, XMPPHP_Log::LEVEL_INFO); + $result = ob_get_clean(); + + $this->assertSame('', $result); + } +} diff --git a/vendor/diogocomposer/xmpphp/tests/XMPPHP/XMLObjTest.php b/vendor/diogocomposer/xmpphp/tests/XMPPHP/XMLObjTest.php new file mode 100755 index 0000000000..f4f2e09da7 --- /dev/null +++ b/vendor/diogocomposer/xmpphp/tests/XMPPHP/XMLObjTest.php @@ -0,0 +1,78 @@ + + * @author Stephan Wentz + * @author Michael Garvin + * @copyright 2008 Nathanael C. Fritz + */ + +/** XMPPHP_XMLObj */ +require_once CLASS_DIR . 'XMPPHP' . DIRECTORY_SEPARATOR . 'XMLObj.php'; + +/** + * XMPPHP XMLObjectTest + * + * @package XMPPHP + * @author Nathanael C. Fritz + * @author Stephan Wentz + * @author Michael Garvin + * @copyright 2008 Nathanael C. Fritz + * @version $Id$ + */ +class XMPPHP_XMLObjTest extends PHPUnit_Framework_TestCase +{ + public function testToStringNameNamespace() + { + $xmlobj = new XMPPHP_XMLObj('testname', 'testNameSpace'); + $expected = ''; + $result = $xmlobj->toString(); + $this->assertSame($expected, $result); + } + + public function testToStringNameNamespaceAttr() + { + $xmlobj = new XMPPHP_XMLObj('testName', 'testNameSpace', array('attr1' => 'valA', 'attr2' => 'valB')); + $expected = ''; + $result = $xmlobj->toString(); + $this->assertSame($expected, $result); + } + + public function testToStringNameNamespaceData() + { + $xmlobj = new XMPPHP_XMLObj('testName', 'testNameSpace', array(), 'I am test data'); + $expected = 'I am test data'; + $result = $xmlobj->toString(); + $this->assertSame($expected, $result); + } + + public function testToStringNameNamespaceSub() + { + $xmlobj = new XMPPHP_XMLObj('testName', 'testNameSpace'); + $sub1 = new XMPPHP_XMLObj('subName', 'subNameSpace'); + $xmlobj->subs = array($sub1); + $expected = ''; + $result = $xmlobj->toString(); + $this->assertSame($expected, $result); + } +} diff --git a/vendor/diogocomposer/xmpphp/tests/XMPPHP/XMPPTest.php b/vendor/diogocomposer/xmpphp/tests/XMPPHP/XMPPTest.php new file mode 100755 index 0000000000..b77a1b926a --- /dev/null +++ b/vendor/diogocomposer/xmpphp/tests/XMPPHP/XMPPTest.php @@ -0,0 +1,82 @@ + + * @author Stephan Wentz + * @author Michael Garvin + * @copyright 2008 Nathanael C. Fritz + */ + +/** XMPPHP_XMPP */ +require_once CLASS_DIR . 'XMPPHP' . DIRECTORY_SEPARATOR . 'XMPP.php'; + +/** + * XMPPHP XMPPTest + * + * @package XMPPHP + * @author Nathanael C. Fritz + * @author Stephan Wentz + * @author Michael Garvin + * @copyright 2008 Nathanael C. Fritz + * @version $Id$ + */ +class XMPPHP_XMPPTest extends PHPUnit_Framework_TestCase +{ + public function testConnectException() + { + try { + $xmpp = new XMPPHP_XMPP('talk.google.com', 1234, 'invalidusername', 'invalidpassword', 'xmpphp', 'talk.google.com', false, XMPPHP_Log::LEVEL_VERBOSE); + $xmpp->useEncryption(false); + $xmpp->connect(10); + $xmpp->processUntil('session_start'); + $xmpp->presence(); + $xmpp->message('stephan@jabber.wentz.it', 'This is a test message!'); + $xmpp->disconnect(); + } catch (XMPPHP_Exception $e) { + return; + } catch (Exception $e) { + $this->fail('Unexpected Exception thrown: '.$e->getMessage()); + } + + $this->fail('Expected XMPPHP_Exception not thrown!'); + } + + public function testAuthException() + { + try { + $xmpp = new XMPPHP_XMPP('jabber.wentz.it', 5222, 'invalidusername', 'invalidpassword', 'xmpphp', 'jabber.wentz.it', true, XMPPHP_Log::LEVEL_VERBOSE); + $xmpp->useEncryption(false); + $xmpp->connect(10); + $xmpp->processUntil('session_start'); + $xmpp->presence(); + $xmpp->message('stephan@jabber.wentz.it', 'This is a test message!'); + $xmpp->disconnect(); + } catch (XMPPHP_Exception $e) { + return; + } catch (Exception $e) { + $this->fail('Unexpected Exception thrown: '.$e->getMessage()); + } + + $this->fail('Expected XMPPHP_Exception not thrown!'); + } +} diff --git a/vendor/doctrine/inflector/LICENSE b/vendor/doctrine/inflector/LICENSE deleted file mode 100644 index 8c38cc1bc2..0000000000 --- a/vendor/doctrine/inflector/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2006-2015 Doctrine Project - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/doctrine/inflector/README.md b/vendor/doctrine/inflector/README.md deleted file mode 100644 index acb55a014b..0000000000 --- a/vendor/doctrine/inflector/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# Doctrine Inflector - -Doctrine Inflector is a small library that can perform string manipulations -with regard to upper-/lowercase and singular/plural forms of words. - -[![Build Status](https://travis-ci.org/doctrine/inflector.svg?branch=master)](https://travis-ci.org/doctrine/inflector) diff --git a/vendor/doctrine/inflector/composer.json b/vendor/doctrine/inflector/composer.json deleted file mode 100644 index 2189ff17fd..0000000000 --- a/vendor/doctrine/inflector/composer.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "name": "doctrine/inflector", - "type": "library", - "description": "Common String Manipulations with regard to casing and singular/plural rules.", - "keywords": ["string", "inflection", "singularize", "pluralize"], - "homepage": "http://www.doctrine-project.org", - "license": "MIT", - "authors": [ - {"name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com"}, - {"name": "Roman Borschel", "email": "roman@code-factory.org"}, - {"name": "Benjamin Eberlei", "email": "kontakt@beberlei.de"}, - {"name": "Jonathan Wage", "email": "jonwage@gmail.com"}, - {"name": "Johannes Schmitt", "email": "schmittjoh@gmail.com"} - ], - "require": { - "php": "^7.1" - }, - "require-dev": { - "phpunit/phpunit": "^6.2" - }, - "autoload": { - "psr-4": { "Doctrine\\Common\\Inflector\\": "lib/Doctrine/Common/Inflector" } - }, - "autoload-dev": { - "psr-4": { "Doctrine\\Tests\\Common\\Inflector\\": "tests/Doctrine/Tests/Common/Inflector" } - }, - "extra": { - "branch-alias": { - "dev-master": "1.3.x-dev" - } - } -} diff --git a/vendor/doctrine/inflector/lib/Doctrine/Common/Inflector/Inflector.php b/vendor/doctrine/inflector/lib/Doctrine/Common/Inflector/Inflector.php deleted file mode 100644 index f9067a0218..0000000000 --- a/vendor/doctrine/inflector/lib/Doctrine/Common/Inflector/Inflector.php +++ /dev/null @@ -1,490 +0,0 @@ -. - */ - -namespace Doctrine\Common\Inflector; - -/** - * Doctrine inflector has static methods for inflecting text. - * - * The methods in these classes are from several different sources collected - * across several different php projects and several different authors. The - * original author names and emails are not known. - * - * Pluralize & Singularize implementation are borrowed from CakePHP with some modifications. - * - * @link www.doctrine-project.org - * @since 1.0 - * @author Konsta Vesterinen - * @author Jonathan H. Wage - */ -class Inflector -{ - /** - * Plural inflector rules. - * - * @var string[][] - */ - private static $plural = array( - 'rules' => array( - '/(s)tatus$/i' => '\1\2tatuses', - '/(quiz)$/i' => '\1zes', - '/^(ox)$/i' => '\1\2en', - '/([m|l])ouse$/i' => '\1ice', - '/(matr|vert|ind)(ix|ex)$/i' => '\1ices', - '/(x|ch|ss|sh)$/i' => '\1es', - '/([^aeiouy]|qu)y$/i' => '\1ies', - '/(hive|gulf)$/i' => '\1s', - '/(?:([^f])fe|([lr])f)$/i' => '\1\2ves', - '/sis$/i' => 'ses', - '/([ti])um$/i' => '\1a', - '/(c)riterion$/i' => '\1riteria', - '/(p)erson$/i' => '\1eople', - '/(m)an$/i' => '\1en', - '/(c)hild$/i' => '\1hildren', - '/(f)oot$/i' => '\1eet', - '/(buffal|her|potat|tomat|volcan)o$/i' => '\1\2oes', - '/(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|vir)us$/i' => '\1i', - '/us$/i' => 'uses', - '/(alias)$/i' => '\1es', - '/(analys|ax|cris|test|thes)is$/i' => '\1es', - '/s$/' => 's', - '/^$/' => '', - '/$/' => 's', - ), - 'uninflected' => array( - '.*[nrlm]ese', - '.*deer', - '.*fish', - '.*measles', - '.*ois', - '.*pox', - '.*sheep', - 'people', - 'cookie', - 'police', - ), - 'irregular' => array( - 'atlas' => 'atlases', - 'axe' => 'axes', - 'beef' => 'beefs', - 'brother' => 'brothers', - 'cafe' => 'cafes', - 'chateau' => 'chateaux', - 'niveau' => 'niveaux', - 'child' => 'children', - 'cookie' => 'cookies', - 'corpus' => 'corpuses', - 'cow' => 'cows', - 'criterion' => 'criteria', - 'curriculum' => 'curricula', - 'demo' => 'demos', - 'domino' => 'dominoes', - 'echo' => 'echoes', - 'foot' => 'feet', - 'fungus' => 'fungi', - 'ganglion' => 'ganglions', - 'genie' => 'genies', - 'genus' => 'genera', - 'goose' => 'geese', - 'graffito' => 'graffiti', - 'hippopotamus' => 'hippopotami', - 'hoof' => 'hoofs', - 'human' => 'humans', - 'iris' => 'irises', - 'larva' => 'larvae', - 'leaf' => 'leaves', - 'loaf' => 'loaves', - 'man' => 'men', - 'medium' => 'media', - 'memorandum' => 'memoranda', - 'money' => 'monies', - 'mongoose' => 'mongooses', - 'motto' => 'mottoes', - 'move' => 'moves', - 'mythos' => 'mythoi', - 'niche' => 'niches', - 'nucleus' => 'nuclei', - 'numen' => 'numina', - 'occiput' => 'occiputs', - 'octopus' => 'octopuses', - 'opus' => 'opuses', - 'ox' => 'oxen', - 'passerby' => 'passersby', - 'penis' => 'penises', - 'person' => 'people', - 'plateau' => 'plateaux', - 'runner-up' => 'runners-up', - 'sex' => 'sexes', - 'soliloquy' => 'soliloquies', - 'son-in-law' => 'sons-in-law', - 'syllabus' => 'syllabi', - 'testis' => 'testes', - 'thief' => 'thieves', - 'tooth' => 'teeth', - 'tornado' => 'tornadoes', - 'trilby' => 'trilbys', - 'turf' => 'turfs', - 'valve' => 'valves', - 'volcano' => 'volcanoes', - ) - ); - - /** - * Singular inflector rules. - * - * @var string[][] - */ - private static $singular = array( - 'rules' => array( - '/(s)tatuses$/i' => '\1\2tatus', - '/^(.*)(menu)s$/i' => '\1\2', - '/(quiz)zes$/i' => '\\1', - '/(matr)ices$/i' => '\1ix', - '/(vert|ind)ices$/i' => '\1ex', - '/^(ox)en/i' => '\1', - '/(alias)(es)*$/i' => '\1', - '/(buffal|her|potat|tomat|volcan)oes$/i' => '\1o', - '/(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|viri?)i$/i' => '\1us', - '/([ftw]ax)es/i' => '\1', - '/(analys|ax|cris|test|thes)es$/i' => '\1is', - '/(shoe|slave)s$/i' => '\1', - '/(o)es$/i' => '\1', - '/ouses$/' => 'ouse', - '/([^a])uses$/' => '\1us', - '/([m|l])ice$/i' => '\1ouse', - '/(x|ch|ss|sh)es$/i' => '\1', - '/(m)ovies$/i' => '\1\2ovie', - '/(s)eries$/i' => '\1\2eries', - '/([^aeiouy]|qu)ies$/i' => '\1y', - '/([lr])ves$/i' => '\1f', - '/(tive)s$/i' => '\1', - '/(hive)s$/i' => '\1', - '/(drive)s$/i' => '\1', - '/(dive)s$/i' => '\1', - '/(olive)s$/i' => '\1', - '/([^fo])ves$/i' => '\1fe', - '/(^analy)ses$/i' => '\1sis', - '/(analy|diagno|^ba|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i' => '\1\2sis', - '/(c)riteria$/i' => '\1riterion', - '/([ti])a$/i' => '\1um', - '/(p)eople$/i' => '\1\2erson', - '/(m)en$/i' => '\1an', - '/(c)hildren$/i' => '\1\2hild', - '/(f)eet$/i' => '\1oot', - '/(n)ews$/i' => '\1\2ews', - '/eaus$/' => 'eau', - '/^(.*us)$/' => '\\1', - '/s$/i' => '', - ), - 'uninflected' => array( - '.*[nrlm]ese', - '.*deer', - '.*fish', - '.*measles', - '.*ois', - '.*pox', - '.*sheep', - '.*ss', - 'data', - 'police', - 'pants', - 'clothes', - ), - 'irregular' => array( - 'abuses' => 'abuse', - 'avalanches' => 'avalanche', - 'caches' => 'cache', - 'criteria' => 'criterion', - 'curves' => 'curve', - 'emphases' => 'emphasis', - 'foes' => 'foe', - 'geese' => 'goose', - 'graves' => 'grave', - 'hoaxes' => 'hoax', - 'media' => 'medium', - 'neuroses' => 'neurosis', - 'waves' => 'wave', - 'oases' => 'oasis', - 'valves' => 'valve', - ) - ); - - /** - * Words that should not be inflected. - * - * @var array - */ - private static $uninflected = array( - '.*?media', 'Amoyese', 'audio', 'bison', 'Borghese', 'bream', 'breeches', - 'britches', 'buffalo', 'cantus', 'carp', 'chassis', 'clippers', 'cod', 'coitus', 'compensation', 'Congoese', - 'contretemps', 'coreopsis', 'corps', 'data', 'debris', 'deer', 'diabetes', 'djinn', 'education', 'eland', - 'elk', 'emoji', 'equipment', 'evidence', 'Faroese', 'feedback', 'fish', 'flounder', 'Foochowese', - 'Furniture', 'furniture', 'gallows', 'Genevese', 'Genoese', 'Gilbertese', 'gold', - 'headquarters', 'herpes', 'hijinks', 'Hottentotese', 'information', 'innings', 'jackanapes', 'jedi', - 'Kiplingese', 'knowledge', 'Kongoese', 'love', 'Lucchese', 'Luggage', 'mackerel', 'Maltese', 'metadata', - 'mews', 'moose', 'mumps', 'Nankingese', 'news', 'nexus', 'Niasese', 'nutrition', 'offspring', - 'Pekingese', 'Piedmontese', 'pincers', 'Pistoiese', 'plankton', 'pliers', 'pokemon', 'police', 'Portuguese', - 'proceedings', 'rabies', 'rain', 'rhinoceros', 'rice', 'salmon', 'Sarawakese', 'scissors', 'sea[- ]bass', - 'series', 'Shavese', 'shears', 'sheep', 'siemens', 'species', 'staff', 'swine', 'traffic', - 'trousers', 'trout', 'tuna', 'us', 'Vermontese', 'Wenchowese', 'wheat', 'whiting', 'wildebeest', 'Yengeese' - ); - - /** - * Method cache array. - * - * @var array - */ - private static $cache = array(); - - /** - * The initial state of Inflector so reset() works. - * - * @var array - */ - private static $initialState = array(); - - /** - * Converts a word into the format for a Doctrine table name. Converts 'ModelName' to 'model_name'. - */ - public static function tableize(string $word) : string - { - return strtolower(preg_replace('~(?<=\\w)([A-Z])~', '_$1', $word)); - } - - /** - * Converts a word into the format for a Doctrine class name. Converts 'table_name' to 'TableName'. - */ - public static function classify(string $word) : string - { - return str_replace([' ', '_', '-'], '', ucwords($word, ' _-')); - } - - /** - * Camelizes a word. This uses the classify() method and turns the first character to lowercase. - */ - public static function camelize(string $word) : string - { - return lcfirst(self::classify($word)); - } - - /** - * Uppercases words with configurable delimeters between words. - * - * Takes a string and capitalizes all of the words, like PHP's built-in - * ucwords function. This extends that behavior, however, by allowing the - * word delimeters to be configured, rather than only separating on - * whitespace. - * - * Here is an example: - * - * - * - * - * @param string $string The string to operate on. - * @param string $delimiters A list of word separators. - * - * @return string The string with all delimeter-separated words capitalized. - */ - public static function ucwords(string $string, string $delimiters = " \n\t\r\0\x0B-") : string - { - return ucwords($string, $delimiters); - } - - /** - * Clears Inflectors inflected value caches, and resets the inflection - * rules to the initial values. - */ - public static function reset() : void - { - if (empty(self::$initialState)) { - self::$initialState = get_class_vars('Inflector'); - - return; - } - - foreach (self::$initialState as $key => $val) { - if ($key !== 'initialState') { - self::${$key} = $val; - } - } - } - - /** - * Adds custom inflection $rules, of either 'plural' or 'singular' $type. - * - * ### Usage: - * - * {{{ - * Inflector::rules('plural', array('/^(inflect)or$/i' => '\1ables')); - * Inflector::rules('plural', array( - * 'rules' => array('/^(inflect)ors$/i' => '\1ables'), - * 'uninflected' => array('dontinflectme'), - * 'irregular' => array('red' => 'redlings') - * )); - * }}} - * - * @param string $type The type of inflection, either 'plural' or 'singular' - * @param array|iterable $rules An array of rules to be added. - * @param boolean $reset If true, will unset default inflections for all - * new rules that are being defined in $rules. - * - * @return void - */ - public static function rules(string $type, iterable $rules, bool $reset = false) : void - { - foreach ($rules as $rule => $pattern) { - if ( ! is_array($pattern)) { - continue; - } - - if ($reset) { - self::${$type}[$rule] = $pattern; - } else { - self::${$type}[$rule] = ($rule === 'uninflected') - ? array_merge($pattern, self::${$type}[$rule]) - : $pattern + self::${$type}[$rule]; - } - - unset($rules[$rule], self::${$type}['cache' . ucfirst($rule)]); - - if (isset(self::${$type}['merged'][$rule])) { - unset(self::${$type}['merged'][$rule]); - } - - if ($type === 'plural') { - self::$cache['pluralize'] = self::$cache['tableize'] = array(); - } elseif ($type === 'singular') { - self::$cache['singularize'] = array(); - } - } - - self::${$type}['rules'] = $rules + self::${$type}['rules']; - } - - /** - * Returns a word in plural form. - * - * @param string $word The word in singular form. - * - * @return string The word in plural form. - */ - public static function pluralize(string $word) : string - { - if (isset(self::$cache['pluralize'][$word])) { - return self::$cache['pluralize'][$word]; - } - - if (!isset(self::$plural['merged']['irregular'])) { - self::$plural['merged']['irregular'] = self::$plural['irregular']; - } - - if (!isset(self::$plural['merged']['uninflected'])) { - self::$plural['merged']['uninflected'] = array_merge(self::$plural['uninflected'], self::$uninflected); - } - - if (!isset(self::$plural['cacheUninflected']) || !isset(self::$plural['cacheIrregular'])) { - self::$plural['cacheUninflected'] = '(?:' . implode('|', self::$plural['merged']['uninflected']) . ')'; - self::$plural['cacheIrregular'] = '(?:' . implode('|', array_keys(self::$plural['merged']['irregular'])) . ')'; - } - - if (preg_match('/(.*)\\b(' . self::$plural['cacheIrregular'] . ')$/i', $word, $regs)) { - self::$cache['pluralize'][$word] = $regs[1] . $word[0] . substr(self::$plural['merged']['irregular'][strtolower($regs[2])], 1); - - return self::$cache['pluralize'][$word]; - } - - if (preg_match('/^(' . self::$plural['cacheUninflected'] . ')$/i', $word, $regs)) { - self::$cache['pluralize'][$word] = $word; - - return $word; - } - - foreach (self::$plural['rules'] as $rule => $replacement) { - if (preg_match($rule, $word)) { - self::$cache['pluralize'][$word] = preg_replace($rule, $replacement, $word); - - return self::$cache['pluralize'][$word]; - } - } - } - - /** - * Returns a word in singular form. - * - * @param string $word The word in plural form. - * - * @return string The word in singular form. - */ - public static function singularize(string $word) : string - { - if (isset(self::$cache['singularize'][$word])) { - return self::$cache['singularize'][$word]; - } - - if (!isset(self::$singular['merged']['uninflected'])) { - self::$singular['merged']['uninflected'] = array_merge( - self::$singular['uninflected'], - self::$uninflected - ); - } - - if (!isset(self::$singular['merged']['irregular'])) { - self::$singular['merged']['irregular'] = array_merge( - self::$singular['irregular'], - array_flip(self::$plural['irregular']) - ); - } - - if (!isset(self::$singular['cacheUninflected']) || !isset(self::$singular['cacheIrregular'])) { - self::$singular['cacheUninflected'] = '(?:' . implode('|', self::$singular['merged']['uninflected']) . ')'; - self::$singular['cacheIrregular'] = '(?:' . implode('|', array_keys(self::$singular['merged']['irregular'])) . ')'; - } - - if (preg_match('/(.*)\\b(' . self::$singular['cacheIrregular'] . ')$/i', $word, $regs)) { - self::$cache['singularize'][$word] = $regs[1] . $word[0] . substr(self::$singular['merged']['irregular'][strtolower($regs[2])], 1); - - return self::$cache['singularize'][$word]; - } - - if (preg_match('/^(' . self::$singular['cacheUninflected'] . ')$/i', $word, $regs)) { - self::$cache['singularize'][$word] = $word; - - return $word; - } - - foreach (self::$singular['rules'] as $rule => $replacement) { - if (preg_match($rule, $word)) { - self::$cache['singularize'][$word] = preg_replace($rule, $replacement, $word); - - return self::$cache['singularize'][$word]; - } - } - - self::$cache['singularize'][$word] = $word; - - return $word; - } -} diff --git a/vendor/illuminate/contracts/Auth/Access/Authorizable.php b/vendor/illuminate/contracts/Auth/Access/Authorizable.php deleted file mode 100644 index 2f9657c574..0000000000 --- a/vendor/illuminate/contracts/Auth/Access/Authorizable.php +++ /dev/null @@ -1,15 +0,0 @@ -id = $id; - $this->class = $class; - $this->relations = $relations; - $this->connection = $connection; - } -} diff --git a/vendor/illuminate/contracts/Debug/ExceptionHandler.php b/vendor/illuminate/contracts/Debug/ExceptionHandler.php deleted file mode 100644 index 975ed6c2e1..0000000000 --- a/vendor/illuminate/contracts/Debug/ExceptionHandler.php +++ /dev/null @@ -1,42 +0,0 @@ -instances = []; - - foreach ($this->providers as $provider) { - $this->instances[] = $this->app->register($provider); - } - } - - /** - * Get the services provided by the provider. - * - * @return array - */ - public function provides() - { - $provides = []; - - foreach ($this->providers as $provider) { - $instance = $this->app->resolveProvider($provider); - - $provides = array_merge($provides, $instance->provides()); - } - - return $provides; - } -} diff --git a/vendor/illuminate/support/Arr.php b/vendor/illuminate/support/Arr.php deleted file mode 100755 index b21a3bbd0b..0000000000 --- a/vendor/illuminate/support/Arr.php +++ /dev/null @@ -1,628 +0,0 @@ -all(); - } elseif (! is_array($values)) { - continue; - } - - $results[] = $values; - } - - return array_merge([], ...$results); - } - - /** - * Cross join the given arrays, returning all possible permutations. - * - * @param array ...$arrays - * @return array - */ - public static function crossJoin(...$arrays) - { - $results = [[]]; - - foreach ($arrays as $index => $array) { - $append = []; - - foreach ($results as $product) { - foreach ($array as $item) { - $product[$index] = $item; - - $append[] = $product; - } - } - - $results = $append; - } - - return $results; - } - - /** - * Divide an array into two arrays. One with keys and the other with values. - * - * @param array $array - * @return array - */ - public static function divide($array) - { - return [array_keys($array), array_values($array)]; - } - - /** - * Flatten a multi-dimensional associative array with dots. - * - * @param array $array - * @param string $prepend - * @return array - */ - public static function dot($array, $prepend = '') - { - $results = []; - - foreach ($array as $key => $value) { - if (is_array($value) && ! empty($value)) { - $results = array_merge($results, static::dot($value, $prepend.$key.'.')); - } else { - $results[$prepend.$key] = $value; - } - } - - return $results; - } - - /** - * Get all of the given array except for a specified array of keys. - * - * @param array $array - * @param array|string $keys - * @return array - */ - public static function except($array, $keys) - { - static::forget($array, $keys); - - return $array; - } - - /** - * Determine if the given key exists in the provided array. - * - * @param \ArrayAccess|array $array - * @param string|int $key - * @return bool - */ - public static function exists($array, $key) - { - if ($array instanceof ArrayAccess) { - return $array->offsetExists($key); - } - - return array_key_exists($key, $array); - } - - /** - * Return the first element in an array passing a given truth test. - * - * @param array $array - * @param callable|null $callback - * @param mixed $default - * @return mixed - */ - public static function first($array, callable $callback = null, $default = null) - { - if (is_null($callback)) { - if (empty($array)) { - return value($default); - } - - foreach ($array as $item) { - return $item; - } - } - - foreach ($array as $key => $value) { - if (call_user_func($callback, $value, $key)) { - return $value; - } - } - - return value($default); - } - - /** - * Return the last element in an array passing a given truth test. - * - * @param array $array - * @param callable|null $callback - * @param mixed $default - * @return mixed - */ - public static function last($array, callable $callback = null, $default = null) - { - if (is_null($callback)) { - return empty($array) ? value($default) : end($array); - } - - return static::first(array_reverse($array, true), $callback, $default); - } - - /** - * Flatten a multi-dimensional array into a single level. - * - * @param array $array - * @param int $depth - * @return array - */ - public static function flatten($array, $depth = INF) - { - $result = []; - - foreach ($array as $item) { - $item = $item instanceof Collection ? $item->all() : $item; - - if (! is_array($item)) { - $result[] = $item; - } else { - $values = $depth === 1 - ? array_values($item) - : static::flatten($item, $depth - 1); - - foreach ($values as $value) { - $result[] = $value; - } - } - } - - return $result; - } - - /** - * Remove one or many array items from a given array using "dot" notation. - * - * @param array $array - * @param array|string $keys - * @return void - */ - public static function forget(&$array, $keys) - { - $original = &$array; - - $keys = (array) $keys; - - if (count($keys) === 0) { - return; - } - - foreach ($keys as $key) { - // if the exact key exists in the top-level, remove it - if (static::exists($array, $key)) { - unset($array[$key]); - - continue; - } - - $parts = explode('.', $key); - - // clean up before each pass - $array = &$original; - - while (count($parts) > 1) { - $part = array_shift($parts); - - if (isset($array[$part]) && is_array($array[$part])) { - $array = &$array[$part]; - } else { - continue 2; - } - } - - unset($array[array_shift($parts)]); - } - } - - /** - * Get an item from an array using "dot" notation. - * - * @param \ArrayAccess|array $array - * @param string|int $key - * @param mixed $default - * @return mixed - */ - public static function get($array, $key, $default = null) - { - if (! static::accessible($array)) { - return value($default); - } - - if (is_null($key)) { - return $array; - } - - if (static::exists($array, $key)) { - return $array[$key]; - } - - if (strpos($key, '.') === false) { - return $array[$key] ?? value($default); - } - - foreach (explode('.', $key) as $segment) { - if (static::accessible($array) && static::exists($array, $segment)) { - $array = $array[$segment]; - } else { - return value($default); - } - } - - return $array; - } - - /** - * Check if an item or items exist in an array using "dot" notation. - * - * @param \ArrayAccess|array $array - * @param string|array $keys - * @return bool - */ - public static function has($array, $keys) - { - $keys = (array) $keys; - - if (! $array || $keys === []) { - return false; - } - - foreach ($keys as $key) { - $subKeyArray = $array; - - if (static::exists($array, $key)) { - continue; - } - - foreach (explode('.', $key) as $segment) { - if (static::accessible($subKeyArray) && static::exists($subKeyArray, $segment)) { - $subKeyArray = $subKeyArray[$segment]; - } else { - return false; - } - } - } - - return true; - } - - /** - * Determines if an array is associative. - * - * An array is "associative" if it doesn't have sequential numerical keys beginning with zero. - * - * @param array $array - * @return bool - */ - public static function isAssoc(array $array) - { - $keys = array_keys($array); - - return array_keys($keys) !== $keys; - } - - /** - * Get a subset of the items from the given array. - * - * @param array $array - * @param array|string $keys - * @return array - */ - public static function only($array, $keys) - { - return array_intersect_key($array, array_flip((array) $keys)); - } - - /** - * Pluck an array of values from an array. - * - * @param array $array - * @param string|array $value - * @param string|array|null $key - * @return array - */ - public static function pluck($array, $value, $key = null) - { - $results = []; - - [$value, $key] = static::explodePluckParameters($value, $key); - - foreach ($array as $item) { - $itemValue = data_get($item, $value); - - // If the key is "null", we will just append the value to the array and keep - // looping. Otherwise we will key the array using the value of the key we - // received from the developer. Then we'll return the final array form. - if (is_null($key)) { - $results[] = $itemValue; - } else { - $itemKey = data_get($item, $key); - - if (is_object($itemKey) && method_exists($itemKey, '__toString')) { - $itemKey = (string) $itemKey; - } - - $results[$itemKey] = $itemValue; - } - } - - return $results; - } - - /** - * Explode the "value" and "key" arguments passed to "pluck". - * - * @param string|array $value - * @param string|array|null $key - * @return array - */ - protected static function explodePluckParameters($value, $key) - { - $value = is_string($value) ? explode('.', $value) : $value; - - $key = is_null($key) || is_array($key) ? $key : explode('.', $key); - - return [$value, $key]; - } - - /** - * Push an item onto the beginning of an array. - * - * @param array $array - * @param mixed $value - * @param mixed $key - * @return array - */ - public static function prepend($array, $value, $key = null) - { - if (is_null($key)) { - array_unshift($array, $value); - } else { - $array = [$key => $value] + $array; - } - - return $array; - } - - /** - * Get a value from the array, and remove it. - * - * @param array $array - * @param string $key - * @param mixed $default - * @return mixed - */ - public static function pull(&$array, $key, $default = null) - { - $value = static::get($array, $key, $default); - - static::forget($array, $key); - - return $value; - } - - /** - * Get one or a specified number of random values from an array. - * - * @param array $array - * @param int|null $number - * @return mixed - * - * @throws \InvalidArgumentException - */ - public static function random($array, $number = null) - { - $requested = is_null($number) ? 1 : $number; - - $count = count($array); - - if ($requested > $count) { - throw new InvalidArgumentException( - "You requested {$requested} items, but there are only {$count} items available." - ); - } - - if (is_null($number)) { - return $array[array_rand($array)]; - } - - if ((int) $number === 0) { - return []; - } - - $keys = array_rand($array, $number); - - $results = []; - - foreach ((array) $keys as $key) { - $results[] = $array[$key]; - } - - return $results; - } - - /** - * Set an array item to a given value using "dot" notation. - * - * If no key is given to the method, the entire array will be replaced. - * - * @param array $array - * @param string $key - * @param mixed $value - * @return array - */ - public static function set(&$array, $key, $value) - { - if (is_null($key)) { - return $array = $value; - } - - $keys = explode('.', $key); - - while (count($keys) > 1) { - $key = array_shift($keys); - - // If the key doesn't exist at this depth, we will just create an empty array - // to hold the next value, allowing us to create the arrays to hold final - // values at the correct depth. Then we'll keep digging into the array. - if (! isset($array[$key]) || ! is_array($array[$key])) { - $array[$key] = []; - } - - $array = &$array[$key]; - } - - $array[array_shift($keys)] = $value; - - return $array; - } - - /** - * Shuffle the given array and return the result. - * - * @param array $array - * @param int|null $seed - * @return array - */ - public static function shuffle($array, $seed = null) - { - if (is_null($seed)) { - shuffle($array); - } else { - mt_srand($seed); - shuffle($array); - mt_srand(); - } - - return $array; - } - - /** - * Sort the array using the given callback or "dot" notation. - * - * @param array $array - * @param callable|string|null $callback - * @return array - */ - public static function sort($array, $callback = null) - { - return Collection::make($array)->sortBy($callback)->all(); - } - - /** - * Recursively sort an array by keys and values. - * - * @param array $array - * @return array - */ - public static function sortRecursive($array) - { - foreach ($array as &$value) { - if (is_array($value)) { - $value = static::sortRecursive($value); - } - } - - if (static::isAssoc($array)) { - ksort($array); - } else { - sort($array); - } - - return $array; - } - - /** - * Convert the array into a query string. - * - * @param array $array - * @return string - */ - public static function query($array) - { - return http_build_query($array, null, '&', PHP_QUERY_RFC3986); - } - - /** - * Filter the array using the given callback. - * - * @param array $array - * @param callable $callback - * @return array - */ - public static function where($array, callable $callback) - { - return array_filter($array, $callback, ARRAY_FILTER_USE_BOTH); - } - - /** - * If the given value is not an array and not null, wrap it in one. - * - * @param mixed $value - * @return array - */ - public static function wrap($value) - { - if (is_null($value)) { - return []; - } - - return is_array($value) ? $value : [$value]; - } -} diff --git a/vendor/illuminate/support/Carbon.php b/vendor/illuminate/support/Carbon.php deleted file mode 100644 index 9383c3fd89..0000000000 --- a/vendor/illuminate/support/Carbon.php +++ /dev/null @@ -1,10 +0,0 @@ -items = $this->getArrayableItems($items); - } - - /** - * Create a new collection instance if the value isn't one already. - * - * @param mixed $items - * @return static - */ - public static function make($items = []) - { - return new static($items); - } - - /** - * Wrap the given value in a collection if applicable. - * - * @param mixed $value - * @return static - */ - public static function wrap($value) - { - return $value instanceof self - ? new static($value) - : new static(Arr::wrap($value)); - } - - /** - * Get the underlying items from the given collection if applicable. - * - * @param array|static $value - * @return array - */ - public static function unwrap($value) - { - return $value instanceof self ? $value->all() : $value; - } - - /** - * Create a new collection by invoking the callback a given amount of times. - * - * @param int $number - * @param callable $callback - * @return static - */ - public static function times($number, callable $callback = null) - { - if ($number < 1) { - return new static; - } - - if (is_null($callback)) { - return new static(range(1, $number)); - } - - return (new static(range(1, $number)))->map($callback); - } - - /** - * Get all of the items in the collection. - * - * @return array - */ - public function all() - { - return $this->items; - } - - /** - * Get the average value of a given key. - * - * @param callable|string|null $callback - * @return mixed - */ - public function avg($callback = null) - { - $callback = $this->valueRetriever($callback); - - $items = $this->map(function ($value) use ($callback) { - return $callback($value); - })->filter(function ($value) { - return ! is_null($value); - }); - - if ($count = $items->count()) { - return $items->sum() / $count; - } - } - - /** - * Alias for the "avg" method. - * - * @param callable|string|null $callback - * @return mixed - */ - public function average($callback = null) - { - return $this->avg($callback); - } - - /** - * Get the median of a given key. - * - * @param string|array|null $key - * @return mixed - */ - public function median($key = null) - { - $values = (isset($key) ? $this->pluck($key) : $this) - ->filter(function ($item) { - return ! is_null($item); - })->sort()->values(); - - $count = $values->count(); - - if ($count === 0) { - return; - } - - $middle = (int) ($count / 2); - - if ($count % 2) { - return $values->get($middle); - } - - return (new static([ - $values->get($middle - 1), $values->get($middle), - ]))->average(); - } - - /** - * Get the mode of a given key. - * - * @param string|array|null $key - * @return array|null - */ - public function mode($key = null) - { - if ($this->count() === 0) { - return; - } - - $collection = isset($key) ? $this->pluck($key) : $this; - - $counts = new self; - - $collection->each(function ($value) use ($counts) { - $counts[$value] = isset($counts[$value]) ? $counts[$value] + 1 : 1; - }); - - $sorted = $counts->sort(); - - $highestValue = $sorted->last(); - - return $sorted->filter(function ($value) use ($highestValue) { - return $value == $highestValue; - })->sort()->keys()->all(); - } - - /** - * Collapse the collection of items into a single array. - * - * @return static - */ - public function collapse() - { - return new static(Arr::collapse($this->items)); - } - - /** - * Alias for the "contains" method. - * - * @param mixed $key - * @param mixed $operator - * @param mixed $value - * @return bool - */ - public function some($key, $operator = null, $value = null) - { - return $this->contains(...func_get_args()); - } - - /** - * Determine if an item exists in the collection. - * - * @param mixed $key - * @param mixed $operator - * @param mixed $value - * @return bool - */ - public function contains($key, $operator = null, $value = null) - { - if (func_num_args() === 1) { - if ($this->useAsCallable($key)) { - $placeholder = new stdClass; - - return $this->first($key, $placeholder) !== $placeholder; - } - - return in_array($key, $this->items); - } - - return $this->contains($this->operatorForWhere(...func_get_args())); - } - - /** - * Determine if an item exists in the collection using strict comparison. - * - * @param mixed $key - * @param mixed $value - * @return bool - */ - public function containsStrict($key, $value = null) - { - if (func_num_args() === 2) { - return $this->contains(function ($item) use ($key, $value) { - return data_get($item, $key) === $value; - }); - } - - if ($this->useAsCallable($key)) { - return ! is_null($this->first($key)); - } - - return in_array($key, $this->items, true); - } - - /** - * Cross join with the given lists, returning all possible permutations. - * - * @param mixed ...$lists - * @return static - */ - public function crossJoin(...$lists) - { - return new static(Arr::crossJoin( - $this->items, ...array_map([$this, 'getArrayableItems'], $lists) - )); - } - - /** - * Dump the collection and end the script. - * - * @param mixed ...$args - * @return void - */ - public function dd(...$args) - { - call_user_func_array([$this, 'dump'], $args); - - die(1); - } - - /** - * Dump the collection. - * - * @return $this - */ - public function dump() - { - (new static(func_get_args())) - ->push($this) - ->each(function ($item) { - VarDumper::dump($item); - }); - - return $this; - } - - /** - * Get the items in the collection that are not present in the given items. - * - * @param mixed $items - * @return static - */ - public function diff($items) - { - return new static(array_diff($this->items, $this->getArrayableItems($items))); - } - - /** - * Get the items in the collection that are not present in the given items. - * - * @param mixed $items - * @param callable $callback - * @return static - */ - public function diffUsing($items, callable $callback) - { - return new static(array_udiff($this->items, $this->getArrayableItems($items), $callback)); - } - - /** - * Get the items in the collection whose keys and values are not present in the given items. - * - * @param mixed $items - * @return static - */ - public function diffAssoc($items) - { - return new static(array_diff_assoc($this->items, $this->getArrayableItems($items))); - } - - /** - * Get the items in the collection whose keys and values are not present in the given items. - * - * @param mixed $items - * @param callable $callback - * @return static - */ - public function diffAssocUsing($items, callable $callback) - { - return new static(array_diff_uassoc($this->items, $this->getArrayableItems($items), $callback)); - } - - /** - * Get the items in the collection whose keys are not present in the given items. - * - * @param mixed $items - * @return static - */ - public function diffKeys($items) - { - return new static(array_diff_key($this->items, $this->getArrayableItems($items))); - } - - /** - * Get the items in the collection whose keys are not present in the given items. - * - * @param mixed $items - * @param callable $callback - * @return static - */ - public function diffKeysUsing($items, callable $callback) - { - return new static(array_diff_ukey($this->items, $this->getArrayableItems($items), $callback)); - } - - /** - * Retrieve duplicate items from the collection. - * - * @param callable|null $callback - * @param bool $strict - * @return static - */ - public function duplicates($callback = null, $strict = false) - { - $items = $this->map($this->valueRetriever($callback)); - - $uniqueItems = $items->unique(null, $strict); - - $compare = $this->duplicateComparator($strict); - - $duplicates = new static; - - foreach ($items as $key => $value) { - if ($uniqueItems->isNotEmpty() && $compare($value, $uniqueItems->first())) { - $uniqueItems->shift(); - } else { - $duplicates[$key] = $value; - } - } - - return $duplicates; - } - - /** - * Retrieve duplicate items from the collection using strict comparison. - * - * @param callable|null $callback - * @return static - */ - public function duplicatesStrict($callback = null) - { - return $this->duplicates($callback, true); - } - - /** - * Get the comparison function to detect duplicates. - * - * @param bool $strict - * @return \Closure - */ - protected function duplicateComparator($strict) - { - if ($strict) { - return function ($a, $b) { - return $a === $b; - }; - } - - return function ($a, $b) { - return $a == $b; - }; - } - - /** - * Execute a callback over each item. - * - * @param callable $callback - * @return $this - */ - public function each(callable $callback) - { - foreach ($this->items as $key => $item) { - if ($callback($item, $key) === false) { - break; - } - } - - return $this; - } - - /** - * Execute a callback over each nested chunk of items. - * - * @param callable $callback - * @return static - */ - public function eachSpread(callable $callback) - { - return $this->each(function ($chunk, $key) use ($callback) { - $chunk[] = $key; - - return $callback(...$chunk); - }); - } - - /** - * Determine if all items in the collection pass the given test. - * - * @param string|callable $key - * @param mixed $operator - * @param mixed $value - * @return bool - */ - public function every($key, $operator = null, $value = null) - { - if (func_num_args() === 1) { - $callback = $this->valueRetriever($key); - - foreach ($this->items as $k => $v) { - if (! $callback($v, $k)) { - return false; - } - } - - return true; - } - - return $this->every($this->operatorForWhere(...func_get_args())); - } - - /** - * Get all items except for those with the specified keys. - * - * @param \Illuminate\Support\Collection|mixed $keys - * @return static - */ - public function except($keys) - { - if ($keys instanceof self) { - $keys = $keys->all(); - } elseif (! is_array($keys)) { - $keys = func_get_args(); - } - - return new static(Arr::except($this->items, $keys)); - } - - /** - * Run a filter over each of the items. - * - * @param callable|null $callback - * @return static - */ - public function filter(callable $callback = null) - { - if ($callback) { - return new static(Arr::where($this->items, $callback)); - } - - return new static(array_filter($this->items)); - } - - /** - * Apply the callback if the value is truthy. - * - * @param bool $value - * @param callable $callback - * @param callable $default - * @return static|mixed - */ - public function when($value, callable $callback, callable $default = null) - { - if ($value) { - return $callback($this, $value); - } elseif ($default) { - return $default($this, $value); - } - - return $this; - } - - /** - * Apply the callback if the collection is empty. - * - * @param callable $callback - * @param callable $default - * @return static|mixed - */ - public function whenEmpty(callable $callback, callable $default = null) - { - return $this->when($this->isEmpty(), $callback, $default); - } - - /** - * Apply the callback if the collection is not empty. - * - * @param callable $callback - * @param callable $default - * @return static|mixed - */ - public function whenNotEmpty(callable $callback, callable $default = null) - { - return $this->when($this->isNotEmpty(), $callback, $default); - } - - /** - * Apply the callback if the value is falsy. - * - * @param bool $value - * @param callable $callback - * @param callable $default - * @return static|mixed - */ - public function unless($value, callable $callback, callable $default = null) - { - return $this->when(! $value, $callback, $default); - } - - /** - * Apply the callback unless the collection is empty. - * - * @param callable $callback - * @param callable $default - * @return static|mixed - */ - public function unlessEmpty(callable $callback, callable $default = null) - { - return $this->whenNotEmpty($callback, $default); - } - - /** - * Apply the callback unless the collection is not empty. - * - * @param callable $callback - * @param callable $default - * @return static|mixed - */ - public function unlessNotEmpty(callable $callback, callable $default = null) - { - return $this->whenEmpty($callback, $default); - } - - /** - * Filter items by the given key value pair. - * - * @param string $key - * @param mixed $operator - * @param mixed $value - * @return static - */ - public function where($key, $operator = null, $value = null) - { - return $this->filter($this->operatorForWhere(...func_get_args())); - } - - /** - * Get an operator checker callback. - * - * @param string $key - * @param string $operator - * @param mixed $value - * @return \Closure - */ - protected function operatorForWhere($key, $operator = null, $value = null) - { - if (func_num_args() === 1) { - $value = true; - - $operator = '='; - } - - if (func_num_args() === 2) { - $value = $operator; - - $operator = '='; - } - - return function ($item) use ($key, $operator, $value) { - $retrieved = data_get($item, $key); - - $strings = array_filter([$retrieved, $value], function ($value) { - return is_string($value) || (is_object($value) && method_exists($value, '__toString')); - }); - - if (count($strings) < 2 && count(array_filter([$retrieved, $value], 'is_object')) == 1) { - return in_array($operator, ['!=', '<>', '!==']); - } - - switch ($operator) { - default: - case '=': - case '==': return $retrieved == $value; - case '!=': - case '<>': return $retrieved != $value; - case '<': return $retrieved < $value; - case '>': return $retrieved > $value; - case '<=': return $retrieved <= $value; - case '>=': return $retrieved >= $value; - case '===': return $retrieved === $value; - case '!==': return $retrieved !== $value; - } - }; - } - - /** - * Filter items by the given key value pair using strict comparison. - * - * @param string $key - * @param mixed $value - * @return static - */ - public function whereStrict($key, $value) - { - return $this->where($key, '===', $value); - } - - /** - * Filter items by the given key value pair. - * - * @param string $key - * @param mixed $values - * @param bool $strict - * @return static - */ - public function whereIn($key, $values, $strict = false) - { - $values = $this->getArrayableItems($values); - - return $this->filter(function ($item) use ($key, $values, $strict) { - return in_array(data_get($item, $key), $values, $strict); - }); - } - - /** - * Filter items by the given key value pair using strict comparison. - * - * @param string $key - * @param mixed $values - * @return static - */ - public function whereInStrict($key, $values) - { - return $this->whereIn($key, $values, true); - } - - /** - * Filter items such that the value of the given key is between the given values. - * - * @param string $key - * @param array $values - * @return static - */ - public function whereBetween($key, $values) - { - return $this->where($key, '>=', reset($values))->where($key, '<=', end($values)); - } - - /** - * Filter items such that the value of the given key is not between the given values. - * - * @param string $key - * @param array $values - * @return static - */ - public function whereNotBetween($key, $values) - { - return $this->filter(function ($item) use ($key, $values) { - return data_get($item, $key) < reset($values) || data_get($item, $key) > end($values); - }); - } - - /** - * Filter items by the given key value pair. - * - * @param string $key - * @param mixed $values - * @param bool $strict - * @return static - */ - public function whereNotIn($key, $values, $strict = false) - { - $values = $this->getArrayableItems($values); - - return $this->reject(function ($item) use ($key, $values, $strict) { - return in_array(data_get($item, $key), $values, $strict); - }); - } - - /** - * Filter items by the given key value pair using strict comparison. - * - * @param string $key - * @param mixed $values - * @return static - */ - public function whereNotInStrict($key, $values) - { - return $this->whereNotIn($key, $values, true); - } - - /** - * Filter the items, removing any items that don't match the given type. - * - * @param string $type - * @return static - */ - public function whereInstanceOf($type) - { - return $this->filter(function ($value) use ($type) { - return $value instanceof $type; - }); - } - - /** - * Get the first item from the collection passing the given truth test. - * - * @param callable|null $callback - * @param mixed $default - * @return mixed - */ - public function first(callable $callback = null, $default = null) - { - return Arr::first($this->items, $callback, $default); - } - - /** - * Get the first item by the given key value pair. - * - * @param string $key - * @param mixed $operator - * @param mixed $value - * @return mixed - */ - public function firstWhere($key, $operator = null, $value = null) - { - return $this->first($this->operatorForWhere(...func_get_args())); - } - - /** - * Get a flattened array of the items in the collection. - * - * @param int $depth - * @return static - */ - public function flatten($depth = INF) - { - return new static(Arr::flatten($this->items, $depth)); - } - - /** - * Flip the items in the collection. - * - * @return static - */ - public function flip() - { - return new static(array_flip($this->items)); - } - - /** - * Remove an item from the collection by key. - * - * @param string|array $keys - * @return $this - */ - public function forget($keys) - { - foreach ((array) $keys as $key) { - $this->offsetUnset($key); - } - - return $this; - } - - /** - * Get an item from the collection by key. - * - * @param mixed $key - * @param mixed $default - * @return mixed - */ - public function get($key, $default = null) - { - if ($this->offsetExists($key)) { - return $this->items[$key]; - } - - return value($default); - } - - /** - * Group an associative array by a field or using a callback. - * - * @param array|callable|string $groupBy - * @param bool $preserveKeys - * @return static - */ - public function groupBy($groupBy, $preserveKeys = false) - { - if (is_array($groupBy)) { - $nextGroups = $groupBy; - - $groupBy = array_shift($nextGroups); - } - - $groupBy = $this->valueRetriever($groupBy); - - $results = []; - - foreach ($this->items as $key => $value) { - $groupKeys = $groupBy($value, $key); - - if (! is_array($groupKeys)) { - $groupKeys = [$groupKeys]; - } - - foreach ($groupKeys as $groupKey) { - $groupKey = is_bool($groupKey) ? (int) $groupKey : $groupKey; - - if (! array_key_exists($groupKey, $results)) { - $results[$groupKey] = new static; - } - - $results[$groupKey]->offsetSet($preserveKeys ? $key : null, $value); - } - } - - $result = new static($results); - - if (! empty($nextGroups)) { - return $result->map->groupBy($nextGroups, $preserveKeys); - } - - return $result; - } - - /** - * Key an associative array by a field or using a callback. - * - * @param callable|string $keyBy - * @return static - */ - public function keyBy($keyBy) - { - $keyBy = $this->valueRetriever($keyBy); - - $results = []; - - foreach ($this->items as $key => $item) { - $resolvedKey = $keyBy($item, $key); - - if (is_object($resolvedKey)) { - $resolvedKey = (string) $resolvedKey; - } - - $results[$resolvedKey] = $item; - } - - return new static($results); - } - - /** - * Determine if an item exists in the collection by key. - * - * @param mixed $key - * @return bool - */ - public function has($key) - { - $keys = is_array($key) ? $key : func_get_args(); - - foreach ($keys as $value) { - if (! $this->offsetExists($value)) { - return false; - } - } - - return true; - } - - /** - * Concatenate values of a given key as a string. - * - * @param string $value - * @param string $glue - * @return string - */ - public function implode($value, $glue = null) - { - $first = $this->first(); - - if (is_array($first) || is_object($first)) { - return implode($glue, $this->pluck($value)->all()); - } - - return implode($value, $this->items); - } - - /** - * Intersect the collection with the given items. - * - * @param mixed $items - * @return static - */ - public function intersect($items) - { - return new static(array_intersect($this->items, $this->getArrayableItems($items))); - } - - /** - * Intersect the collection with the given items by key. - * - * @param mixed $items - * @return static - */ - public function intersectByKeys($items) - { - return new static(array_intersect_key( - $this->items, $this->getArrayableItems($items) - )); - } - - /** - * Determine if the collection is empty or not. - * - * @return bool - */ - public function isEmpty() - { - return empty($this->items); - } - - /** - * Determine if the collection is not empty. - * - * @return bool - */ - public function isNotEmpty() - { - return ! $this->isEmpty(); - } - - /** - * Determine if the given value is callable, but not a string. - * - * @param mixed $value - * @return bool - */ - protected function useAsCallable($value) - { - return ! is_string($value) && is_callable($value); - } - - /** - * Join all items from the collection using a string. The final items can use a separate glue string. - * - * @param string $glue - * @param string $finalGlue - * @return string - */ - public function join($glue, $finalGlue = '') - { - if ($finalGlue === '') { - return $this->implode($glue); - } - - $count = $this->count(); - - if ($count === 0) { - return ''; - } - - if ($count === 1) { - return $this->last(); - } - - $collection = new static($this->items); - - $finalItem = $collection->pop(); - - return $collection->implode($glue).$finalGlue.$finalItem; - } - - /** - * Get the keys of the collection items. - * - * @return static - */ - public function keys() - { - return new static(array_keys($this->items)); - } - - /** - * Get the last item from the collection. - * - * @param callable|null $callback - * @param mixed $default - * @return mixed - */ - public function last(callable $callback = null, $default = null) - { - return Arr::last($this->items, $callback, $default); - } - - /** - * Get the values of a given key. - * - * @param string|array $value - * @param string|null $key - * @return static - */ - public function pluck($value, $key = null) - { - return new static(Arr::pluck($this->items, $value, $key)); - } - - /** - * Run a map over each of the items. - * - * @param callable $callback - * @return static - */ - public function map(callable $callback) - { - $keys = array_keys($this->items); - - $items = array_map($callback, $this->items, $keys); - - return new static(array_combine($keys, $items)); - } - - /** - * Run a map over each nested chunk of items. - * - * @param callable $callback - * @return static - */ - public function mapSpread(callable $callback) - { - return $this->map(function ($chunk, $key) use ($callback) { - $chunk[] = $key; - - return $callback(...$chunk); - }); - } - - /** - * Run a dictionary map over the items. - * - * The callback should return an associative array with a single key/value pair. - * - * @param callable $callback - * @return static - */ - public function mapToDictionary(callable $callback) - { - $dictionary = []; - - foreach ($this->items as $key => $item) { - $pair = $callback($item, $key); - - $key = key($pair); - - $value = reset($pair); - - if (! isset($dictionary[$key])) { - $dictionary[$key] = []; - } - - $dictionary[$key][] = $value; - } - - return new static($dictionary); - } - - /** - * Run a grouping map over the items. - * - * The callback should return an associative array with a single key/value pair. - * - * @param callable $callback - * @return static - */ - public function mapToGroups(callable $callback) - { - $groups = $this->mapToDictionary($callback); - - return $groups->map([$this, 'make']); - } - - /** - * Run an associative map over each of the items. - * - * The callback should return an associative array with a single key/value pair. - * - * @param callable $callback - * @return static - */ - public function mapWithKeys(callable $callback) - { - $result = []; - - foreach ($this->items as $key => $value) { - $assoc = $callback($value, $key); - - foreach ($assoc as $mapKey => $mapValue) { - $result[$mapKey] = $mapValue; - } - } - - return new static($result); - } - - /** - * Map a collection and flatten the result by a single level. - * - * @param callable $callback - * @return static - */ - public function flatMap(callable $callback) - { - return $this->map($callback)->collapse(); - } - - /** - * Map the values into a new class. - * - * @param string $class - * @return static - */ - public function mapInto($class) - { - return $this->map(function ($value, $key) use ($class) { - return new $class($value, $key); - }); - } - - /** - * Get the max value of a given key. - * - * @param callable|string|null $callback - * @return mixed - */ - public function max($callback = null) - { - $callback = $this->valueRetriever($callback); - - return $this->filter(function ($value) { - return ! is_null($value); - })->reduce(function ($result, $item) use ($callback) { - $value = $callback($item); - - return is_null($result) || $value > $result ? $value : $result; - }); - } - - /** - * Merge the collection with the given items. - * - * @param mixed $items - * @return static - */ - public function merge($items) - { - return new static(array_merge($this->items, $this->getArrayableItems($items))); - } - - /** - * Create a collection by using this collection for keys and another for its values. - * - * @param mixed $values - * @return static - */ - public function combine($values) - { - return new static(array_combine($this->all(), $this->getArrayableItems($values))); - } - - /** - * Union the collection with the given items. - * - * @param mixed $items - * @return static - */ - public function union($items) - { - return new static($this->items + $this->getArrayableItems($items)); - } - - /** - * Get the min value of a given key. - * - * @param callable|string|null $callback - * @return mixed - */ - public function min($callback = null) - { - $callback = $this->valueRetriever($callback); - - return $this->map(function ($value) use ($callback) { - return $callback($value); - })->filter(function ($value) { - return ! is_null($value); - })->reduce(function ($result, $value) { - return is_null($result) || $value < $result ? $value : $result; - }); - } - - /** - * Create a new collection consisting of every n-th element. - * - * @param int $step - * @param int $offset - * @return static - */ - public function nth($step, $offset = 0) - { - $new = []; - - $position = 0; - - foreach ($this->items as $item) { - if ($position % $step === $offset) { - $new[] = $item; - } - - $position++; - } - - return new static($new); - } - - /** - * Get the items with the specified keys. - * - * @param mixed $keys - * @return static - */ - public function only($keys) - { - if (is_null($keys)) { - return new static($this->items); - } - - if ($keys instanceof self) { - $keys = $keys->all(); - } - - $keys = is_array($keys) ? $keys : func_get_args(); - - return new static(Arr::only($this->items, $keys)); - } - - /** - * "Paginate" the collection by slicing it into a smaller collection. - * - * @param int $page - * @param int $perPage - * @return static - */ - public function forPage($page, $perPage) - { - $offset = max(0, ($page - 1) * $perPage); - - return $this->slice($offset, $perPage); - } - - /** - * Partition the collection into two arrays using the given callback or key. - * - * @param callable|string $key - * @param mixed $operator - * @param mixed $value - * @return static - */ - public function partition($key, $operator = null, $value = null) - { - $partitions = [new static, new static]; - - $callback = func_num_args() === 1 - ? $this->valueRetriever($key) - : $this->operatorForWhere(...func_get_args()); - - foreach ($this->items as $key => $item) { - $partitions[(int) ! $callback($item, $key)][$key] = $item; - } - - return new static($partitions); - } - - /** - * Pass the collection to the given callback and return the result. - * - * @param callable $callback - * @return mixed - */ - public function pipe(callable $callback) - { - return $callback($this); - } - - /** - * Get and remove the last item from the collection. - * - * @return mixed - */ - public function pop() - { - return array_pop($this->items); - } - - /** - * Push an item onto the beginning of the collection. - * - * @param mixed $value - * @param mixed $key - * @return $this - */ - public function prepend($value, $key = null) - { - $this->items = Arr::prepend($this->items, $value, $key); - - return $this; - } - - /** - * Push an item onto the end of the collection. - * - * @param mixed $value - * @return $this - */ - public function push($value) - { - $this->offsetSet(null, $value); - - return $this; - } - - /** - * Push all of the given items onto the collection. - * - * @param iterable $source - * @return static - */ - public function concat($source) - { - $result = new static($this); - - foreach ($source as $item) { - $result->push($item); - } - - return $result; - } - - /** - * Get and remove an item from the collection. - * - * @param mixed $key - * @param mixed $default - * @return mixed - */ - public function pull($key, $default = null) - { - return Arr::pull($this->items, $key, $default); - } - - /** - * Put an item in the collection by key. - * - * @param mixed $key - * @param mixed $value - * @return $this - */ - public function put($key, $value) - { - $this->offsetSet($key, $value); - - return $this; - } - - /** - * Get one or a specified number of items randomly from the collection. - * - * @param int|null $number - * @return static|mixed - * - * @throws \InvalidArgumentException - */ - public function random($number = null) - { - if (is_null($number)) { - return Arr::random($this->items); - } - - return new static(Arr::random($this->items, $number)); - } - - /** - * Reduce the collection to a single value. - * - * @param callable $callback - * @param mixed $initial - * @return mixed - */ - public function reduce(callable $callback, $initial = null) - { - return array_reduce($this->items, $callback, $initial); - } - - /** - * Create a collection of all elements that do not pass a given truth test. - * - * @param callable|mixed $callback - * @return static - */ - public function reject($callback = true) - { - $useAsCallable = $this->useAsCallable($callback); - - return $this->filter(function ($value, $key) use ($callback, $useAsCallable) { - return $useAsCallable - ? ! $callback($value, $key) - : $value != $callback; - }); - } - - /** - * Reverse items order. - * - * @return static - */ - public function reverse() - { - return new static(array_reverse($this->items, true)); - } - - /** - * Search the collection for a given value and return the corresponding key if successful. - * - * @param mixed $value - * @param bool $strict - * @return mixed - */ - public function search($value, $strict = false) - { - if (! $this->useAsCallable($value)) { - return array_search($value, $this->items, $strict); - } - - foreach ($this->items as $key => $item) { - if (call_user_func($value, $item, $key)) { - return $key; - } - } - - return false; - } - - /** - * Get and remove the first item from the collection. - * - * @return mixed - */ - public function shift() - { - return array_shift($this->items); - } - - /** - * Shuffle the items in the collection. - * - * @param int $seed - * @return static - */ - public function shuffle($seed = null) - { - return new static(Arr::shuffle($this->items, $seed)); - } - - /** - * Slice the underlying collection array. - * - * @param int $offset - * @param int $length - * @return static - */ - public function slice($offset, $length = null) - { - return new static(array_slice($this->items, $offset, $length, true)); - } - - /** - * Split a collection into a certain number of groups. - * - * @param int $numberOfGroups - * @return static - */ - public function split($numberOfGroups) - { - if ($this->isEmpty()) { - return new static; - } - - $groups = new static; - - $groupSize = floor($this->count() / $numberOfGroups); - - $remain = $this->count() % $numberOfGroups; - - $start = 0; - - for ($i = 0; $i < $numberOfGroups; $i++) { - $size = $groupSize; - - if ($i < $remain) { - $size++; - } - - if ($size) { - $groups->push(new static(array_slice($this->items, $start, $size))); - - $start += $size; - } - } - - return $groups; - } - - /** - * Chunk the underlying collection array. - * - * @param int $size - * @return static - */ - public function chunk($size) - { - if ($size <= 0) { - return new static; - } - - $chunks = []; - - foreach (array_chunk($this->items, $size, true) as $chunk) { - $chunks[] = new static($chunk); - } - - return new static($chunks); - } - - /** - * Sort through each item with a callback. - * - * @param callable|null $callback - * @return static - */ - public function sort(callable $callback = null) - { - $items = $this->items; - - $callback - ? uasort($items, $callback) - : asort($items); - - return new static($items); - } - - /** - * Sort the collection using the given callback. - * - * @param callable|string $callback - * @param int $options - * @param bool $descending - * @return static - */ - public function sortBy($callback, $options = SORT_REGULAR, $descending = false) - { - $results = []; - - $callback = $this->valueRetriever($callback); - - // First we will loop through the items and get the comparator from a callback - // function which we were given. Then, we will sort the returned values and - // and grab the corresponding values for the sorted keys from this array. - foreach ($this->items as $key => $value) { - $results[$key] = $callback($value, $key); - } - - $descending ? arsort($results, $options) - : asort($results, $options); - - // Once we have sorted all of the keys in the array, we will loop through them - // and grab the corresponding model so we can set the underlying items list - // to the sorted version. Then we'll just return the collection instance. - foreach (array_keys($results) as $key) { - $results[$key] = $this->items[$key]; - } - - return new static($results); - } - - /** - * Sort the collection in descending order using the given callback. - * - * @param callable|string $callback - * @param int $options - * @return static - */ - public function sortByDesc($callback, $options = SORT_REGULAR) - { - return $this->sortBy($callback, $options, true); - } - - /** - * Sort the collection keys. - * - * @param int $options - * @param bool $descending - * @return static - */ - public function sortKeys($options = SORT_REGULAR, $descending = false) - { - $items = $this->items; - - $descending ? krsort($items, $options) : ksort($items, $options); - - return new static($items); - } - - /** - * Sort the collection keys in descending order. - * - * @param int $options - * @return static - */ - public function sortKeysDesc($options = SORT_REGULAR) - { - return $this->sortKeys($options, true); - } - - /** - * Splice a portion of the underlying collection array. - * - * @param int $offset - * @param int|null $length - * @param mixed $replacement - * @return static - */ - public function splice($offset, $length = null, $replacement = []) - { - if (func_num_args() === 1) { - return new static(array_splice($this->items, $offset)); - } - - return new static(array_splice($this->items, $offset, $length, $replacement)); - } - - /** - * Get the sum of the given values. - * - * @param callable|string|null $callback - * @return mixed - */ - public function sum($callback = null) - { - if (is_null($callback)) { - return array_sum($this->items); - } - - $callback = $this->valueRetriever($callback); - - return $this->reduce(function ($result, $item) use ($callback) { - return $result + $callback($item); - }, 0); - } - - /** - * Take the first or last {$limit} items. - * - * @param int $limit - * @return static - */ - public function take($limit) - { - if ($limit < 0) { - return $this->slice($limit, abs($limit)); - } - - return $this->slice(0, $limit); - } - - /** - * Pass the collection to the given callback and then return it. - * - * @param callable $callback - * @return $this - */ - public function tap(callable $callback) - { - $callback(new static($this->items)); - - return $this; - } - - /** - * Transform each item in the collection using a callback. - * - * @param callable $callback - * @return $this - */ - public function transform(callable $callback) - { - $this->items = $this->map($callback)->all(); - - return $this; - } - - /** - * Return only unique items from the collection array. - * - * @param string|callable|null $key - * @param bool $strict - * @return static - */ - public function unique($key = null, $strict = false) - { - $callback = $this->valueRetriever($key); - - $exists = []; - - return $this->reject(function ($item, $key) use ($callback, $strict, &$exists) { - if (in_array($id = $callback($item, $key), $exists, $strict)) { - return true; - } - - $exists[] = $id; - }); - } - - /** - * Return only unique items from the collection array using strict comparison. - * - * @param string|callable|null $key - * @return static - */ - public function uniqueStrict($key = null) - { - return $this->unique($key, true); - } - - /** - * Reset the keys on the underlying array. - * - * @return static - */ - public function values() - { - return new static(array_values($this->items)); - } - - /** - * Get a value retrieving callback. - * - * @param callable|string|null $value - * @return callable - */ - protected function valueRetriever($value) - { - if ($this->useAsCallable($value)) { - return $value; - } - - return function ($item) use ($value) { - return data_get($item, $value); - }; - } - - /** - * Zip the collection together with one or more arrays. - * - * e.g. new Collection([1, 2, 3])->zip([4, 5, 6]); - * => [[1, 4], [2, 5], [3, 6]] - * - * @param mixed ...$items - * @return static - */ - public function zip($items) - { - $arrayableItems = array_map(function ($items) { - return $this->getArrayableItems($items); - }, func_get_args()); - - $params = array_merge([function () { - return new static(func_get_args()); - }, $this->items], $arrayableItems); - - return new static(call_user_func_array('array_map', $params)); - } - - /** - * Pad collection to the specified length with a value. - * - * @param int $size - * @param mixed $value - * @return static - */ - public function pad($size, $value) - { - return new static(array_pad($this->items, $size, $value)); - } - - /** - * Get the collection of items as a plain array. - * - * @return array - */ - public function toArray() - { - return array_map(function ($value) { - return $value instanceof Arrayable ? $value->toArray() : $value; - }, $this->items); - } - - /** - * Convert the object into something JSON serializable. - * - * @return array - */ - public function jsonSerialize() - { - return array_map(function ($value) { - if ($value instanceof JsonSerializable) { - return $value->jsonSerialize(); - } elseif ($value instanceof Jsonable) { - return json_decode($value->toJson(), true); - } elseif ($value instanceof Arrayable) { - return $value->toArray(); - } - - return $value; - }, $this->items); - } - - /** - * Get the collection of items as JSON. - * - * @param int $options - * @return string - */ - public function toJson($options = 0) - { - return json_encode($this->jsonSerialize(), $options); - } - - /** - * Get an iterator for the items. - * - * @return \ArrayIterator - */ - public function getIterator() - { - return new ArrayIterator($this->items); - } - - /** - * Get a CachingIterator instance. - * - * @param int $flags - * @return \CachingIterator - */ - public function getCachingIterator($flags = CachingIterator::CALL_TOSTRING) - { - return new CachingIterator($this->getIterator(), $flags); - } - - /** - * Count the number of items in the collection. - * - * @return int - */ - public function count() - { - return count($this->items); - } - - /** - * Count the number of items in the collection using a given truth test. - * - * @param callable|null $callback - * @return static - */ - public function countBy($callback = null) - { - if (is_null($callback)) { - $callback = function ($value) { - return $value; - }; - } - - return new static($this->groupBy($callback)->map(function ($value) { - return $value->count(); - })); - } - - /** - * Add an item to the collection. - * - * @param mixed $item - * @return $this - */ - public function add($item) - { - $this->items[] = $item; - - return $this; - } - - /** - * Get a base Support collection instance from this collection. - * - * @return \Illuminate\Support\Collection - */ - public function toBase() - { - return new self($this); - } - - /** - * Determine if an item exists at an offset. - * - * @param mixed $key - * @return bool - */ - public function offsetExists($key) - { - return array_key_exists($key, $this->items); - } - - /** - * Get an item at a given offset. - * - * @param mixed $key - * @return mixed - */ - public function offsetGet($key) - { - return $this->items[$key]; - } - - /** - * Set the item at a given offset. - * - * @param mixed $key - * @param mixed $value - * @return void - */ - public function offsetSet($key, $value) - { - if (is_null($key)) { - $this->items[] = $value; - } else { - $this->items[$key] = $value; - } - } - - /** - * Unset the item at a given offset. - * - * @param string $key - * @return void - */ - public function offsetUnset($key) - { - unset($this->items[$key]); - } - - /** - * Convert the collection to its string representation. - * - * @return string - */ - public function __toString() - { - return $this->toJson(); - } - - /** - * Results array of items from Collection or Arrayable. - * - * @param mixed $items - * @return array - */ - protected function getArrayableItems($items) - { - if (is_array($items)) { - return $items; - } elseif ($items instanceof self) { - return $items->all(); - } elseif ($items instanceof Arrayable) { - return $items->toArray(); - } elseif ($items instanceof Jsonable) { - return json_decode($items->toJson(), true); - } elseif ($items instanceof JsonSerializable) { - return $items->jsonSerialize(); - } elseif ($items instanceof Traversable) { - return iterator_to_array($items); - } - - return (array) $items; - } - - /** - * Add a method to the list of proxied methods. - * - * @param string $method - * @return void - */ - public static function proxy($method) - { - static::$proxies[] = $method; - } - - /** - * Dynamically access collection proxies. - * - * @param string $key - * @return mixed - * - * @throws \Exception - */ - public function __get($key) - { - if (! in_array($key, static::$proxies)) { - throw new Exception("Property [{$key}] does not exist on this collection instance."); - } - - return new HigherOrderCollectionProxy($this, $key); - } -} diff --git a/vendor/illuminate/support/Composer.php b/vendor/illuminate/support/Composer.php deleted file mode 100644 index 63a00e9ac8..0000000000 --- a/vendor/illuminate/support/Composer.php +++ /dev/null @@ -1,110 +0,0 @@ -files = $files; - $this->workingPath = $workingPath; - } - - /** - * Regenerate the Composer autoloader files. - * - * @param string|array $extra - * @return void - */ - public function dumpAutoloads($extra = '') - { - $extra = $extra ? (array) $extra : []; - - $command = array_merge($this->findComposer(), ['dump-autoload'], $extra); - - $this->getProcess($command)->run(); - } - - /** - * Regenerate the optimized Composer autoloader files. - * - * @return void - */ - public function dumpOptimized() - { - $this->dumpAutoloads('--optimize'); - } - - /** - * Get the composer command for the environment. - * - * @return array - */ - protected function findComposer() - { - if ($this->files->exists($this->workingPath.'/composer.phar')) { - return [$this->phpBinary(), 'composer.phar']; - } - - return ['composer']; - } - - /** - * Get the PHP binary. - * - * @return string - */ - protected function phpBinary() - { - return ProcessUtils::escapeArgument((new PhpExecutableFinder)->find(false)); - } - - /** - * Get a new Symfony process instance. - * - * @param array $command - * @return \Symfony\Component\Process\Process - */ - protected function getProcess(array $command) - { - return (new Process($command, $this->workingPath))->setTimeout(null); - } - - /** - * Set the working path used by the class. - * - * @param string $path - * @return $this - */ - public function setWorkingPath($path) - { - $this->workingPath = realpath($path); - - return $this; - } -} diff --git a/vendor/illuminate/support/ConfigurationUrlParser.php b/vendor/illuminate/support/ConfigurationUrlParser.php deleted file mode 100644 index 308ff8f890..0000000000 --- a/vendor/illuminate/support/ConfigurationUrlParser.php +++ /dev/null @@ -1,189 +0,0 @@ - 'sqlsrv', - 'mysql2' => 'mysql', // RDS - 'postgres' => 'pgsql', - 'postgresql' => 'pgsql', - 'sqlite3' => 'sqlite', - ]; - - /** - * Parse the database configuration, hydrating options using a database configuration URL if possible. - * - * @param array|string $config - * @return array - */ - public function parseConfiguration($config) - { - if (is_string($config)) { - $config = ['url' => $config]; - } - - $url = $config['url'] ?? null; - - $config = Arr::except($config, 'url'); - - if (! $url) { - return $config; - } - - $parsedUrl = $this->parseUrl($url); - - return array_merge( - $config, - $this->getPrimaryOptions($parsedUrl), - $this->getQueryOptions($parsedUrl) - ); - } - - /** - * Get the primary database connection options. - * - * @param array $url - * @return array - */ - protected function getPrimaryOptions($url) - { - return array_filter([ - 'driver' => $this->getDriver($url), - 'database' => $this->getDatabase($url), - 'host' => $url['host'] ?? null, - 'port' => $url['port'] ?? null, - 'username' => $url['user'] ?? null, - 'password' => $url['pass'] ?? null, - ], function ($value) { - return ! is_null($value); - }); - } - - /** - * Get the database driver from the URL. - * - * @param array $url - * @return string|null - */ - protected function getDriver($url) - { - $alias = $url['scheme'] ?? null; - - if (! $alias) { - return; - } - - return static::$driverAliases[$alias] ?? $alias; - } - - /** - * Get the database name from the URL. - * - * @param array $url - * @return string|null - */ - protected function getDatabase($url) - { - $path = $url['path'] ?? null; - - return $path ? substr($path, 1) : null; - } - - /** - * Get all of the additional database options from the query string. - * - * @param array $url - * @return array - */ - protected function getQueryOptions($url) - { - $queryString = $url['query'] ?? null; - - if (! $queryString) { - return []; - } - - $query = []; - - parse_str($queryString, $query); - - return $this->parseStringsToNativeTypes($query); - } - - /** - * Parse the string URL to an array of components. - * - * @param string $url - * @return array - */ - protected function parseUrl($url) - { - $url = preg_replace('#^(sqlite3?):///#', '$1://null/', $url); - - $parsedUrl = parse_url($url); - - if ($parsedUrl === false) { - throw new InvalidArgumentException('The database configuration URL is malformed.'); - } - - return $this->parseStringsToNativeTypes( - array_map('rawurldecode', $parsedUrl) - ); - } - - /** - * Convert string casted values to their native types. - * - * @param mixed $value - * @return mixed - */ - protected function parseStringsToNativeTypes($value) - { - if (is_array($value)) { - return array_map([$this, 'parseStringsToNativeTypes'], $value); - } - - if (! is_string($value)) { - return $value; - } - - $parsedValue = json_decode($value, true); - - if (json_last_error() === JSON_ERROR_NONE) { - return $parsedValue; - } - - return $value; - } - - /** - * Get all of the current drivers aliases. - * - * @return array - */ - public static function getDriverAliases() - { - return static::$driverAliases; - } - - /** - * Add the given driver alias to the driver aliases array. - * - * @param string $alias - * @param string $driver - * @return void - */ - public static function addDriverAlias($alias, $driver) - { - static::$driverAliases[$alias] = $driver; - } -} diff --git a/vendor/illuminate/support/DateFactory.php b/vendor/illuminate/support/DateFactory.php deleted file mode 100644 index cb679c7453..0000000000 --- a/vendor/illuminate/support/DateFactory.php +++ /dev/null @@ -1,230 +0,0 @@ -$method(...$parameters); - } - - $dateClass = static::$dateClass ?: $defaultClassName; - - // Check if date can be created using public class method... - if (method_exists($dateClass, $method) || - method_exists($dateClass, 'hasMacro') && $dateClass::hasMacro($method)) { - return $dateClass::$method(...$parameters); - } - - // If that fails, create the date with the default class.. - $date = $defaultClassName::$method(...$parameters); - - // If the configured class has an "instance" method, we'll try to pass our date into there... - if (method_exists($dateClass, 'instance')) { - return $dateClass::instance($date); - } - - // Otherwise, assume the configured class has a DateTime compatible constructor... - return new $dateClass($date->format('Y-m-d H:i:s.u'), $date->getTimezone()); - } -} diff --git a/vendor/illuminate/support/Facades/App.php b/vendor/illuminate/support/Facades/App.php deleted file mode 100755 index 67e0b4c233..0000000000 --- a/vendor/illuminate/support/Facades/App.php +++ /dev/null @@ -1,58 +0,0 @@ -make('router')->auth($options); - } -} diff --git a/vendor/illuminate/support/Facades/Blade.php b/vendor/illuminate/support/Facades/Blade.php deleted file mode 100755 index 003176c72f..0000000000 --- a/vendor/illuminate/support/Facades/Blade.php +++ /dev/null @@ -1,36 +0,0 @@ -cookie($key, null)); - } - - /** - * Retrieve a cookie from the request. - * - * @param string $key - * @param mixed $default - * @return string|array|null - */ - public static function get($key = null, $default = null) - { - return static::$app['request']->cookie($key, $default); - } - - /** - * Get the registered name of the component. - * - * @return string - */ - protected static function getFacadeAccessor() - { - return 'cookie'; - } -} diff --git a/vendor/illuminate/support/Facades/Crypt.php b/vendor/illuminate/support/Facades/Crypt.php deleted file mode 100755 index 20f269d9b4..0000000000 --- a/vendor/illuminate/support/Facades/Crypt.php +++ /dev/null @@ -1,27 +0,0 @@ -afterResolving(static::getFacadeAccessor(), function ($service) use ($callback) { - $callback($service); - }); - } - - /** - * Convert the facade into a Mockery spy. - * - * @return \Mockery\MockInterface - */ - public static function spy() - { - if (! static::isMock()) { - $class = static::getMockableClass(); - - return tap($class ? Mockery::spy($class) : Mockery::spy(), function ($spy) { - static::swap($spy); - }); - } - } - - /** - * Initiate a mock expectation on the facade. - * - * @return \Mockery\Expectation - */ - public static function shouldReceive() - { - $name = static::getFacadeAccessor(); - - $mock = static::isMock() - ? static::$resolvedInstance[$name] - : static::createFreshMockInstance(); - - return $mock->shouldReceive(...func_get_args()); - } - - /** - * Create a fresh mock instance for the given class. - * - * @return \Mockery\Expectation - */ - protected static function createFreshMockInstance() - { - return tap(static::createMock(), function ($mock) { - static::swap($mock); - - $mock->shouldAllowMockingProtectedMethods(); - }); - } - - /** - * Create a fresh mock instance for the given class. - * - * @return \Mockery\MockInterface - */ - protected static function createMock() - { - $class = static::getMockableClass(); - - return $class ? Mockery::mock($class) : Mockery::mock(); - } - - /** - * Determines whether a mock is set as the instance of the facade. - * - * @return bool - */ - protected static function isMock() - { - $name = static::getFacadeAccessor(); - - return isset(static::$resolvedInstance[$name]) && - static::$resolvedInstance[$name] instanceof MockInterface; - } - - /** - * Get the mockable class for the bound instance. - * - * @return string|null - */ - protected static function getMockableClass() - { - if ($root = static::getFacadeRoot()) { - return get_class($root); - } - } - - /** - * Hotswap the underlying instance behind the facade. - * - * @param mixed $instance - * @return void - */ - public static function swap($instance) - { - static::$resolvedInstance[static::getFacadeAccessor()] = $instance; - - if (isset(static::$app)) { - static::$app->instance(static::getFacadeAccessor(), $instance); - } - } - - /** - * Get the root object behind the facade. - * - * @return mixed - */ - public static function getFacadeRoot() - { - return static::resolveFacadeInstance(static::getFacadeAccessor()); - } - - /** - * Get the registered name of the component. - * - * @return string - * - * @throws \RuntimeException - */ - protected static function getFacadeAccessor() - { - throw new RuntimeException('Facade does not implement getFacadeAccessor method.'); - } - - /** - * Resolve the facade root instance from the container. - * - * @param object|string $name - * @return mixed - */ - protected static function resolveFacadeInstance($name) - { - if (is_object($name)) { - return $name; - } - - if (isset(static::$resolvedInstance[$name])) { - return static::$resolvedInstance[$name]; - } - - return static::$resolvedInstance[$name] = static::$app[$name]; - } - - /** - * Clear a resolved facade instance. - * - * @param string $name - * @return void - */ - public static function clearResolvedInstance($name) - { - unset(static::$resolvedInstance[$name]); - } - - /** - * Clear all of the resolved instances. - * - * @return void - */ - public static function clearResolvedInstances() - { - static::$resolvedInstance = []; - } - - /** - * Get the application instance behind the facade. - * - * @return \Illuminate\Contracts\Foundation\Application - */ - public static function getFacadeApplication() - { - return static::$app; - } - - /** - * Set the application instance. - * - * @param \Illuminate\Contracts\Foundation\Application $app - * @return void - */ - public static function setFacadeApplication($app) - { - static::$app = $app; - } - - /** - * Handle dynamic, static calls to the object. - * - * @param string $method - * @param array $args - * @return mixed - * - * @throws \RuntimeException - */ - public static function __callStatic($method, $args) - { - $instance = static::getFacadeRoot(); - - if (! $instance) { - throw new RuntimeException('A facade root has not been set.'); - } - - return $instance->$method(...$args); - } -} diff --git a/vendor/illuminate/support/Facades/File.php b/vendor/illuminate/support/Facades/File.php deleted file mode 100755 index b0a52e62bc..0000000000 --- a/vendor/illuminate/support/Facades/File.php +++ /dev/null @@ -1,57 +0,0 @@ -input($key, $default); - } - - /** - * Get the registered name of the component. - * - * @return string - */ - protected static function getFacadeAccessor() - { - return 'request'; - } -} diff --git a/vendor/illuminate/support/Facades/Lang.php b/vendor/illuminate/support/Facades/Lang.php deleted file mode 100755 index 5d533052ae..0000000000 --- a/vendor/illuminate/support/Facades/Lang.php +++ /dev/null @@ -1,25 +0,0 @@ -route($channel, $route); - } - - /** - * Get the registered name of the component. - * - * @return string - */ - protected static function getFacadeAccessor() - { - return ChannelManager::class; - } -} diff --git a/vendor/illuminate/support/Facades/Password.php b/vendor/illuminate/support/Facades/Password.php deleted file mode 100755 index c291b97f46..0000000000 --- a/vendor/illuminate/support/Facades/Password.php +++ /dev/null @@ -1,59 +0,0 @@ -connection($name)->getSchemaBuilder(); - } - - /** - * Get a schema builder instance for the default connection. - * - * @return \Illuminate\Database\Schema\Builder - */ - protected static function getFacadeAccessor() - { - return static::$app['db']->connection()->getSchemaBuilder(); - } -} diff --git a/vendor/illuminate/support/Facades/Session.php b/vendor/illuminate/support/Facades/Session.php deleted file mode 100755 index 4df35ce95b..0000000000 --- a/vendor/illuminate/support/Facades/Session.php +++ /dev/null @@ -1,43 +0,0 @@ -get('filesystems.default'); - - (new Filesystem)->cleanDirectory( - $root = storage_path('framework/testing/disks/'.$disk) - ); - - static::set($disk, $fake = self::createLocalDriver(['root' => $root])); - - return $fake; - } - - /** - * Replace the given disk with a persistent local testing disk. - * - * @param string|null $disk - * @return \Illuminate\Filesystem\Filesystem - */ - public static function persistentFake($disk = null) - { - $disk = $disk ?: self::$app['config']->get('filesystems.default'); - - static::set($disk, $fake = self::createLocalDriver([ - 'root' => storage_path('framework/testing/disks/'.$disk), - ])); - - return $fake; - } - - /** - * Get the registered name of the component. - * - * @return string - */ - protected static function getFacadeAccessor() - { - return 'filesystem'; - } -} diff --git a/vendor/illuminate/support/Facades/URL.php b/vendor/illuminate/support/Facades/URL.php deleted file mode 100755 index baa2356966..0000000000 --- a/vendor/illuminate/support/Facades/URL.php +++ /dev/null @@ -1,33 +0,0 @@ - $value) { - $this->attributes[$key] = $value; - } - } - - /** - * Get an attribute from the fluent instance. - * - * @param string $key - * @param mixed $default - * @return mixed - */ - public function get($key, $default = null) - { - if (array_key_exists($key, $this->attributes)) { - return $this->attributes[$key]; - } - - return value($default); - } - - /** - * Get the attributes from the fluent instance. - * - * @return array - */ - public function getAttributes() - { - return $this->attributes; - } - - /** - * Convert the fluent instance to an array. - * - * @return array - */ - public function toArray() - { - return $this->attributes; - } - - /** - * Convert the object into something JSON serializable. - * - * @return array - */ - public function jsonSerialize() - { - return $this->toArray(); - } - - /** - * Convert the fluent instance to JSON. - * - * @param int $options - * @return string - */ - public function toJson($options = 0) - { - return json_encode($this->jsonSerialize(), $options); - } - - /** - * Determine if the given offset exists. - * - * @param string $offset - * @return bool - */ - public function offsetExists($offset) - { - return isset($this->attributes[$offset]); - } - - /** - * Get the value for a given offset. - * - * @param string $offset - * @return mixed - */ - public function offsetGet($offset) - { - return $this->get($offset); - } - - /** - * Set the value at the given offset. - * - * @param string $offset - * @param mixed $value - * @return void - */ - public function offsetSet($offset, $value) - { - $this->attributes[$offset] = $value; - } - - /** - * Unset the value at the given offset. - * - * @param string $offset - * @return void - */ - public function offsetUnset($offset) - { - unset($this->attributes[$offset]); - } - - /** - * Handle dynamic calls to the fluent instance to set attributes. - * - * @param string $method - * @param array $parameters - * @return $this - */ - public function __call($method, $parameters) - { - $this->attributes[$method] = count($parameters) > 0 ? $parameters[0] : true; - - return $this; - } - - /** - * Dynamically retrieve the value of an attribute. - * - * @param string $key - * @return mixed - */ - public function __get($key) - { - return $this->get($key); - } - - /** - * Dynamically set the value of an attribute. - * - * @param string $key - * @param mixed $value - * @return void - */ - public function __set($key, $value) - { - $this->offsetSet($key, $value); - } - - /** - * Dynamically check if an attribute is set. - * - * @param string $key - * @return bool - */ - public function __isset($key) - { - return $this->offsetExists($key); - } - - /** - * Dynamically unset an attribute. - * - * @param string $key - * @return void - */ - public function __unset($key) - { - $this->offsetUnset($key); - } -} diff --git a/vendor/illuminate/support/HigherOrderCollectionProxy.php b/vendor/illuminate/support/HigherOrderCollectionProxy.php deleted file mode 100644 index 7a781a0216..0000000000 --- a/vendor/illuminate/support/HigherOrderCollectionProxy.php +++ /dev/null @@ -1,63 +0,0 @@ -method = $method; - $this->collection = $collection; - } - - /** - * Proxy accessing an attribute onto the collection items. - * - * @param string $key - * @return mixed - */ - public function __get($key) - { - return $this->collection->{$this->method}(function ($value) use ($key) { - return is_array($value) ? $value[$key] : $value->{$key}; - }); - } - - /** - * Proxy a method call onto the collection items. - * - * @param string $method - * @param array $parameters - * @return mixed - */ - public function __call($method, $parameters) - { - return $this->collection->{$this->method}(function ($value) use ($method, $parameters) { - return $value->{$method}(...$parameters); - }); - } -} diff --git a/vendor/illuminate/support/HigherOrderTapProxy.php b/vendor/illuminate/support/HigherOrderTapProxy.php deleted file mode 100644 index bbf9b2e54d..0000000000 --- a/vendor/illuminate/support/HigherOrderTapProxy.php +++ /dev/null @@ -1,38 +0,0 @@ -target = $target; - } - - /** - * Dynamically pass method calls to the target. - * - * @param string $method - * @param array $parameters - * @return mixed - */ - public function __call($method, $parameters) - { - $this->target->{$method}(...$parameters); - - return $this->target; - } -} diff --git a/vendor/illuminate/support/HtmlString.php b/vendor/illuminate/support/HtmlString.php deleted file mode 100644 index c13adfd47e..0000000000 --- a/vendor/illuminate/support/HtmlString.php +++ /dev/null @@ -1,46 +0,0 @@ -html = $html; - } - - /** - * Get the HTML string. - * - * @return string - */ - public function toHtml() - { - return $this->html; - } - - /** - * Get the HTML string. - * - * @return string - */ - public function __toString() - { - return $this->toHtml(); - } -} diff --git a/vendor/illuminate/support/InteractsWithTime.php b/vendor/illuminate/support/InteractsWithTime.php deleted file mode 100644 index 2b617c392a..0000000000 --- a/vendor/illuminate/support/InteractsWithTime.php +++ /dev/null @@ -1,64 +0,0 @@ -parseDateInterval($delay); - - return $delay instanceof DateTimeInterface - ? max(0, $delay->getTimestamp() - $this->currentTime()) - : (int) $delay; - } - - /** - * Get the "available at" UNIX timestamp. - * - * @param \DateTimeInterface|\DateInterval|int $delay - * @return int - */ - protected function availableAt($delay = 0) - { - $delay = $this->parseDateInterval($delay); - - return $delay instanceof DateTimeInterface - ? $delay->getTimestamp() - : Carbon::now()->addRealSeconds($delay)->getTimestamp(); - } - - /** - * If the given value is an interval, convert it to a DateTime instance. - * - * @param \DateTimeInterface|\DateInterval|int $delay - * @return \DateTimeInterface|int - */ - protected function parseDateInterval($delay) - { - if ($delay instanceof DateInterval) { - $delay = Carbon::now()->add($delay); - } - - return $delay; - } - - /** - * Get the current system time as a UNIX timestamp. - * - * @return int - */ - protected function currentTime() - { - return Carbon::now()->getTimestamp(); - } -} diff --git a/vendor/illuminate/support/LICENSE.md b/vendor/illuminate/support/LICENSE.md deleted file mode 100644 index 79810c848f..0000000000 --- a/vendor/illuminate/support/LICENSE.md +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) Taylor Otwell - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/vendor/illuminate/support/Manager.php b/vendor/illuminate/support/Manager.php deleted file mode 100755 index 38e9308f71..0000000000 --- a/vendor/illuminate/support/Manager.php +++ /dev/null @@ -1,148 +0,0 @@ -app = $app; - } - - /** - * Get the default driver name. - * - * @return string - */ - abstract public function getDefaultDriver(); - - /** - * Get a driver instance. - * - * @param string $driver - * @return mixed - * - * @throws \InvalidArgumentException - */ - public function driver($driver = null) - { - $driver = $driver ?: $this->getDefaultDriver(); - - if (is_null($driver)) { - throw new InvalidArgumentException(sprintf( - 'Unable to resolve NULL driver for [%s].', static::class - )); - } - - // If the given driver has not been created before, we will create the instances - // here and cache it so we can return it next time very quickly. If there is - // already a driver created by this name, we'll just return that instance. - if (! isset($this->drivers[$driver])) { - $this->drivers[$driver] = $this->createDriver($driver); - } - - return $this->drivers[$driver]; - } - - /** - * Create a new driver instance. - * - * @param string $driver - * @return mixed - * - * @throws \InvalidArgumentException - */ - protected function createDriver($driver) - { - // First, we will determine if a custom driver creator exists for the given driver and - // if it does not we will check for a creator method for the driver. Custom creator - // callbacks allow developers to build their own "drivers" easily using Closures. - if (isset($this->customCreators[$driver])) { - return $this->callCustomCreator($driver); - } else { - $method = 'create'.Str::studly($driver).'Driver'; - - if (method_exists($this, $method)) { - return $this->$method(); - } - } - throw new InvalidArgumentException("Driver [$driver] not supported."); - } - - /** - * Call a custom driver creator. - * - * @param string $driver - * @return mixed - */ - protected function callCustomCreator($driver) - { - return $this->customCreators[$driver]($this->app); - } - - /** - * Register a custom driver creator Closure. - * - * @param string $driver - * @param \Closure $callback - * @return $this - */ - public function extend($driver, Closure $callback) - { - $this->customCreators[$driver] = $callback; - - return $this; - } - - /** - * Get all of the created "drivers". - * - * @return array - */ - public function getDrivers() - { - return $this->drivers; - } - - /** - * Dynamically call the default driver instance. - * - * @param string $method - * @param array $parameters - * @return mixed - */ - public function __call($method, $parameters) - { - return $this->driver()->$method(...$parameters); - } -} diff --git a/vendor/illuminate/support/MessageBag.php b/vendor/illuminate/support/MessageBag.php deleted file mode 100755 index b20bd77a7b..0000000000 --- a/vendor/illuminate/support/MessageBag.php +++ /dev/null @@ -1,404 +0,0 @@ - $value) { - $value = $value instanceof Arrayable ? $value->toArray() : (array) $value; - - $this->messages[$key] = array_unique($value); - } - } - - /** - * Get the keys present in the message bag. - * - * @return array - */ - public function keys() - { - return array_keys($this->messages); - } - - /** - * Add a message to the message bag. - * - * @param string $key - * @param string $message - * @return $this - */ - public function add($key, $message) - { - if ($this->isUnique($key, $message)) { - $this->messages[$key][] = $message; - } - - return $this; - } - - /** - * Determine if a key and message combination already exists. - * - * @param string $key - * @param string $message - * @return bool - */ - protected function isUnique($key, $message) - { - $messages = (array) $this->messages; - - return ! isset($messages[$key]) || ! in_array($message, $messages[$key]); - } - - /** - * Merge a new array of messages into the message bag. - * - * @param \Illuminate\Contracts\Support\MessageProvider|array $messages - * @return $this - */ - public function merge($messages) - { - if ($messages instanceof MessageProvider) { - $messages = $messages->getMessageBag()->getMessages(); - } - - $this->messages = array_merge_recursive($this->messages, $messages); - - return $this; - } - - /** - * Determine if messages exist for all of the given keys. - * - * @param array|string $key - * @return bool - */ - public function has($key) - { - if ($this->isEmpty()) { - return false; - } - - if (is_null($key)) { - return $this->any(); - } - - $keys = is_array($key) ? $key : func_get_args(); - - foreach ($keys as $key) { - if ($this->first($key) === '') { - return false; - } - } - - return true; - } - - /** - * Determine if messages exist for any of the given keys. - * - * @param array|string $keys - * @return bool - */ - public function hasAny($keys = []) - { - if ($this->isEmpty()) { - return false; - } - - $keys = is_array($keys) ? $keys : func_get_args(); - - foreach ($keys as $key) { - if ($this->has($key)) { - return true; - } - } - - return false; - } - - /** - * Get the first message from the message bag for a given key. - * - * @param string $key - * @param string $format - * @return string - */ - public function first($key = null, $format = null) - { - $messages = is_null($key) ? $this->all($format) : $this->get($key, $format); - - $firstMessage = Arr::first($messages, null, ''); - - return is_array($firstMessage) ? Arr::first($firstMessage) : $firstMessage; - } - - /** - * Get all of the messages from the message bag for a given key. - * - * @param string $key - * @param string $format - * @return array - */ - public function get($key, $format = null) - { - // If the message exists in the message bag, we will transform it and return - // the message. Otherwise, we will check if the key is implicit & collect - // all the messages that match the given key and output it as an array. - if (array_key_exists($key, $this->messages)) { - return $this->transform( - $this->messages[$key], $this->checkFormat($format), $key - ); - } - - if (Str::contains($key, '*')) { - return $this->getMessagesForWildcardKey($key, $format); - } - - return []; - } - - /** - * Get the messages for a wildcard key. - * - * @param string $key - * @param string|null $format - * @return array - */ - protected function getMessagesForWildcardKey($key, $format) - { - return collect($this->messages) - ->filter(function ($messages, $messageKey) use ($key) { - return Str::is($key, $messageKey); - }) - ->map(function ($messages, $messageKey) use ($format) { - return $this->transform( - $messages, $this->checkFormat($format), $messageKey - ); - })->all(); - } - - /** - * Get all of the messages for every key in the message bag. - * - * @param string $format - * @return array - */ - public function all($format = null) - { - $format = $this->checkFormat($format); - - $all = []; - - foreach ($this->messages as $key => $messages) { - $all = array_merge($all, $this->transform($messages, $format, $key)); - } - - return $all; - } - - /** - * Get all of the unique messages for every key in the message bag. - * - * @param string $format - * @return array - */ - public function unique($format = null) - { - return array_unique($this->all($format)); - } - - /** - * Format an array of messages. - * - * @param array $messages - * @param string $format - * @param string $messageKey - * @return array - */ - protected function transform($messages, $format, $messageKey) - { - return collect((array) $messages) - ->map(function ($message) use ($format, $messageKey) { - // We will simply spin through the given messages and transform each one - // replacing the :message place holder with the real message allowing - // the messages to be easily formatted to each developer's desires. - return str_replace([':message', ':key'], [$message, $messageKey], $format); - })->all(); - } - - /** - * Get the appropriate format based on the given format. - * - * @param string $format - * @return string - */ - protected function checkFormat($format) - { - return $format ?: $this->format; - } - - /** - * Get the raw messages in the message bag. - * - * @return array - */ - public function messages() - { - return $this->messages; - } - - /** - * Get the raw messages in the message bag. - * - * @return array - */ - public function getMessages() - { - return $this->messages(); - } - - /** - * Get the messages for the instance. - * - * @return \Illuminate\Support\MessageBag - */ - public function getMessageBag() - { - return $this; - } - - /** - * Get the default message format. - * - * @return string - */ - public function getFormat() - { - return $this->format; - } - - /** - * Set the default message format. - * - * @param string $format - * @return \Illuminate\Support\MessageBag - */ - public function setFormat($format = ':message') - { - $this->format = $format; - - return $this; - } - - /** - * Determine if the message bag has any messages. - * - * @return bool - */ - public function isEmpty() - { - return ! $this->any(); - } - - /** - * Determine if the message bag has any messages. - * - * @return bool - */ - public function isNotEmpty() - { - return $this->any(); - } - - /** - * Determine if the message bag has any messages. - * - * @return bool - */ - public function any() - { - return $this->count() > 0; - } - - /** - * Get the number of messages in the message bag. - * - * @return int - */ - public function count() - { - return count($this->messages, COUNT_RECURSIVE) - count($this->messages); - } - - /** - * Get the instance as an array. - * - * @return array - */ - public function toArray() - { - return $this->getMessages(); - } - - /** - * Convert the object into something JSON serializable. - * - * @return array - */ - public function jsonSerialize() - { - return $this->toArray(); - } - - /** - * Convert the object to its JSON representation. - * - * @param int $options - * @return string - */ - public function toJson($options = 0) - { - return json_encode($this->jsonSerialize(), $options); - } - - /** - * Convert the message bag to its string representation. - * - * @return string - */ - public function __toString() - { - return $this->toJson(); - } -} diff --git a/vendor/illuminate/support/NamespacedItemResolver.php b/vendor/illuminate/support/NamespacedItemResolver.php deleted file mode 100755 index cc389578c1..0000000000 --- a/vendor/illuminate/support/NamespacedItemResolver.php +++ /dev/null @@ -1,102 +0,0 @@ -parsed[$key])) { - return $this->parsed[$key]; - } - - // If the key does not contain a double colon, it means the key is not in a - // namespace, and is just a regular configuration item. Namespaces are a - // tool for organizing configuration items for things such as modules. - if (strpos($key, '::') === false) { - $segments = explode('.', $key); - - $parsed = $this->parseBasicSegments($segments); - } else { - $parsed = $this->parseNamespacedSegments($key); - } - - // Once we have the parsed array of this key's elements, such as its groups - // and namespace, we will cache each array inside a simple list that has - // the key and the parsed array for quick look-ups for later requests. - return $this->parsed[$key] = $parsed; - } - - /** - * Parse an array of basic segments. - * - * @param array $segments - * @return array - */ - protected function parseBasicSegments(array $segments) - { - // The first segment in a basic array will always be the group, so we can go - // ahead and grab that segment. If there is only one total segment we are - // just pulling an entire group out of the array and not a single item. - $group = $segments[0]; - - // If there is more than one segment in this group, it means we are pulling - // a specific item out of a group and will need to return this item name - // as well as the group so we know which item to pull from the arrays. - $item = count($segments) === 1 - ? null - : implode('.', array_slice($segments, 1)); - - return [null, $group, $item]; - } - - /** - * Parse an array of namespaced segments. - * - * @param string $key - * @return array - */ - protected function parseNamespacedSegments($key) - { - [$namespace, $item] = explode('::', $key); - - // First we'll just explode the first segment to get the namespace and group - // since the item should be in the remaining segments. Once we have these - // two pieces of data we can proceed with parsing out the item's value. - $itemSegments = explode('.', $item); - - $groupAndItem = array_slice( - $this->parseBasicSegments($itemSegments), 1 - ); - - return array_merge([$namespace], $groupAndItem); - } - - /** - * Set the parsed value of a key. - * - * @param string $key - * @param array $parsed - * @return void - */ - public function setParsedKey($key, $parsed) - { - $this->parsed[$key] = $parsed; - } -} diff --git a/vendor/illuminate/support/Optional.php b/vendor/illuminate/support/Optional.php deleted file mode 100644 index 5e0b7d9cb0..0000000000 --- a/vendor/illuminate/support/Optional.php +++ /dev/null @@ -1,130 +0,0 @@ -value = $value; - } - - /** - * Dynamically access a property on the underlying object. - * - * @param string $key - * @return mixed - */ - public function __get($key) - { - if (is_object($this->value)) { - return $this->value->{$key} ?? null; - } - } - - /** - * Dynamically check a property exists on the underlying object. - * - * @param mixed $name - * @return bool - */ - public function __isset($name) - { - if (is_object($this->value)) { - return isset($this->value->{$name}); - } - - if (is_array($this->value) || $this->value instanceof ArrayObject) { - return isset($this->value[$name]); - } - - return false; - } - - /** - * Determine if an item exists at an offset. - * - * @param mixed $key - * @return bool - */ - public function offsetExists($key) - { - return Arr::accessible($this->value) && Arr::exists($this->value, $key); - } - - /** - * Get an item at a given offset. - * - * @param mixed $key - * @return mixed - */ - public function offsetGet($key) - { - return Arr::get($this->value, $key); - } - - /** - * Set the item at a given offset. - * - * @param mixed $key - * @param mixed $value - * @return void - */ - public function offsetSet($key, $value) - { - if (Arr::accessible($this->value)) { - $this->value[$key] = $value; - } - } - - /** - * Unset the item at a given offset. - * - * @param string $key - * @return void - */ - public function offsetUnset($key) - { - if (Arr::accessible($this->value)) { - unset($this->value[$key]); - } - } - - /** - * Dynamically pass a method to the underlying object. - * - * @param string $method - * @param array $parameters - * @return mixed - */ - public function __call($method, $parameters) - { - if (static::hasMacro($method)) { - return $this->macroCall($method, $parameters); - } - - if (is_object($this->value)) { - return $this->value->{$method}(...$parameters); - } - } -} diff --git a/vendor/illuminate/support/Pluralizer.php b/vendor/illuminate/support/Pluralizer.php deleted file mode 100755 index 01cba35676..0000000000 --- a/vendor/illuminate/support/Pluralizer.php +++ /dev/null @@ -1,121 +0,0 @@ -app = $app; - } - - /** - * Register any application services. - * - * @return void - */ - public function register() - { - // - } - - /** - * Merge the given configuration with the existing configuration. - * - * @param string $path - * @param string $key - * @return void - */ - protected function mergeConfigFrom($path, $key) - { - $config = $this->app['config']->get($key, []); - - $this->app['config']->set($key, array_merge(require $path, $config)); - } - - /** - * Load the given routes file if routes are not already cached. - * - * @param string $path - * @return void - */ - protected function loadRoutesFrom($path) - { - if (! $this->app->routesAreCached()) { - require $path; - } - } - - /** - * Register a view file namespace. - * - * @param string|array $path - * @param string $namespace - * @return void - */ - protected function loadViewsFrom($path, $namespace) - { - if (is_array($this->app->config['view']['paths'])) { - foreach ($this->app->config['view']['paths'] as $viewPath) { - if (is_dir($appPath = $viewPath.'/vendor/'.$namespace)) { - $this->app['view']->addNamespace($namespace, $appPath); - } - } - } - - $this->app['view']->addNamespace($namespace, $path); - } - - /** - * Register a translation file namespace. - * - * @param string $path - * @param string $namespace - * @return void - */ - protected function loadTranslationsFrom($path, $namespace) - { - $this->app['translator']->addNamespace($namespace, $path); - } - - /** - * Register a JSON translation file path. - * - * @param string $path - * @return void - */ - protected function loadJsonTranslationsFrom($path) - { - $this->app['translator']->addJsonPath($path); - } - - /** - * Register a database migration path. - * - * @param array|string $paths - * @return void - */ - protected function loadMigrationsFrom($paths) - { - $this->app->afterResolving('migrator', function ($migrator) use ($paths) { - foreach ((array) $paths as $path) { - $migrator->path($path); - } - }); - } - - /** - * Register paths to be published by the publish command. - * - * @param array $paths - * @param mixed $groups - * @return void - */ - protected function publishes(array $paths, $groups = null) - { - $this->ensurePublishArrayInitialized($class = static::class); - - static::$publishes[$class] = array_merge(static::$publishes[$class], $paths); - - if (! is_null($groups)) { - foreach ((array) $groups as $group) { - $this->addPublishGroup($group, $paths); - } - } - } - - /** - * Ensure the publish array for the service provider is initialized. - * - * @param string $class - * @return void - */ - protected function ensurePublishArrayInitialized($class) - { - if (! array_key_exists($class, static::$publishes)) { - static::$publishes[$class] = []; - } - } - - /** - * Add a publish group / tag to the service provider. - * - * @param string $group - * @param array $paths - * @return void - */ - protected function addPublishGroup($group, $paths) - { - if (! array_key_exists($group, static::$publishGroups)) { - static::$publishGroups[$group] = []; - } - - static::$publishGroups[$group] = array_merge( - static::$publishGroups[$group], $paths - ); - } - - /** - * Get the paths to publish. - * - * @param string $provider - * @param string $group - * @return array - */ - public static function pathsToPublish($provider = null, $group = null) - { - if (! is_null($paths = static::pathsForProviderOrGroup($provider, $group))) { - return $paths; - } - - return collect(static::$publishes)->reduce(function ($paths, $p) { - return array_merge($paths, $p); - }, []); - } - - /** - * Get the paths for the provider or group (or both). - * - * @param string|null $provider - * @param string|null $group - * @return array - */ - protected static function pathsForProviderOrGroup($provider, $group) - { - if ($provider && $group) { - return static::pathsForProviderAndGroup($provider, $group); - } elseif ($group && array_key_exists($group, static::$publishGroups)) { - return static::$publishGroups[$group]; - } elseif ($provider && array_key_exists($provider, static::$publishes)) { - return static::$publishes[$provider]; - } elseif ($group || $provider) { - return []; - } - } - - /** - * Get the paths for the provider and group. - * - * @param string $provider - * @param string $group - * @return array - */ - protected static function pathsForProviderAndGroup($provider, $group) - { - if (! empty(static::$publishes[$provider]) && ! empty(static::$publishGroups[$group])) { - return array_intersect_key(static::$publishes[$provider], static::$publishGroups[$group]); - } - - return []; - } - - /** - * Get the service providers available for publishing. - * - * @return array - */ - public static function publishableProviders() - { - return array_keys(static::$publishes); - } - - /** - * Get the groups available for publishing. - * - * @return array - */ - public static function publishableGroups() - { - return array_keys(static::$publishGroups); - } - - /** - * Register the package's custom Artisan commands. - * - * @param array|mixed $commands - * @return void - */ - public function commands($commands) - { - $commands = is_array($commands) ? $commands : func_get_args(); - - Artisan::starting(function ($artisan) use ($commands) { - $artisan->resolveCommands($commands); - }); - } - - /** - * Get the services provided by the provider. - * - * @return array - */ - public function provides() - { - return []; - } - - /** - * Get the events that trigger this service provider to register. - * - * @return array - */ - public function when() - { - return []; - } - - /** - * Determine if the provider is deferred. - * - * @return bool - */ - public function isDeferred() - { - return $this->defer || $this instanceof DeferrableProvider; - } -} diff --git a/vendor/illuminate/support/Str.php b/vendor/illuminate/support/Str.php deleted file mode 100644 index bb367a2d25..0000000000 --- a/vendor/illuminate/support/Str.php +++ /dev/null @@ -1,764 +0,0 @@ - $val) { - $value = str_replace($val, $key, $value); - } - - return preg_replace('/[^\x20-\x7E]/u', '', $value); - } - - /** - * Get the portion of a string before a given value. - * - * @param string $subject - * @param string $search - * @return string - */ - public static function before($subject, $search) - { - return $search === '' ? $subject : explode($search, $subject)[0]; - } - - /** - * Convert a value to camel case. - * - * @param string $value - * @return string - */ - public static function camel($value) - { - if (isset(static::$camelCache[$value])) { - return static::$camelCache[$value]; - } - - return static::$camelCache[$value] = lcfirst(static::studly($value)); - } - - /** - * Determine if a given string contains a given substring. - * - * @param string $haystack - * @param string|array $needles - * @return bool - */ - public static function contains($haystack, $needles) - { - foreach ((array) $needles as $needle) { - if ($needle !== '' && mb_strpos($haystack, $needle) !== false) { - return true; - } - } - - return false; - } - - /** - * Determine if a given string contains all array values. - * - * @param string $haystack - * @param array $needles - * @return bool - */ - public static function containsAll($haystack, array $needles) - { - foreach ($needles as $needle) { - if (! static::contains($haystack, $needle)) { - return false; - } - } - - return true; - } - - /** - * Determine if a given string ends with a given substring. - * - * @param string $haystack - * @param string|array $needles - * @return bool - */ - public static function endsWith($haystack, $needles) - { - foreach ((array) $needles as $needle) { - if (substr($haystack, -strlen($needle)) === (string) $needle) { - return true; - } - } - - return false; - } - - /** - * Cap a string with a single instance of a given value. - * - * @param string $value - * @param string $cap - * @return string - */ - public static function finish($value, $cap) - { - $quoted = preg_quote($cap, '/'); - - return preg_replace('/(?:'.$quoted.')+$/u', '', $value).$cap; - } - - /** - * Determine if a given string matches a given pattern. - * - * @param string|array $pattern - * @param string $value - * @return bool - */ - public static function is($pattern, $value) - { - $patterns = Arr::wrap($pattern); - - if (empty($patterns)) { - return false; - } - - foreach ($patterns as $pattern) { - // If the given value is an exact match we can of course return true right - // from the beginning. Otherwise, we will translate asterisks and do an - // actual pattern match against the two strings to see if they match. - if ($pattern == $value) { - return true; - } - - $pattern = preg_quote($pattern, '#'); - - // Asterisks are translated into zero-or-more regular expression wildcards - // to make it convenient to check if the strings starts with the given - // pattern such as "library/*", making any string check convenient. - $pattern = str_replace('\*', '.*', $pattern); - - if (preg_match('#^'.$pattern.'\z#u', $value) === 1) { - return true; - } - } - - return false; - } - - /** - * Convert a string to kebab case. - * - * @param string $value - * @return string - */ - public static function kebab($value) - { - return static::snake($value, '-'); - } - - /** - * Return the length of the given string. - * - * @param string $value - * @param string $encoding - * @return int - */ - public static function length($value, $encoding = null) - { - if ($encoding) { - return mb_strlen($value, $encoding); - } - - return mb_strlen($value); - } - - /** - * Limit the number of characters in a string. - * - * @param string $value - * @param int $limit - * @param string $end - * @return string - */ - public static function limit($value, $limit = 100, $end = '...') - { - if (mb_strwidth($value, 'UTF-8') <= $limit) { - return $value; - } - - return rtrim(mb_strimwidth($value, 0, $limit, '', 'UTF-8')).$end; - } - - /** - * Convert the given string to lower-case. - * - * @param string $value - * @return string - */ - public static function lower($value) - { - return mb_strtolower($value, 'UTF-8'); - } - - /** - * Limit the number of words in a string. - * - * @param string $value - * @param int $words - * @param string $end - * @return string - */ - public static function words($value, $words = 100, $end = '...') - { - preg_match('/^\s*+(?:\S++\s*+){1,'.$words.'}/u', $value, $matches); - - if (! isset($matches[0]) || static::length($value) === static::length($matches[0])) { - return $value; - } - - return rtrim($matches[0]).$end; - } - - /** - * Parse a Class@method style callback into class and method. - * - * @param string $callback - * @param string|null $default - * @return array - */ - public static function parseCallback($callback, $default = null) - { - return static::contains($callback, '@') ? explode('@', $callback, 2) : [$callback, $default]; - } - - /** - * Get the plural form of an English word. - * - * @param string $value - * @param int $count - * @return string - */ - public static function plural($value, $count = 2) - { - return Pluralizer::plural($value, $count); - } - - /** - * Pluralize the last word of an English, studly caps case string. - * - * @param string $value - * @param int $count - * @return string - */ - public static function pluralStudly($value, $count = 2) - { - $parts = preg_split('/(.)(?=[A-Z])/u', $value, -1, PREG_SPLIT_DELIM_CAPTURE); - - $lastWord = array_pop($parts); - - return implode('', $parts).self::plural($lastWord, $count); - } - - /** - * Generate a more truly "random" alpha-numeric string. - * - * @param int $length - * @return string - */ - public static function random($length = 16) - { - $string = ''; - - while (($len = strlen($string)) < $length) { - $size = $length - $len; - - $bytes = random_bytes($size); - - $string .= substr(str_replace(['/', '+', '='], '', base64_encode($bytes)), 0, $size); - } - - return $string; - } - - /** - * Replace a given value in the string sequentially with an array. - * - * @param string $search - * @param array $replace - * @param string $subject - * @return string - */ - public static function replaceArray($search, array $replace, $subject) - { - $segments = explode($search, $subject); - - $result = array_shift($segments); - - foreach ($segments as $segment) { - $result .= (array_shift($replace) ?? $search).$segment; - } - - return $result; - } - - /** - * Replace the first occurrence of a given value in the string. - * - * @param string $search - * @param string $replace - * @param string $subject - * @return string - */ - public static function replaceFirst($search, $replace, $subject) - { - if ($search == '') { - return $subject; - } - - $position = strpos($subject, $search); - - if ($position !== false) { - return substr_replace($subject, $replace, $position, strlen($search)); - } - - return $subject; - } - - /** - * Replace the last occurrence of a given value in the string. - * - * @param string $search - * @param string $replace - * @param string $subject - * @return string - */ - public static function replaceLast($search, $replace, $subject) - { - $position = strrpos($subject, $search); - - if ($position !== false) { - return substr_replace($subject, $replace, $position, strlen($search)); - } - - return $subject; - } - - /** - * Begin a string with a single instance of a given value. - * - * @param string $value - * @param string $prefix - * @return string - */ - public static function start($value, $prefix) - { - $quoted = preg_quote($prefix, '/'); - - return $prefix.preg_replace('/^(?:'.$quoted.')+/u', '', $value); - } - - /** - * Convert the given string to upper-case. - * - * @param string $value - * @return string - */ - public static function upper($value) - { - return mb_strtoupper($value, 'UTF-8'); - } - - /** - * Convert the given string to title case. - * - * @param string $value - * @return string - */ - public static function title($value) - { - return mb_convert_case($value, MB_CASE_TITLE, 'UTF-8'); - } - - /** - * Get the singular form of an English word. - * - * @param string $value - * @return string - */ - public static function singular($value) - { - return Pluralizer::singular($value); - } - - /** - * Generate a URL friendly "slug" from a given string. - * - * @param string $title - * @param string $separator - * @param string|null $language - * @return string - */ - public static function slug($title, $separator = '-', $language = 'en') - { - $title = $language ? static::ascii($title, $language) : $title; - - // Convert all dashes/underscores into separator - $flip = $separator === '-' ? '_' : '-'; - - $title = preg_replace('!['.preg_quote($flip).']+!u', $separator, $title); - - // Replace @ with the word 'at' - $title = str_replace('@', $separator.'at'.$separator, $title); - - // Remove all characters that are not the separator, letters, numbers, or whitespace. - $title = preg_replace('![^'.preg_quote($separator).'\pL\pN\s]+!u', '', static::lower($title)); - - // Replace all separator characters and whitespace by a single separator - $title = preg_replace('!['.preg_quote($separator).'\s]+!u', $separator, $title); - - return trim($title, $separator); - } - - /** - * Convert a string to snake case. - * - * @param string $value - * @param string $delimiter - * @return string - */ - public static function snake($value, $delimiter = '_') - { - $key = $value; - - if (isset(static::$snakeCache[$key][$delimiter])) { - return static::$snakeCache[$key][$delimiter]; - } - - if (! ctype_lower($value)) { - $value = preg_replace('/\s+/u', '', ucwords($value)); - - $value = static::lower(preg_replace('/(.)(?=[A-Z])/u', '$1'.$delimiter, $value)); - } - - return static::$snakeCache[$key][$delimiter] = $value; - } - - /** - * Determine if a given string starts with a given substring. - * - * @param string $haystack - * @param string|array $needles - * @return bool - */ - public static function startsWith($haystack, $needles) - { - foreach ((array) $needles as $needle) { - if ($needle !== '' && substr($haystack, 0, strlen($needle)) === (string) $needle) { - return true; - } - } - - return false; - } - - /** - * Convert a value to studly caps case. - * - * @param string $value - * @return string - */ - public static function studly($value) - { - $key = $value; - - if (isset(static::$studlyCache[$key])) { - return static::$studlyCache[$key]; - } - - $value = ucwords(str_replace(['-', '_'], ' ', $value)); - - return static::$studlyCache[$key] = str_replace(' ', '', $value); - } - - /** - * Returns the portion of string specified by the start and length parameters. - * - * @param string $string - * @param int $start - * @param int|null $length - * @return string - */ - public static function substr($string, $start, $length = null) - { - return mb_substr($string, $start, $length, 'UTF-8'); - } - - /** - * Make a string's first character uppercase. - * - * @param string $string - * @return string - */ - public static function ucfirst($string) - { - return static::upper(static::substr($string, 0, 1)).static::substr($string, 1); - } - - /** - * Generate a UUID (version 4). - * - * @return \Ramsey\Uuid\UuidInterface - */ - public static function uuid() - { - return Uuid::uuid4(); - } - - /** - * Generate a time-ordered UUID (version 4). - * - * @return \Ramsey\Uuid\UuidInterface - */ - public static function orderedUuid() - { - $factory = new UuidFactory; - - $factory->setRandomGenerator(new CombGenerator( - $factory->getRandomGenerator(), - $factory->getNumberConverter() - )); - - $factory->setCodec(new TimestampFirstCombCodec( - $factory->getUuidBuilder() - )); - - return $factory->uuid4(); - } - - /** - * Returns the replacements for the ascii method. - * - * Note: Adapted from Stringy\Stringy. - * - * @see https://github.com/danielstjules/Stringy/blob/3.1.0/LICENSE.txt - * - * @return array - */ - protected static function charsArray() - { - static $charsArray; - - if (isset($charsArray)) { - return $charsArray; - } - - return $charsArray = [ - '0' => ['°', '₀', '۰', '0'], - '1' => ['¹', '₁', '۱', '1'], - '2' => ['²', '₂', '۲', '2'], - '3' => ['³', '₃', '۳', '3'], - '4' => ['⁴', '₄', '۴', '٤', '4'], - '5' => ['⁵', '₅', '۵', '٥', '5'], - '6' => ['⁶', '₆', '۶', '٦', '6'], - '7' => ['⁷', '₇', '۷', '7'], - '8' => ['⁸', '₈', '۸', '8'], - '9' => ['⁹', '₉', '۹', '9'], - 'a' => ['à', 'á', 'ả', 'ã', 'ạ', 'ă', 'ắ', 'ằ', 'ẳ', 'ẵ', 'ặ', 'â', 'ấ', 'ầ', 'ẩ', 'ẫ', 'ậ', 'ā', 'ą', 'å', 'α', 'ά', 'ἀ', 'ἁ', 'ἂ', 'ἃ', 'ἄ', 'ἅ', 'ἆ', 'ἇ', 'ᾀ', 'ᾁ', 'ᾂ', 'ᾃ', 'ᾄ', 'ᾅ', 'ᾆ', 'ᾇ', 'ὰ', 'ά', 'ᾰ', 'ᾱ', 'ᾲ', 'ᾳ', 'ᾴ', 'ᾶ', 'ᾷ', 'а', 'أ', 'အ', 'ာ', 'ါ', 'ǻ', 'ǎ', 'ª', 'ა', 'अ', 'ا', 'a', 'ä'], - 'b' => ['б', 'β', 'ب', 'ဗ', 'ბ', 'b'], - 'c' => ['ç', 'ć', 'č', 'ĉ', 'ċ', 'c'], - 'd' => ['ď', 'ð', 'đ', 'ƌ', 'ȡ', 'ɖ', 'ɗ', 'ᵭ', 'ᶁ', 'ᶑ', 'д', 'δ', 'د', 'ض', 'ဍ', 'ဒ', 'დ', 'd'], - 'e' => ['é', 'è', 'ẻ', 'ẽ', 'ẹ', 'ê', 'ế', 'ề', 'ể', 'ễ', 'ệ', 'ë', 'ē', 'ę', 'ě', 'ĕ', 'ė', 'ε', 'έ', 'ἐ', 'ἑ', 'ἒ', 'ἓ', 'ἔ', 'ἕ', 'ὲ', 'έ', 'е', 'ё', 'э', 'є', 'ə', 'ဧ', 'ေ', 'ဲ', 'ე', 'ए', 'إ', 'ئ', 'e'], - 'f' => ['ф', 'φ', 'ف', 'ƒ', 'ფ', 'f'], - 'g' => ['ĝ', 'ğ', 'ġ', 'ģ', 'г', 'ґ', 'γ', 'ဂ', 'გ', 'گ', 'g'], - 'h' => ['ĥ', 'ħ', 'η', 'ή', 'ح', 'ه', 'ဟ', 'ှ', 'ჰ', 'h'], - 'i' => ['í', 'ì', 'ỉ', 'ĩ', 'ị', 'î', 'ï', 'ī', 'ĭ', 'į', 'ı', 'ι', 'ί', 'ϊ', 'ΐ', 'ἰ', 'ἱ', 'ἲ', 'ἳ', 'ἴ', 'ἵ', 'ἶ', 'ἷ', 'ὶ', 'ί', 'ῐ', 'ῑ', 'ῒ', 'ΐ', 'ῖ', 'ῗ', 'і', 'ї', 'и', 'ဣ', 'ိ', 'ီ', 'ည်', 'ǐ', 'ი', 'इ', 'ی', 'i'], - 'j' => ['ĵ', 'ј', 'Ј', 'ჯ', 'ج', 'j'], - 'k' => ['ķ', 'ĸ', 'к', 'κ', 'Ķ', 'ق', 'ك', 'က', 'კ', 'ქ', 'ک', 'k'], - 'l' => ['ł', 'ľ', 'ĺ', 'ļ', 'ŀ', 'л', 'λ', 'ل', 'လ', 'ლ', 'l'], - 'm' => ['м', 'μ', 'م', 'မ', 'მ', 'm'], - 'n' => ['ñ', 'ń', 'ň', 'ņ', 'ʼn', 'ŋ', 'ν', 'н', 'ن', 'န', 'ნ', 'n'], - 'o' => ['ó', 'ò', 'ỏ', 'õ', 'ọ', 'ô', 'ố', 'ồ', 'ổ', 'ỗ', 'ộ', 'ơ', 'ớ', 'ờ', 'ở', 'ỡ', 'ợ', 'ø', 'ō', 'ő', 'ŏ', 'ο', 'ὀ', 'ὁ', 'ὂ', 'ὃ', 'ὄ', 'ὅ', 'ὸ', 'ό', 'о', 'و', 'θ', 'ို', 'ǒ', 'ǿ', 'º', 'ო', 'ओ', 'o', 'ö'], - 'p' => ['п', 'π', 'ပ', 'პ', 'پ', 'p'], - 'q' => ['ყ', 'q'], - 'r' => ['ŕ', 'ř', 'ŗ', 'р', 'ρ', 'ر', 'რ', 'r'], - 's' => ['ś', 'š', 'ş', 'с', 'σ', 'ș', 'ς', 'س', 'ص', 'စ', 'ſ', 'ს', 's'], - 't' => ['ť', 'ţ', 'т', 'τ', 'ț', 'ت', 'ط', 'ဋ', 'တ', 'ŧ', 'თ', 'ტ', 't'], - 'u' => ['ú', 'ù', 'ủ', 'ũ', 'ụ', 'ư', 'ứ', 'ừ', 'ử', 'ữ', 'ự', 'û', 'ū', 'ů', 'ű', 'ŭ', 'ų', 'µ', 'у', 'ဉ', 'ု', 'ူ', 'ǔ', 'ǖ', 'ǘ', 'ǚ', 'ǜ', 'უ', 'उ', 'u', 'ў', 'ü'], - 'v' => ['в', 'ვ', 'ϐ', 'v'], - 'w' => ['ŵ', 'ω', 'ώ', 'ဝ', 'ွ', 'w'], - 'x' => ['χ', 'ξ', 'x'], - 'y' => ['ý', 'ỳ', 'ỷ', 'ỹ', 'ỵ', 'ÿ', 'ŷ', 'й', 'ы', 'υ', 'ϋ', 'ύ', 'ΰ', 'ي', 'ယ', 'y'], - 'z' => ['ź', 'ž', 'ż', 'з', 'ζ', 'ز', 'ဇ', 'ზ', 'z'], - 'aa' => ['ع', 'आ', 'آ'], - 'ae' => ['æ', 'ǽ'], - 'ai' => ['ऐ'], - 'ch' => ['ч', 'ჩ', 'ჭ', 'چ'], - 'dj' => ['ђ', 'đ'], - 'dz' => ['џ', 'ძ'], - 'ei' => ['ऍ'], - 'gh' => ['غ', 'ღ'], - 'ii' => ['ई'], - 'ij' => ['ij'], - 'kh' => ['х', 'خ', 'ხ'], - 'lj' => ['љ'], - 'nj' => ['њ'], - 'oe' => ['ö', 'œ', 'ؤ'], - 'oi' => ['ऑ'], - 'oii' => ['ऒ'], - 'ps' => ['ψ'], - 'sh' => ['ш', 'შ', 'ش'], - 'shch' => ['щ'], - 'ss' => ['ß'], - 'sx' => ['ŝ'], - 'th' => ['þ', 'ϑ', 'ث', 'ذ', 'ظ'], - 'ts' => ['ц', 'ც', 'წ'], - 'ue' => ['ü'], - 'uu' => ['ऊ'], - 'ya' => ['я'], - 'yu' => ['ю'], - 'zh' => ['ж', 'ჟ', 'ژ'], - '(c)' => ['©'], - 'A' => ['Á', 'À', 'Ả', 'Ã', 'Ạ', 'Ă', 'Ắ', 'Ằ', 'Ẳ', 'Ẵ', 'Ặ', 'Â', 'Ấ', 'Ầ', 'Ẩ', 'Ẫ', 'Ậ', 'Å', 'Ā', 'Ą', 'Α', 'Ά', 'Ἀ', 'Ἁ', 'Ἂ', 'Ἃ', 'Ἄ', 'Ἅ', 'Ἆ', 'Ἇ', 'ᾈ', 'ᾉ', 'ᾊ', 'ᾋ', 'ᾌ', 'ᾍ', 'ᾎ', 'ᾏ', 'Ᾰ', 'Ᾱ', 'Ὰ', 'Ά', 'ᾼ', 'А', 'Ǻ', 'Ǎ', 'A', 'Ä'], - 'B' => ['Б', 'Β', 'ब', 'B'], - 'C' => ['Ç', 'Ć', 'Č', 'Ĉ', 'Ċ', 'C'], - 'D' => ['Ď', 'Ð', 'Đ', 'Ɖ', 'Ɗ', 'Ƌ', 'ᴅ', 'ᴆ', 'Д', 'Δ', 'D'], - 'E' => ['É', 'È', 'Ẻ', 'Ẽ', 'Ẹ', 'Ê', 'Ế', 'Ề', 'Ể', 'Ễ', 'Ệ', 'Ë', 'Ē', 'Ę', 'Ě', 'Ĕ', 'Ė', 'Ε', 'Έ', 'Ἐ', 'Ἑ', 'Ἒ', 'Ἓ', 'Ἔ', 'Ἕ', 'Έ', 'Ὲ', 'Е', 'Ё', 'Э', 'Є', 'Ə', 'E'], - 'F' => ['Ф', 'Φ', 'F'], - 'G' => ['Ğ', 'Ġ', 'Ģ', 'Г', 'Ґ', 'Γ', 'G'], - 'H' => ['Η', 'Ή', 'Ħ', 'H'], - 'I' => ['Í', 'Ì', 'Ỉ', 'Ĩ', 'Ị', 'Î', 'Ï', 'Ī', 'Ĭ', 'Į', 'İ', 'Ι', 'Ί', 'Ϊ', 'Ἰ', 'Ἱ', 'Ἳ', 'Ἴ', 'Ἵ', 'Ἶ', 'Ἷ', 'Ῐ', 'Ῑ', 'Ὶ', 'Ί', 'И', 'І', 'Ї', 'Ǐ', 'ϒ', 'I'], - 'J' => ['J'], - 'K' => ['К', 'Κ', 'K'], - 'L' => ['Ĺ', 'Ł', 'Л', 'Λ', 'Ļ', 'Ľ', 'Ŀ', 'ल', 'L'], - 'M' => ['М', 'Μ', 'M'], - 'N' => ['Ń', 'Ñ', 'Ň', 'Ņ', 'Ŋ', 'Н', 'Ν', 'N'], - 'O' => ['Ó', 'Ò', 'Ỏ', 'Õ', 'Ọ', 'Ô', 'Ố', 'Ồ', 'Ổ', 'Ỗ', 'Ộ', 'Ơ', 'Ớ', 'Ờ', 'Ở', 'Ỡ', 'Ợ', 'Ø', 'Ō', 'Ő', 'Ŏ', 'Ο', 'Ό', 'Ὀ', 'Ὁ', 'Ὂ', 'Ὃ', 'Ὄ', 'Ὅ', 'Ὸ', 'Ό', 'О', 'Θ', 'Ө', 'Ǒ', 'Ǿ', 'O', 'Ö'], - 'P' => ['П', 'Π', 'P'], - 'Q' => ['Q'], - 'R' => ['Ř', 'Ŕ', 'Р', 'Ρ', 'Ŗ', 'R'], - 'S' => ['Ş', 'Ŝ', 'Ș', 'Š', 'Ś', 'С', 'Σ', 'S'], - 'T' => ['Ť', 'Ţ', 'Ŧ', 'Ț', 'Т', 'Τ', 'T'], - 'U' => ['Ú', 'Ù', 'Ủ', 'Ũ', 'Ụ', 'Ư', 'Ứ', 'Ừ', 'Ử', 'Ữ', 'Ự', 'Û', 'Ū', 'Ů', 'Ű', 'Ŭ', 'Ų', 'У', 'Ǔ', 'Ǖ', 'Ǘ', 'Ǚ', 'Ǜ', 'U', 'Ў', 'Ü'], - 'V' => ['В', 'V'], - 'W' => ['Ω', 'Ώ', 'Ŵ', 'W'], - 'X' => ['Χ', 'Ξ', 'X'], - 'Y' => ['Ý', 'Ỳ', 'Ỷ', 'Ỹ', 'Ỵ', 'Ÿ', 'Ῠ', 'Ῡ', 'Ὺ', 'Ύ', 'Ы', 'Й', 'Υ', 'Ϋ', 'Ŷ', 'Y'], - 'Z' => ['Ź', 'Ž', 'Ż', 'З', 'Ζ', 'Z'], - 'AE' => ['Æ', 'Ǽ'], - 'Ch' => ['Ч'], - 'Dj' => ['Ђ'], - 'Dz' => ['Џ'], - 'Gx' => ['Ĝ'], - 'Hx' => ['Ĥ'], - 'Ij' => ['IJ'], - 'Jx' => ['Ĵ'], - 'Kh' => ['Х'], - 'Lj' => ['Љ'], - 'Nj' => ['Њ'], - 'Oe' => ['Œ'], - 'Ps' => ['Ψ'], - 'Sh' => ['Ш'], - 'Shch' => ['Щ'], - 'Ss' => ['ẞ'], - 'Th' => ['Þ'], - 'Ts' => ['Ц'], - 'Ya' => ['Я'], - 'Yu' => ['Ю'], - 'Zh' => ['Ж'], - ' ' => ["\xC2\xA0", "\xE2\x80\x80", "\xE2\x80\x81", "\xE2\x80\x82", "\xE2\x80\x83", "\xE2\x80\x84", "\xE2\x80\x85", "\xE2\x80\x86", "\xE2\x80\x87", "\xE2\x80\x88", "\xE2\x80\x89", "\xE2\x80\x8A", "\xE2\x80\xAF", "\xE2\x81\x9F", "\xE3\x80\x80", "\xEF\xBE\xA0"], - ]; - } - - /** - * Returns the language specific replacements for the ascii method. - * - * Note: Adapted from Stringy\Stringy. - * - * @see https://github.com/danielstjules/Stringy/blob/3.1.0/LICENSE.txt - * - * @param string $language - * @return array|null - */ - protected static function languageSpecificCharsArray($language) - { - static $languageSpecific; - - if (! isset($languageSpecific)) { - $languageSpecific = [ - 'bg' => [ - ['х', 'Х', 'щ', 'Щ', 'ъ', 'Ъ', 'ь', 'Ь'], - ['h', 'H', 'sht', 'SHT', 'a', 'А', 'y', 'Y'], - ], - 'da' => [ - ['æ', 'ø', 'å', 'Æ', 'Ø', 'Å'], - ['ae', 'oe', 'aa', 'Ae', 'Oe', 'Aa'], - ], - 'de' => [ - ['ä', 'ö', 'ü', 'Ä', 'Ö', 'Ü'], - ['ae', 'oe', 'ue', 'AE', 'OE', 'UE'], - ], - 'ro' => [ - ['ă', 'â', 'î', 'ș', 'ț', 'Ă', 'Â', 'Î', 'Ș', 'Ț'], - ['a', 'a', 'i', 's', 't', 'A', 'A', 'I', 'S', 'T'], - ], - ]; - } - - return $languageSpecific[$language] ?? null; - } -} diff --git a/vendor/illuminate/support/Testing/Fakes/BusFake.php b/vendor/illuminate/support/Testing/Fakes/BusFake.php deleted file mode 100644 index 4cd6deb26e..0000000000 --- a/vendor/illuminate/support/Testing/Fakes/BusFake.php +++ /dev/null @@ -1,165 +0,0 @@ -assertDispatchedTimes($command, $callback); - } - - PHPUnit::assertTrue( - $this->dispatched($command, $callback)->count() > 0, - "The expected [{$command}] job was not dispatched." - ); - } - - /** - * Assert if a job was pushed a number of times. - * - * @param string $command - * @param int $times - * @return void - */ - protected function assertDispatchedTimes($command, $times = 1) - { - PHPUnit::assertTrue( - ($count = $this->dispatched($command)->count()) === $times, - "The expected [{$command}] job was pushed {$count} times instead of {$times} times." - ); - } - - /** - * Determine if a job was dispatched based on a truth-test callback. - * - * @param string $command - * @param callable|null $callback - * @return void - */ - public function assertNotDispatched($command, $callback = null) - { - PHPUnit::assertTrue( - $this->dispatched($command, $callback)->count() === 0, - "The unexpected [{$command}] job was dispatched." - ); - } - - /** - * Get all of the jobs matching a truth-test callback. - * - * @param string $command - * @param callable|null $callback - * @return \Illuminate\Support\Collection - */ - public function dispatched($command, $callback = null) - { - if (! $this->hasDispatched($command)) { - return collect(); - } - - $callback = $callback ?: function () { - return true; - }; - - return collect($this->commands[$command])->filter(function ($command) use ($callback) { - return $callback($command); - }); - } - - /** - * Determine if there are any stored commands for a given class. - * - * @param string $command - * @return bool - */ - public function hasDispatched($command) - { - return isset($this->commands[$command]) && ! empty($this->commands[$command]); - } - - /** - * Dispatch a command to its appropriate handler. - * - * @param mixed $command - * @return mixed - */ - public function dispatch($command) - { - return $this->dispatchNow($command); - } - - /** - * Dispatch a command to its appropriate handler in the current process. - * - * @param mixed $command - * @param mixed $handler - * @return mixed - */ - public function dispatchNow($command, $handler = null) - { - $this->commands[get_class($command)][] = $command; - } - - /** - * Set the pipes commands should be piped through before dispatching. - * - * @param array $pipes - * @return $this - */ - public function pipeThrough(array $pipes) - { - return $this; - } - - /** - * Determine if the given command has a handler. - * - * @param mixed $command - * @return bool - */ - public function hasCommandHandler($command) - { - return false; - } - - /** - * Retrieve the handler for a command. - * - * @param mixed $command - * @return mixed - */ - public function getCommandHandler($command) - { - return false; - } - - /** - * Map a command to a handler. - * - * @param array $map - * @return $this - */ - public function map(array $map) - { - return $this; - } -} diff --git a/vendor/illuminate/support/Testing/Fakes/EventFake.php b/vendor/illuminate/support/Testing/Fakes/EventFake.php deleted file mode 100644 index 8790fc5ee6..0000000000 --- a/vendor/illuminate/support/Testing/Fakes/EventFake.php +++ /dev/null @@ -1,259 +0,0 @@ -dispatcher = $dispatcher; - - $this->eventsToFake = Arr::wrap($eventsToFake); - } - - /** - * Assert if an event was dispatched based on a truth-test callback. - * - * @param string $event - * @param callable|int|null $callback - * @return void - */ - public function assertDispatched($event, $callback = null) - { - if (is_int($callback)) { - return $this->assertDispatchedTimes($event, $callback); - } - - PHPUnit::assertTrue( - $this->dispatched($event, $callback)->count() > 0, - "The expected [{$event}] event was not dispatched." - ); - } - - /** - * Assert if a event was dispatched a number of times. - * - * @param string $event - * @param int $times - * @return void - */ - public function assertDispatchedTimes($event, $times = 1) - { - PHPUnit::assertTrue( - ($count = $this->dispatched($event)->count()) === $times, - "The expected [{$event}] event was dispatched {$count} times instead of {$times} times." - ); - } - - /** - * Determine if an event was dispatched based on a truth-test callback. - * - * @param string $event - * @param callable|null $callback - * @return void - */ - public function assertNotDispatched($event, $callback = null) - { - PHPUnit::assertTrue( - $this->dispatched($event, $callback)->count() === 0, - "The unexpected [{$event}] event was dispatched." - ); - } - - /** - * Get all of the events matching a truth-test callback. - * - * @param string $event - * @param callable|null $callback - * @return \Illuminate\Support\Collection - */ - public function dispatched($event, $callback = null) - { - if (! $this->hasDispatched($event)) { - return collect(); - } - - $callback = $callback ?: function () { - return true; - }; - - return collect($this->events[$event])->filter(function ($arguments) use ($callback) { - return $callback(...$arguments); - }); - } - - /** - * Determine if the given event has been dispatched. - * - * @param string $event - * @return bool - */ - public function hasDispatched($event) - { - return isset($this->events[$event]) && ! empty($this->events[$event]); - } - - /** - * Register an event listener with the dispatcher. - * - * @param string|array $events - * @param mixed $listener - * @return void - */ - public function listen($events, $listener) - { - $this->dispatcher->listen($events, $listener); - } - - /** - * Determine if a given event has listeners. - * - * @param string $eventName - * @return bool - */ - public function hasListeners($eventName) - { - return $this->dispatcher->hasListeners($eventName); - } - - /** - * Register an event and payload to be dispatched later. - * - * @param string $event - * @param array $payload - * @return void - */ - public function push($event, $payload = []) - { - // - } - - /** - * Register an event subscriber with the dispatcher. - * - * @param object|string $subscriber - * @return void - */ - public function subscribe($subscriber) - { - $this->dispatcher->subscribe($subscriber); - } - - /** - * Flush a set of pushed events. - * - * @param string $event - * @return void - */ - public function flush($event) - { - // - } - - /** - * Fire an event and call the listeners. - * - * @param string|object $event - * @param mixed $payload - * @param bool $halt - * @return array|null - */ - public function dispatch($event, $payload = [], $halt = false) - { - $name = is_object($event) ? get_class($event) : (string) $event; - - if ($this->shouldFakeEvent($name, $payload)) { - $this->events[$name][] = func_get_args(); - } else { - return $this->dispatcher->dispatch($event, $payload, $halt); - } - } - - /** - * Determine if an event should be faked or actually dispatched. - * - * @param string $eventName - * @param mixed $payload - * @return bool - */ - protected function shouldFakeEvent($eventName, $payload) - { - if (empty($this->eventsToFake)) { - return true; - } - - return collect($this->eventsToFake) - ->filter(function ($event) use ($eventName, $payload) { - return $event instanceof Closure - ? $event($eventName, $payload) - : $event === $eventName; - }) - ->isNotEmpty(); - } - - /** - * Remove a set of listeners from the dispatcher. - * - * @param string $event - * @return void - */ - public function forget($event) - { - // - } - - /** - * Forget all of the queued listeners. - * - * @return void - */ - public function forgetPushed() - { - // - } - - /** - * Dispatch an event and call the listeners. - * - * @param string|object $event - * @param mixed $payload - * @return void - */ - public function until($event, $payload = []) - { - return $this->dispatch($event, $payload, true); - } -} diff --git a/vendor/illuminate/support/Testing/Fakes/MailFake.php b/vendor/illuminate/support/Testing/Fakes/MailFake.php deleted file mode 100644 index c363ae00f1..0000000000 --- a/vendor/illuminate/support/Testing/Fakes/MailFake.php +++ /dev/null @@ -1,336 +0,0 @@ -assertSentTimes($mailable, $callback); - } - - $message = "The expected [{$mailable}] mailable was not sent."; - - if (count($this->queuedMailables) > 0) { - $message .= ' Did you mean to use assertQueued() instead?'; - } - - PHPUnit::assertTrue( - $this->sent($mailable, $callback)->count() > 0, - $message - ); - } - - /** - * Assert if a mailable was sent a number of times. - * - * @param string $mailable - * @param int $times - * @return void - */ - protected function assertSentTimes($mailable, $times = 1) - { - PHPUnit::assertTrue( - ($count = $this->sent($mailable)->count()) === $times, - "The expected [{$mailable}] mailable was sent {$count} times instead of {$times} times." - ); - } - - /** - * Determine if a mailable was not sent based on a truth-test callback. - * - * @param string $mailable - * @param callable|null $callback - * @return void - */ - public function assertNotSent($mailable, $callback = null) - { - PHPUnit::assertTrue( - $this->sent($mailable, $callback)->count() === 0, - "The unexpected [{$mailable}] mailable was sent." - ); - } - - /** - * Assert that no mailables were sent. - * - * @return void - */ - public function assertNothingSent() - { - PHPUnit::assertEmpty($this->mailables, 'Mailables were sent unexpectedly.'); - } - - /** - * Assert if a mailable was queued based on a truth-test callback. - * - * @param string $mailable - * @param callable|int|null $callback - * @return void - */ - public function assertQueued($mailable, $callback = null) - { - if (is_numeric($callback)) { - return $this->assertQueuedTimes($mailable, $callback); - } - - PHPUnit::assertTrue( - $this->queued($mailable, $callback)->count() > 0, - "The expected [{$mailable}] mailable was not queued." - ); - } - - /** - * Assert if a mailable was queued a number of times. - * - * @param string $mailable - * @param int $times - * @return void - */ - protected function assertQueuedTimes($mailable, $times = 1) - { - PHPUnit::assertTrue( - ($count = $this->queued($mailable)->count()) === $times, - "The expected [{$mailable}] mailable was queued {$count} times instead of {$times} times." - ); - } - - /** - * Determine if a mailable was not queued based on a truth-test callback. - * - * @param string $mailable - * @param callable|null $callback - * @return void - */ - public function assertNotQueued($mailable, $callback = null) - { - PHPUnit::assertTrue( - $this->queued($mailable, $callback)->count() === 0, - "The unexpected [{$mailable}] mailable was queued." - ); - } - - /** - * Assert that no mailables were queued. - * - * @return void - */ - public function assertNothingQueued() - { - PHPUnit::assertEmpty($this->queuedMailables, 'Mailables were queued unexpectedly.'); - } - - /** - * Get all of the mailables matching a truth-test callback. - * - * @param string $mailable - * @param callable|null $callback - * @return \Illuminate\Support\Collection - */ - public function sent($mailable, $callback = null) - { - if (! $this->hasSent($mailable)) { - return collect(); - } - - $callback = $callback ?: function () { - return true; - }; - - return $this->mailablesOf($mailable)->filter(function ($mailable) use ($callback) { - return $callback($mailable); - }); - } - - /** - * Determine if the given mailable has been sent. - * - * @param string $mailable - * @return bool - */ - public function hasSent($mailable) - { - return $this->mailablesOf($mailable)->count() > 0; - } - - /** - * Get all of the queued mailables matching a truth-test callback. - * - * @param string $mailable - * @param callable|null $callback - * @return \Illuminate\Support\Collection - */ - public function queued($mailable, $callback = null) - { - if (! $this->hasQueued($mailable)) { - return collect(); - } - - $callback = $callback ?: function () { - return true; - }; - - return $this->queuedMailablesOf($mailable)->filter(function ($mailable) use ($callback) { - return $callback($mailable); - }); - } - - /** - * Determine if the given mailable has been queued. - * - * @param string $mailable - * @return bool - */ - public function hasQueued($mailable) - { - return $this->queuedMailablesOf($mailable)->count() > 0; - } - - /** - * Get all of the mailed mailables for a given type. - * - * @param string $type - * @return \Illuminate\Support\Collection - */ - protected function mailablesOf($type) - { - return collect($this->mailables)->filter(function ($mailable) use ($type) { - return $mailable instanceof $type; - }); - } - - /** - * Get all of the mailed mailables for a given type. - * - * @param string $type - * @return \Illuminate\Support\Collection - */ - protected function queuedMailablesOf($type) - { - return collect($this->queuedMailables)->filter(function ($mailable) use ($type) { - return $mailable instanceof $type; - }); - } - - /** - * Begin the process of mailing a mailable class instance. - * - * @param mixed $users - * @return \Illuminate\Mail\PendingMail - */ - public function to($users) - { - return (new PendingMailFake($this))->to($users); - } - - /** - * Begin the process of mailing a mailable class instance. - * - * @param mixed $users - * @return \Illuminate\Mail\PendingMail - */ - public function bcc($users) - { - return (new PendingMailFake($this))->bcc($users); - } - - /** - * Send a new message with only a raw text part. - * - * @param string $text - * @param \Closure|string $callback - * @return void - */ - public function raw($text, $callback) - { - // - } - - /** - * Send a new message using a view. - * - * @param string|array $view - * @param array $data - * @param \Closure|string $callback - * @return void - */ - public function send($view, array $data = [], $callback = null) - { - if (! $view instanceof Mailable) { - return; - } - - if ($view instanceof ShouldQueue) { - return $this->queue($view, $data); - } - - $this->mailables[] = $view; - } - - /** - * Queue a new e-mail message for sending. - * - * @param string|array $view - * @param string|null $queue - * @return mixed - */ - public function queue($view, $queue = null) - { - if (! $view instanceof Mailable) { - return; - } - - $this->queuedMailables[] = $view; - } - - /** - * Queue a new e-mail message for sending after (n) seconds. - * - * @param \DateTimeInterface|\DateInterval|int $delay - * @param string|array|\Illuminate\Contracts\Mail\Mailable $view - * @param string $queue - * @return mixed - */ - public function later($delay, $view, $queue = null) - { - $this->queue($view, $queue); - } - - /** - * Get the array of failed recipients. - * - * @return array - */ - public function failures() - { - return []; - } -} diff --git a/vendor/illuminate/support/Testing/Fakes/NotificationFake.php b/vendor/illuminate/support/Testing/Fakes/NotificationFake.php deleted file mode 100644 index 49fc548dbb..0000000000 --- a/vendor/illuminate/support/Testing/Fakes/NotificationFake.php +++ /dev/null @@ -1,245 +0,0 @@ -assertSentTo($singleNotifiable, $notification, $callback); - } - - return; - } - - if (is_numeric($callback)) { - return $this->assertSentToTimes($notifiable, $notification, $callback); - } - - PHPUnit::assertTrue( - $this->sent($notifiable, $notification, $callback)->count() > 0, - "The expected [{$notification}] notification was not sent." - ); - } - - /** - * Assert if a notification was sent a number of times. - * - * @param mixed $notifiable - * @param string $notification - * @param int $times - * @return void - */ - public function assertSentToTimes($notifiable, $notification, $times = 1) - { - PHPUnit::assertTrue( - ($count = $this->sent($notifiable, $notification)->count()) === $times, - "Expected [{$notification}] to be sent {$times} times, but was sent {$count} times." - ); - } - - /** - * Determine if a notification was sent based on a truth-test callback. - * - * @param mixed $notifiable - * @param string $notification - * @param callable|null $callback - * @return void - */ - public function assertNotSentTo($notifiable, $notification, $callback = null) - { - if (is_array($notifiable) || $notifiable instanceof Collection) { - foreach ($notifiable as $singleNotifiable) { - $this->assertNotSentTo($singleNotifiable, $notification, $callback); - } - - return; - } - - PHPUnit::assertTrue( - $this->sent($notifiable, $notification, $callback)->count() === 0, - "The unexpected [{$notification}] notification was sent." - ); - } - - /** - * Assert that no notifications were sent. - * - * @return void - */ - public function assertNothingSent() - { - PHPUnit::assertEmpty($this->notifications, 'Notifications were sent unexpectedly.'); - } - - /** - * Assert the total amount of times a notification was sent. - * - * @param int $expectedCount - * @param string $notification - * @return void - */ - public function assertTimesSent($expectedCount, $notification) - { - $actualCount = collect($this->notifications) - ->flatten(1) - ->reduce(function ($count, $sent) use ($notification) { - return $count + count($sent[$notification] ?? []); - }, 0); - - PHPUnit::assertSame( - $expectedCount, $actualCount, - "Expected [{$notification}] to be sent {$expectedCount} times, but was sent {$actualCount} times." - ); - } - - /** - * Get all of the notifications matching a truth-test callback. - * - * @param mixed $notifiable - * @param string $notification - * @param callable|null $callback - * @return \Illuminate\Support\Collection - */ - public function sent($notifiable, $notification, $callback = null) - { - if (! $this->hasSent($notifiable, $notification)) { - return collect(); - } - - $callback = $callback ?: function () { - return true; - }; - - $notifications = collect($this->notificationsFor($notifiable, $notification)); - - return $notifications->filter(function ($arguments) use ($callback) { - return $callback(...array_values($arguments)); - })->pluck('notification'); - } - - /** - * Determine if there are more notifications left to inspect. - * - * @param mixed $notifiable - * @param string $notification - * @return bool - */ - public function hasSent($notifiable, $notification) - { - return ! empty($this->notificationsFor($notifiable, $notification)); - } - - /** - * Get all of the notifications for a notifiable entity by type. - * - * @param mixed $notifiable - * @param string $notification - * @return array - */ - protected function notificationsFor($notifiable, $notification) - { - return $this->notifications[get_class($notifiable)][$notifiable->getKey()][$notification] ?? []; - } - - /** - * Send the given notification to the given notifiable entities. - * - * @param \Illuminate\Support\Collection|array|mixed $notifiables - * @param mixed $notification - * @return void - */ - public function send($notifiables, $notification) - { - return $this->sendNow($notifiables, $notification); - } - - /** - * Send the given notification immediately. - * - * @param \Illuminate\Support\Collection|array|mixed $notifiables - * @param mixed $notification - * @return void - */ - public function sendNow($notifiables, $notification) - { - if (! $notifiables instanceof Collection && ! is_array($notifiables)) { - $notifiables = [$notifiables]; - } - - foreach ($notifiables as $notifiable) { - if (! $notification->id) { - $notification->id = Str::uuid()->toString(); - } - - $this->notifications[get_class($notifiable)][$notifiable->getKey()][get_class($notification)][] = [ - 'notification' => $notification, - 'channels' => $notification->via($notifiable), - 'notifiable' => $notifiable, - 'locale' => $notification->locale ?? $this->locale ?? value(function () use ($notifiable) { - if ($notifiable instanceof HasLocalePreference) { - return $notifiable->preferredLocale(); - } - }), - ]; - } - } - - /** - * Get a channel instance by name. - * - * @param string|null $name - * @return mixed - */ - public function channel($name = null) - { - // - } - - /** - * Set the locale of notifications. - * - * @param string $locale - * @return $this - */ - public function locale($locale) - { - $this->locale = $locale; - - return $this; - } -} diff --git a/vendor/illuminate/support/Testing/Fakes/PendingMailFake.php b/vendor/illuminate/support/Testing/Fakes/PendingMailFake.php deleted file mode 100644 index 83f1d27935..0000000000 --- a/vendor/illuminate/support/Testing/Fakes/PendingMailFake.php +++ /dev/null @@ -1,53 +0,0 @@ -mailer = $mailer; - } - - /** - * Send a new mailable message instance. - * - * @param \Illuminate\Contracts\Mail\Mailable $mailable; - * @return mixed - */ - public function send(Mailable $mailable) - { - return $this->sendNow($mailable); - } - - /** - * Send a mailable message immediately. - * - * @param \Illuminate\Contracts\Mail\Mailable $mailable; - * @return mixed - */ - public function sendNow(Mailable $mailable) - { - $this->mailer->send($this->fill($mailable)); - } - - /** - * Push the given mailable onto the queue. - * - * @param \Illuminate\Contracts\Mail\Mailable $mailable; - * @return mixed - */ - public function queue(Mailable $mailable) - { - return $this->mailer->queue($this->fill($mailable)); - } -} diff --git a/vendor/illuminate/support/Testing/Fakes/QueueFake.php b/vendor/illuminate/support/Testing/Fakes/QueueFake.php deleted file mode 100644 index eb47a7d9f3..0000000000 --- a/vendor/illuminate/support/Testing/Fakes/QueueFake.php +++ /dev/null @@ -1,375 +0,0 @@ -assertPushedTimes($job, $callback); - } - - PHPUnit::assertTrue( - $this->pushed($job, $callback)->count() > 0, - "The expected [{$job}] job was not pushed." - ); - } - - /** - * Assert if a job was pushed a number of times. - * - * @param string $job - * @param int $times - * @return void - */ - protected function assertPushedTimes($job, $times = 1) - { - PHPUnit::assertTrue( - ($count = $this->pushed($job)->count()) === $times, - "The expected [{$job}] job was pushed {$count} times instead of {$times} times." - ); - } - - /** - * Assert if a job was pushed based on a truth-test callback. - * - * @param string $queue - * @param string $job - * @param callable|null $callback - * @return void - */ - public function assertPushedOn($queue, $job, $callback = null) - { - return $this->assertPushed($job, function ($job, $pushedQueue) use ($callback, $queue) { - if ($pushedQueue !== $queue) { - return false; - } - - return $callback ? $callback(...func_get_args()) : true; - }); - } - - /** - * Assert if a job was pushed with chained jobs based on a truth-test callback. - * - * @param string $job - * @param array $expectedChain - * @param callable|null $callback - * @return void - */ - public function assertPushedWithChain($job, $expectedChain = [], $callback = null) - { - PHPUnit::assertTrue( - $this->pushed($job, $callback)->isNotEmpty(), - "The expected [{$job}] job was not pushed." - ); - - PHPUnit::assertTrue( - collect($expectedChain)->isNotEmpty(), - 'The expected chain can not be empty.' - ); - - $this->isChainOfObjects($expectedChain) - ? $this->assertPushedWithChainOfObjects($job, $expectedChain, $callback) - : $this->assertPushedWithChainOfClasses($job, $expectedChain, $callback); - } - - /** - * Assert if a job was pushed with chained jobs based on a truth-test callback. - * - * @param string $job - * @param array $expectedChain - * @param callable|null $callback - * @return void - */ - protected function assertPushedWithChainOfObjects($job, $expectedChain, $callback) - { - $chain = collect($expectedChain)->map(function ($job) { - return serialize($job); - })->all(); - - PHPUnit::assertTrue( - $this->pushed($job, $callback)->filter(function ($job) use ($chain) { - return $job->chained == $chain; - })->isNotEmpty(), - 'The expected chain was not pushed.' - ); - } - - /** - * Assert if a job was pushed with chained jobs based on a truth-test callback. - * - * @param string $job - * @param array $expectedChain - * @param callable|null $callback - * @return void - */ - protected function assertPushedWithChainOfClasses($job, $expectedChain, $callback) - { - $matching = $this->pushed($job, $callback)->map->chained->map(function ($chain) { - return collect($chain)->map(function ($job) { - return get_class(unserialize($job)); - }); - })->filter(function ($chain) use ($expectedChain) { - return $chain->all() === $expectedChain; - }); - - PHPUnit::assertTrue( - $matching->isNotEmpty(), 'The expected chain was not pushed.' - ); - } - - /** - * Determine if the given chain is entirely composed of objects. - * - * @param array $chain - * @return bool - */ - protected function isChainOfObjects($chain) - { - return ! collect($chain)->contains(function ($job) { - return ! is_object($job); - }); - } - - /** - * Determine if a job was pushed based on a truth-test callback. - * - * @param string $job - * @param callable|null $callback - * @return void - */ - public function assertNotPushed($job, $callback = null) - { - PHPUnit::assertTrue( - $this->pushed($job, $callback)->count() === 0, - "The unexpected [{$job}] job was pushed." - ); - } - - /** - * Assert that no jobs were pushed. - * - * @return void - */ - public function assertNothingPushed() - { - PHPUnit::assertEmpty($this->jobs, 'Jobs were pushed unexpectedly.'); - } - - /** - * Get all of the jobs matching a truth-test callback. - * - * @param string $job - * @param callable|null $callback - * @return \Illuminate\Support\Collection - */ - public function pushed($job, $callback = null) - { - if (! $this->hasPushed($job)) { - return collect(); - } - - $callback = $callback ?: function () { - return true; - }; - - return collect($this->jobs[$job])->filter(function ($data) use ($callback) { - return $callback($data['job'], $data['queue']); - })->pluck('job'); - } - - /** - * Determine if there are any stored jobs for a given class. - * - * @param string $job - * @return bool - */ - public function hasPushed($job) - { - return isset($this->jobs[$job]) && ! empty($this->jobs[$job]); - } - - /** - * Resolve a queue connection instance. - * - * @param mixed $value - * @return \Illuminate\Contracts\Queue\Queue - */ - public function connection($value = null) - { - return $this; - } - - /** - * Get the size of the queue. - * - * @param string|null $queue - * @return int - */ - public function size($queue = null) - { - return count($this->jobs); - } - - /** - * Push a new job onto the queue. - * - * @param string $job - * @param mixed $data - * @param string|null $queue - * @return mixed - */ - public function push($job, $data = '', $queue = null) - { - $this->jobs[is_object($job) ? get_class($job) : $job][] = [ - 'job' => $job, - 'queue' => $queue, - ]; - } - - /** - * Push a raw payload onto the queue. - * - * @param string $payload - * @param string|null $queue - * @param array $options - * @return mixed - */ - public function pushRaw($payload, $queue = null, array $options = []) - { - // - } - - /** - * Push a new job onto the queue after a delay. - * - * @param \DateTimeInterface|\DateInterval|int $delay - * @param string $job - * @param mixed $data - * @param string|null $queue - * @return mixed - */ - public function later($delay, $job, $data = '', $queue = null) - { - return $this->push($job, $data, $queue); - } - - /** - * Push a new job onto the queue. - * - * @param string $queue - * @param string $job - * @param mixed $data - * @return mixed - */ - public function pushOn($queue, $job, $data = '') - { - return $this->push($job, $data, $queue); - } - - /** - * Push a new job onto the queue after a delay. - * - * @param string $queue - * @param \DateTimeInterface|\DateInterval|int $delay - * @param string $job - * @param mixed $data - * @return mixed - */ - public function laterOn($queue, $delay, $job, $data = '') - { - return $this->push($job, $data, $queue); - } - - /** - * Pop the next job off of the queue. - * - * @param string|null $queue - * @return \Illuminate\Contracts\Queue\Job|null - */ - public function pop($queue = null) - { - // - } - - /** - * Push an array of jobs onto the queue. - * - * @param array $jobs - * @param mixed $data - * @param string|null $queue - * @return mixed - */ - public function bulk($jobs, $data = '', $queue = null) - { - foreach ($jobs as $job) { - $this->push($job, $data, $queue); - } - } - - /** - * Get the jobs that have been pushed. - * - * @return array - */ - public function pushedJobs() - { - return $this->jobs; - } - - /** - * Get the connection name for the queue. - * - * @return string - */ - public function getConnectionName() - { - // - } - - /** - * Set the connection name for the queue. - * - * @param string $name - * @return $this - */ - public function setConnectionName($name) - { - return $this; - } - - /** - * Override the QueueManager to prevent circular dependency. - * - * @param string $method - * @param array $parameters - * @return mixed - */ - public function __call($method, $parameters) - { - throw new BadMethodCallException(sprintf( - 'Call to undefined method %s::%s()', static::class, $method - )); - } -} diff --git a/vendor/illuminate/support/Traits/CapsuleManagerTrait.php b/vendor/illuminate/support/Traits/CapsuleManagerTrait.php deleted file mode 100644 index 08089ef661..0000000000 --- a/vendor/illuminate/support/Traits/CapsuleManagerTrait.php +++ /dev/null @@ -1,69 +0,0 @@ -container = $container; - - if (! $this->container->bound('config')) { - $this->container->instance('config', new Fluent); - } - } - - /** - * Make this capsule instance available globally. - * - * @return void - */ - public function setAsGlobal() - { - static::$instance = $this; - } - - /** - * Get the IoC container instance. - * - * @return \Illuminate\Contracts\Container\Container - */ - public function getContainer() - { - return $this->container; - } - - /** - * Set the IoC container instance. - * - * @param \Illuminate\Contracts\Container\Container $container - * @return void - */ - public function setContainer(Container $container) - { - $this->container = $container; - } -} diff --git a/vendor/illuminate/support/Traits/ForwardsCalls.php b/vendor/illuminate/support/Traits/ForwardsCalls.php deleted file mode 100644 index 3d0f122f31..0000000000 --- a/vendor/illuminate/support/Traits/ForwardsCalls.php +++ /dev/null @@ -1,54 +0,0 @@ -{$method}(...$parameters); - } catch (Error | BadMethodCallException $e) { - $pattern = '~^Call to undefined method (?P[^:]+)::(?P[^\(]+)\(\)$~'; - - if (! preg_match($pattern, $e->getMessage(), $matches)) { - throw $e; - } - - if ($matches['class'] != get_class($object) || - $matches['method'] != $method) { - throw $e; - } - - static::throwBadMethodCallException($method); - } - } - - /** - * Throw a bad method call exception for the given method. - * - * @param string $method - * @return void - * - * @throws \BadMethodCallException - */ - protected static function throwBadMethodCallException($method) - { - throw new BadMethodCallException(sprintf( - 'Call to undefined method %s::%s()', static::class, $method - )); - } -} diff --git a/vendor/illuminate/support/Traits/Localizable.php b/vendor/illuminate/support/Traits/Localizable.php deleted file mode 100644 index b03276d277..0000000000 --- a/vendor/illuminate/support/Traits/Localizable.php +++ /dev/null @@ -1,34 +0,0 @@ -getLocale(); - - try { - $app->setLocale($locale); - - return $callback(); - } finally { - $app->setLocale($original); - } - } -} diff --git a/vendor/illuminate/support/Traits/Macroable.php b/vendor/illuminate/support/Traits/Macroable.php deleted file mode 100644 index 6b8229ca9e..0000000000 --- a/vendor/illuminate/support/Traits/Macroable.php +++ /dev/null @@ -1,115 +0,0 @@ -getMethods( - ReflectionMethod::IS_PUBLIC | ReflectionMethod::IS_PROTECTED - ); - - foreach ($methods as $method) { - if ($replace || ! static::hasMacro($method->name)) { - $method->setAccessible(true); - static::macro($method->name, $method->invoke($mixin)); - } - } - } - - /** - * Checks if macro is registered. - * - * @param string $name - * @return bool - */ - public static function hasMacro($name) - { - return isset(static::$macros[$name]); - } - - /** - * Dynamically handle calls to the class. - * - * @param string $method - * @param array $parameters - * @return mixed - * - * @throws \BadMethodCallException - */ - public static function __callStatic($method, $parameters) - { - if (! static::hasMacro($method)) { - throw new BadMethodCallException(sprintf( - 'Method %s::%s does not exist.', static::class, $method - )); - } - - if (static::$macros[$method] instanceof Closure) { - return call_user_func_array(Closure::bind(static::$macros[$method], null, static::class), $parameters); - } - - return call_user_func_array(static::$macros[$method], $parameters); - } - - /** - * Dynamically handle calls to the class. - * - * @param string $method - * @param array $parameters - * @return mixed - * - * @throws \BadMethodCallException - */ - public function __call($method, $parameters) - { - if (! static::hasMacro($method)) { - throw new BadMethodCallException(sprintf( - 'Method %s::%s does not exist.', static::class, $method - )); - } - - $macro = static::$macros[$method]; - - if ($macro instanceof Closure) { - return call_user_func_array($macro->bindTo($this, static::class), $parameters); - } - - return call_user_func_array($macro, $parameters); - } -} diff --git a/vendor/illuminate/support/Traits/Tappable.php b/vendor/illuminate/support/Traits/Tappable.php deleted file mode 100644 index e4a321cdfd..0000000000 --- a/vendor/illuminate/support/Traits/Tappable.php +++ /dev/null @@ -1,17 +0,0 @@ -bags[$key]); - } - - /** - * Get a MessageBag instance from the bags. - * - * @param string $key - * @return \Illuminate\Contracts\Support\MessageBag - */ - public function getBag($key) - { - return Arr::get($this->bags, $key) ?: new MessageBag; - } - - /** - * Get all the bags. - * - * @return array - */ - public function getBags() - { - return $this->bags; - } - - /** - * Add a new MessageBag instance to the bags. - * - * @param string $key - * @param \Illuminate\Contracts\Support\MessageBag $bag - * @return $this - */ - public function put($key, MessageBagContract $bag) - { - $this->bags[$key] = $bag; - - return $this; - } - - /** - * Determine if the default message bag has any messages. - * - * @return bool - */ - public function any() - { - return $this->count() > 0; - } - - /** - * Get the number of messages in the default bag. - * - * @return int - */ - public function count() - { - return $this->getBag('default')->count(); - } - - /** - * Dynamically call methods on the default bag. - * - * @param string $method - * @param array $parameters - * @return mixed - */ - public function __call($method, $parameters) - { - return $this->getBag('default')->$method(...$parameters); - } - - /** - * Dynamically access a view error bag. - * - * @param string $key - * @return \Illuminate\Contracts\Support\MessageBag - */ - public function __get($key) - { - return $this->getBag($key); - } - - /** - * Dynamically set a view error bag. - * - * @param string $key - * @param \Illuminate\Contracts\Support\MessageBag $value - * @return void - */ - public function __set($key, $value) - { - $this->put($key, $value); - } - - /** - * Convert the default bag to its string representation. - * - * @return string - */ - public function __toString() - { - return (string) $this->getBag('default'); - } -} diff --git a/vendor/illuminate/support/composer.json b/vendor/illuminate/support/composer.json deleted file mode 100644 index 16bd0a8dee..0000000000 --- a/vendor/illuminate/support/composer.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "name": "illuminate/support", - "description": "The Illuminate Support package.", - "license": "MIT", - "homepage": "https://laravel.com", - "support": { - "issues": "https://github.com/laravel/framework/issues", - "source": "https://github.com/laravel/framework" - }, - "authors": [ - { - "name": "Taylor Otwell", - "email": "taylor@laravel.com" - } - ], - "require": { - "php": "^7.1.3", - "ext-json": "*", - "ext-mbstring": "*", - "doctrine/inflector": "^1.1", - "illuminate/contracts": "5.8.*", - "nesbot/carbon": "^1.26.3 || ^2.0" - }, - "conflict": { - "tightenco/collect": "<5.5.33" - }, - "autoload": { - "psr-4": { - "Illuminate\\Support\\": "" - }, - "files": [ - "helpers.php" - ] - }, - "extra": { - "branch-alias": { - "dev-master": "5.8-dev" - } - }, - "suggest": { - "illuminate/filesystem": "Required to use the composer class (5.8.*).", - "moontoast/math": "Required to use ordered UUIDs (^1.1).", - "ramsey/uuid": "Required to use Str::uuid() (^3.7).", - "symfony/process": "Required to use the composer class (^4.2).", - "symfony/var-dumper": "Required to use the dd function (^4.2).", - "vlucas/phpdotenv": "Required to use the env helper (^3.3)." - }, - "config": { - "sort-packages": true - }, - "minimum-stability": "dev" -} diff --git a/vendor/illuminate/support/helpers.php b/vendor/illuminate/support/helpers.php deleted file mode 100755 index affab85a3e..0000000000 --- a/vendor/illuminate/support/helpers.php +++ /dev/null @@ -1,1265 +0,0 @@ - $value) { - if (is_numeric($key)) { - $start++; - - $array[$start] = Arr::pull($array, $key); - } - } - - return $array; - } -} - -if (! function_exists('array_add')) { - /** - * Add an element to an array using "dot" notation if it doesn't exist. - * - * @param array $array - * @param string $key - * @param mixed $value - * @return array - * - * @deprecated Arr::add() should be used directly instead. Will be removed in Laravel 5.9. - */ - function array_add($array, $key, $value) - { - return Arr::add($array, $key, $value); - } -} - -if (! function_exists('array_collapse')) { - /** - * Collapse an array of arrays into a single array. - * - * @param array $array - * @return array - * - * @deprecated Arr::collapse() should be used directly instead. Will be removed in Laravel 5.9. - */ - function array_collapse($array) - { - return Arr::collapse($array); - } -} - -if (! function_exists('array_divide')) { - /** - * Divide an array into two arrays. One with keys and the other with values. - * - * @param array $array - * @return array - * - * @deprecated Arr::divide() should be used directly instead. Will be removed in Laravel 5.9. - */ - function array_divide($array) - { - return Arr::divide($array); - } -} - -if (! function_exists('array_dot')) { - /** - * Flatten a multi-dimensional associative array with dots. - * - * @param array $array - * @param string $prepend - * @return array - * - * @deprecated Arr::dot() should be used directly instead. Will be removed in Laravel 5.9. - */ - function array_dot($array, $prepend = '') - { - return Arr::dot($array, $prepend); - } -} - -if (! function_exists('array_except')) { - /** - * Get all of the given array except for a specified array of keys. - * - * @param array $array - * @param array|string $keys - * @return array - * - * @deprecated Arr::except() should be used directly instead. Will be removed in Laravel 5.9. - */ - function array_except($array, $keys) - { - return Arr::except($array, $keys); - } -} - -if (! function_exists('array_first')) { - /** - * Return the first element in an array passing a given truth test. - * - * @param array $array - * @param callable|null $callback - * @param mixed $default - * @return mixed - * - * @deprecated Arr::first() should be used directly instead. Will be removed in Laravel 5.9. - */ - function array_first($array, callable $callback = null, $default = null) - { - return Arr::first($array, $callback, $default); - } -} - -if (! function_exists('array_flatten')) { - /** - * Flatten a multi-dimensional array into a single level. - * - * @param array $array - * @param int $depth - * @return array - * - * @deprecated Arr::flatten() should be used directly instead. Will be removed in Laravel 5.9. - */ - function array_flatten($array, $depth = INF) - { - return Arr::flatten($array, $depth); - } -} - -if (! function_exists('array_forget')) { - /** - * Remove one or many array items from a given array using "dot" notation. - * - * @param array $array - * @param array|string $keys - * @return void - * - * @deprecated Arr::forget() should be used directly instead. Will be removed in Laravel 5.9. - */ - function array_forget(&$array, $keys) - { - return Arr::forget($array, $keys); - } -} - -if (! function_exists('array_get')) { - /** - * Get an item from an array using "dot" notation. - * - * @param \ArrayAccess|array $array - * @param string $key - * @param mixed $default - * @return mixed - * - * @deprecated Arr::get() should be used directly instead. Will be removed in Laravel 5.9. - */ - function array_get($array, $key, $default = null) - { - return Arr::get($array, $key, $default); - } -} - -if (! function_exists('array_has')) { - /** - * Check if an item or items exist in an array using "dot" notation. - * - * @param \ArrayAccess|array $array - * @param string|array $keys - * @return bool - * - * @deprecated Arr::has() should be used directly instead. Will be removed in Laravel 5.9. - */ - function array_has($array, $keys) - { - return Arr::has($array, $keys); - } -} - -if (! function_exists('array_last')) { - /** - * Return the last element in an array passing a given truth test. - * - * @param array $array - * @param callable|null $callback - * @param mixed $default - * @return mixed - * - * @deprecated Arr::last() should be used directly instead. Will be removed in Laravel 5.9. - */ - function array_last($array, callable $callback = null, $default = null) - { - return Arr::last($array, $callback, $default); - } -} - -if (! function_exists('array_only')) { - /** - * Get a subset of the items from the given array. - * - * @param array $array - * @param array|string $keys - * @return array - * - * @deprecated Arr::only() should be used directly instead. Will be removed in Laravel 5.9. - */ - function array_only($array, $keys) - { - return Arr::only($array, $keys); - } -} - -if (! function_exists('array_pluck')) { - /** - * Pluck an array of values from an array. - * - * @param array $array - * @param string|array $value - * @param string|array|null $key - * @return array - * - * @deprecated Arr::pluck() should be used directly instead. Will be removed in Laravel 5.9. - */ - function array_pluck($array, $value, $key = null) - { - return Arr::pluck($array, $value, $key); - } -} - -if (! function_exists('array_prepend')) { - /** - * Push an item onto the beginning of an array. - * - * @param array $array - * @param mixed $value - * @param mixed $key - * @return array - * - * @deprecated Arr::prepend() should be used directly instead. Will be removed in Laravel 5.9. - */ - function array_prepend($array, $value, $key = null) - { - return Arr::prepend($array, $value, $key); - } -} - -if (! function_exists('array_pull')) { - /** - * Get a value from the array, and remove it. - * - * @param array $array - * @param string $key - * @param mixed $default - * @return mixed - * - * @deprecated Arr::pull() should be used directly instead. Will be removed in Laravel 5.9. - */ - function array_pull(&$array, $key, $default = null) - { - return Arr::pull($array, $key, $default); - } -} - -if (! function_exists('array_random')) { - /** - * Get a random value from an array. - * - * @param array $array - * @param int|null $num - * @return mixed - * - * @deprecated Arr::random() should be used directly instead. Will be removed in Laravel 5.9. - */ - function array_random($array, $num = null) - { - return Arr::random($array, $num); - } -} - -if (! function_exists('array_set')) { - /** - * Set an array item to a given value using "dot" notation. - * - * If no key is given to the method, the entire array will be replaced. - * - * @param array $array - * @param string $key - * @param mixed $value - * @return array - * - * @deprecated Arr::set() should be used directly instead. Will be removed in Laravel 5.9. - */ - function array_set(&$array, $key, $value) - { - return Arr::set($array, $key, $value); - } -} - -if (! function_exists('array_sort')) { - /** - * Sort the array by the given callback or attribute name. - * - * @param array $array - * @param callable|string|null $callback - * @return array - * - * @deprecated Arr::sort() should be used directly instead. Will be removed in Laravel 5.9. - */ - function array_sort($array, $callback = null) - { - return Arr::sort($array, $callback); - } -} - -if (! function_exists('array_sort_recursive')) { - /** - * Recursively sort an array by keys and values. - * - * @param array $array - * @return array - * - * @deprecated Arr::sortRecursive() should be used directly instead. Will be removed in Laravel 5.9. - */ - function array_sort_recursive($array) - { - return Arr::sortRecursive($array); - } -} - -if (! function_exists('array_where')) { - /** - * Filter the array using the given callback. - * - * @param array $array - * @param callable $callback - * @return array - * - * @deprecated Arr::where() should be used directly instead. Will be removed in Laravel 5.9. - */ - function array_where($array, callable $callback) - { - return Arr::where($array, $callback); - } -} - -if (! function_exists('array_wrap')) { - /** - * If the given value is not an array, wrap it in one. - * - * @param mixed $value - * @return array - * - * @deprecated Arr::wrap() should be used directly instead. Will be removed in Laravel 5.9. - */ - function array_wrap($value) - { - return Arr::wrap($value); - } -} - -if (! function_exists('blank')) { - /** - * Determine if the given value is "blank". - * - * @param mixed $value - * @return bool - */ - function blank($value) - { - if (is_null($value)) { - return true; - } - - if (is_string($value)) { - return trim($value) === ''; - } - - if (is_numeric($value) || is_bool($value)) { - return false; - } - - if ($value instanceof Countable) { - return count($value) === 0; - } - - return empty($value); - } -} - -if (! function_exists('camel_case')) { - /** - * Convert a value to camel case. - * - * @param string $value - * @return string - * - * @deprecated Str::camel() should be used directly instead. Will be removed in Laravel 5.9. - */ - function camel_case($value) - { - return Str::camel($value); - } -} - -if (! function_exists('class_basename')) { - /** - * Get the class "basename" of the given object / class. - * - * @param string|object $class - * @return string - */ - function class_basename($class) - { - $class = is_object($class) ? get_class($class) : $class; - - return basename(str_replace('\\', '/', $class)); - } -} - -if (! function_exists('class_uses_recursive')) { - /** - * Returns all traits used by a class, its parent classes and trait of their traits. - * - * @param object|string $class - * @return array - */ - function class_uses_recursive($class) - { - if (is_object($class)) { - $class = get_class($class); - } - - $results = []; - - foreach (array_reverse(class_parents($class)) + [$class => $class] as $class) { - $results += trait_uses_recursive($class); - } - - return array_unique($results); - } -} - -if (! function_exists('collect')) { - /** - * Create a collection from the given value. - * - * @param mixed $value - * @return \Illuminate\Support\Collection - */ - function collect($value = null) - { - return new Collection($value); - } -} - -if (! function_exists('data_fill')) { - /** - * Fill in data where it's missing. - * - * @param mixed $target - * @param string|array $key - * @param mixed $value - * @return mixed - */ - function data_fill(&$target, $key, $value) - { - return data_set($target, $key, $value, false); - } -} - -if (! function_exists('data_get')) { - /** - * Get an item from an array or object using "dot" notation. - * - * @param mixed $target - * @param string|array|int $key - * @param mixed $default - * @return mixed - */ - function data_get($target, $key, $default = null) - { - if (is_null($key)) { - return $target; - } - - $key = is_array($key) ? $key : explode('.', $key); - - while (! is_null($segment = array_shift($key))) { - if ($segment === '*') { - if ($target instanceof Collection) { - $target = $target->all(); - } elseif (! is_array($target)) { - return value($default); - } - - $result = []; - - foreach ($target as $item) { - $result[] = data_get($item, $key); - } - - return in_array('*', $key) ? Arr::collapse($result) : $result; - } - - if (Arr::accessible($target) && Arr::exists($target, $segment)) { - $target = $target[$segment]; - } elseif (is_object($target) && isset($target->{$segment})) { - $target = $target->{$segment}; - } else { - return value($default); - } - } - - return $target; - } -} - -if (! function_exists('data_set')) { - /** - * Set an item on an array or object using dot notation. - * - * @param mixed $target - * @param string|array $key - * @param mixed $value - * @param bool $overwrite - * @return mixed - */ - function data_set(&$target, $key, $value, $overwrite = true) - { - $segments = is_array($key) ? $key : explode('.', $key); - - if (($segment = array_shift($segments)) === '*') { - if (! Arr::accessible($target)) { - $target = []; - } - - if ($segments) { - foreach ($target as &$inner) { - data_set($inner, $segments, $value, $overwrite); - } - } elseif ($overwrite) { - foreach ($target as &$inner) { - $inner = $value; - } - } - } elseif (Arr::accessible($target)) { - if ($segments) { - if (! Arr::exists($target, $segment)) { - $target[$segment] = []; - } - - data_set($target[$segment], $segments, $value, $overwrite); - } elseif ($overwrite || ! Arr::exists($target, $segment)) { - $target[$segment] = $value; - } - } elseif (is_object($target)) { - if ($segments) { - if (! isset($target->{$segment})) { - $target->{$segment} = []; - } - - data_set($target->{$segment}, $segments, $value, $overwrite); - } elseif ($overwrite || ! isset($target->{$segment})) { - $target->{$segment} = $value; - } - } else { - $target = []; - - if ($segments) { - data_set($target[$segment], $segments, $value, $overwrite); - } elseif ($overwrite) { - $target[$segment] = $value; - } - } - - return $target; - } -} - -if (! function_exists('e')) { - /** - * Encode HTML special characters in a string. - * - * @param \Illuminate\Contracts\Support\Htmlable|string $value - * @param bool $doubleEncode - * @return string - */ - function e($value, $doubleEncode = true) - { - if ($value instanceof Htmlable) { - return $value->toHtml(); - } - - return htmlspecialchars($value, ENT_QUOTES, 'UTF-8', $doubleEncode); - } -} - -if (! function_exists('ends_with')) { - /** - * Determine if a given string ends with a given substring. - * - * @param string $haystack - * @param string|array $needles - * @return bool - * - * @deprecated Str::endsWith() should be used directly instead. Will be removed in Laravel 5.9. - */ - function ends_with($haystack, $needles) - { - return Str::endsWith($haystack, $needles); - } -} - -if (! function_exists('env')) { - /** - * Gets the value of an environment variable. - * - * @param string $key - * @param mixed $default - * @return mixed - */ - function env($key, $default = null) - { - static $variables; - - if ($variables === null) { - $variables = (new DotenvFactory([new EnvConstAdapter, new PutenvAdapter, new ServerConstAdapter]))->createImmutable(); - } - - return Option::fromValue($variables->get($key)) - ->map(function ($value) { - switch (strtolower($value)) { - case 'true': - case '(true)': - return true; - case 'false': - case '(false)': - return false; - case 'empty': - case '(empty)': - return ''; - case 'null': - case '(null)': - return; - } - - if (preg_match('/\A([\'"])(.*)\1\z/', $value, $matches)) { - return $matches[2]; - } - - return $value; - }) - ->getOrCall(function () use ($default) { - return value($default); - }); - } -} - -if (! function_exists('filled')) { - /** - * Determine if a value is "filled". - * - * @param mixed $value - * @return bool - */ - function filled($value) - { - return ! blank($value); - } -} - -if (! function_exists('head')) { - /** - * Get the first element of an array. Useful for method chaining. - * - * @param array $array - * @return mixed - */ - function head($array) - { - return reset($array); - } -} - -if (! function_exists('kebab_case')) { - /** - * Convert a string to kebab case. - * - * @param string $value - * @return string - * - * @deprecated Str::kebab() should be used directly instead. Will be removed in Laravel 5.9. - */ - function kebab_case($value) - { - return Str::kebab($value); - } -} - -if (! function_exists('last')) { - /** - * Get the last element from an array. - * - * @param array $array - * @return mixed - */ - function last($array) - { - return end($array); - } -} - -if (! function_exists('object_get')) { - /** - * Get an item from an object using "dot" notation. - * - * @param object $object - * @param string $key - * @param mixed $default - * @return mixed - */ - function object_get($object, $key, $default = null) - { - if (is_null($key) || trim($key) == '') { - return $object; - } - - foreach (explode('.', $key) as $segment) { - if (! is_object($object) || ! isset($object->{$segment})) { - return value($default); - } - - $object = $object->{$segment}; - } - - return $object; - } -} - -if (! function_exists('optional')) { - /** - * Provide access to optional objects. - * - * @param mixed $value - * @param callable|null $callback - * @return mixed - */ - function optional($value = null, callable $callback = null) - { - if (is_null($callback)) { - return new Optional($value); - } elseif (! is_null($value)) { - return $callback($value); - } - } -} - -if (! function_exists('preg_replace_array')) { - /** - * Replace a given pattern with each value in the array in sequentially. - * - * @param string $pattern - * @param array $replacements - * @param string $subject - * @return string - */ - function preg_replace_array($pattern, array $replacements, $subject) - { - return preg_replace_callback($pattern, function () use (&$replacements) { - foreach ($replacements as $key => $value) { - return array_shift($replacements); - } - }, $subject); - } -} - -if (! function_exists('retry')) { - /** - * Retry an operation a given number of times. - * - * @param int $times - * @param callable $callback - * @param int $sleep - * @param callable $when - * @return mixed - * - * @throws \Exception - */ - function retry($times, callable $callback, $sleep = 0, $when = null) - { - $attempts = 0; - $times--; - - beginning: - $attempts++; - - try { - return $callback($attempts); - } catch (Exception $e) { - if (! $times || ($when && ! $when($e))) { - throw $e; - } - - $times--; - - if ($sleep) { - usleep($sleep * 1000); - } - - goto beginning; - } - } -} - -if (! function_exists('snake_case')) { - /** - * Convert a string to snake case. - * - * @param string $value - * @param string $delimiter - * @return string - * - * @deprecated Str::snake() should be used directly instead. Will be removed in Laravel 5.9. - */ - function snake_case($value, $delimiter = '_') - { - return Str::snake($value, $delimiter); - } -} - -if (! function_exists('starts_with')) { - /** - * Determine if a given string starts with a given substring. - * - * @param string $haystack - * @param string|array $needles - * @return bool - * - * @deprecated Str::startsWith() should be used directly instead. Will be removed in Laravel 5.9. - */ - function starts_with($haystack, $needles) - { - return Str::startsWith($haystack, $needles); - } -} - -if (! function_exists('str_after')) { - /** - * Return the remainder of a string after a given value. - * - * @param string $subject - * @param string $search - * @return string - * - * @deprecated Str::after() should be used directly instead. Will be removed in Laravel 5.9. - */ - function str_after($subject, $search) - { - return Str::after($subject, $search); - } -} - -if (! function_exists('str_before')) { - /** - * Get the portion of a string before a given value. - * - * @param string $subject - * @param string $search - * @return string - * - * @deprecated Str::before() should be used directly instead. Will be removed in Laravel 5.9. - */ - function str_before($subject, $search) - { - return Str::before($subject, $search); - } -} - -if (! function_exists('str_contains')) { - /** - * Determine if a given string contains a given substring. - * - * @param string $haystack - * @param string|array $needles - * @return bool - * - * @deprecated Str::contains() should be used directly instead. Will be removed in Laravel 5.9. - */ - function str_contains($haystack, $needles) - { - return Str::contains($haystack, $needles); - } -} - -if (! function_exists('str_finish')) { - /** - * Cap a string with a single instance of a given value. - * - * @param string $value - * @param string $cap - * @return string - * - * @deprecated Str::finish() should be used directly instead. Will be removed in Laravel 5.9. - */ - function str_finish($value, $cap) - { - return Str::finish($value, $cap); - } -} - -if (! function_exists('str_is')) { - /** - * Determine if a given string matches a given pattern. - * - * @param string|array $pattern - * @param string $value - * @return bool - * - * @deprecated Str::is() should be used directly instead. Will be removed in Laravel 5.9. - */ - function str_is($pattern, $value) - { - return Str::is($pattern, $value); - } -} - -if (! function_exists('str_limit')) { - /** - * Limit the number of characters in a string. - * - * @param string $value - * @param int $limit - * @param string $end - * @return string - * - * @deprecated Str::limit() should be used directly instead. Will be removed in Laravel 5.9. - */ - function str_limit($value, $limit = 100, $end = '...') - { - return Str::limit($value, $limit, $end); - } -} - -if (! function_exists('str_plural')) { - /** - * Get the plural form of an English word. - * - * @param string $value - * @param int $count - * @return string - * - * @deprecated Str::plural() should be used directly instead. Will be removed in Laravel 5.9. - */ - function str_plural($value, $count = 2) - { - return Str::plural($value, $count); - } -} - -if (! function_exists('str_random')) { - /** - * Generate a more truly "random" alpha-numeric string. - * - * @param int $length - * @return string - * - * @throws \RuntimeException - * - * @deprecated Str::random() should be used directly instead. Will be removed in Laravel 5.9. - */ - function str_random($length = 16) - { - return Str::random($length); - } -} - -if (! function_exists('str_replace_array')) { - /** - * Replace a given value in the string sequentially with an array. - * - * @param string $search - * @param array $replace - * @param string $subject - * @return string - * - * @deprecated Str::replaceArray() should be used directly instead. Will be removed in Laravel 5.9. - */ - function str_replace_array($search, array $replace, $subject) - { - return Str::replaceArray($search, $replace, $subject); - } -} - -if (! function_exists('str_replace_first')) { - /** - * Replace the first occurrence of a given value in the string. - * - * @param string $search - * @param string $replace - * @param string $subject - * @return string - * - * @deprecated Str::replaceFirst() should be used directly instead. Will be removed in Laravel 5.9. - */ - function str_replace_first($search, $replace, $subject) - { - return Str::replaceFirst($search, $replace, $subject); - } -} - -if (! function_exists('str_replace_last')) { - /** - * Replace the last occurrence of a given value in the string. - * - * @param string $search - * @param string $replace - * @param string $subject - * @return string - * - * @deprecated Str::replaceLast() should be used directly instead. Will be removed in Laravel 5.9. - */ - function str_replace_last($search, $replace, $subject) - { - return Str::replaceLast($search, $replace, $subject); - } -} - -if (! function_exists('str_singular')) { - /** - * Get the singular form of an English word. - * - * @param string $value - * @return string - * - * @deprecated Str::singular() should be used directly instead. Will be removed in Laravel 5.9. - */ - function str_singular($value) - { - return Str::singular($value); - } -} - -if (! function_exists('str_slug')) { - /** - * Generate a URL friendly "slug" from a given string. - * - * @param string $title - * @param string $separator - * @param string $language - * @return string - * - * @deprecated Str::slug() should be used directly instead. Will be removed in Laravel 5.9. - */ - function str_slug($title, $separator = '-', $language = 'en') - { - return Str::slug($title, $separator, $language); - } -} - -if (! function_exists('str_start')) { - /** - * Begin a string with a single instance of a given value. - * - * @param string $value - * @param string $prefix - * @return string - * - * @deprecated Str::start() should be used directly instead. Will be removed in Laravel 5.9. - */ - function str_start($value, $prefix) - { - return Str::start($value, $prefix); - } -} - -if (! function_exists('studly_case')) { - /** - * Convert a value to studly caps case. - * - * @param string $value - * @return string - * - * @deprecated Str::studly() should be used directly instead. Will be removed in Laravel 5.9. - */ - function studly_case($value) - { - return Str::studly($value); - } -} - -if (! function_exists('tap')) { - /** - * Call the given Closure with the given value then return the value. - * - * @param mixed $value - * @param callable|null $callback - * @return mixed - */ - function tap($value, $callback = null) - { - if (is_null($callback)) { - return new HigherOrderTapProxy($value); - } - - $callback($value); - - return $value; - } -} - -if (! function_exists('throw_if')) { - /** - * Throw the given exception if the given condition is true. - * - * @param mixed $condition - * @param \Throwable|string $exception - * @param array ...$parameters - * @return mixed - * - * @throws \Throwable - */ - function throw_if($condition, $exception, ...$parameters) - { - if ($condition) { - throw (is_string($exception) ? new $exception(...$parameters) : $exception); - } - - return $condition; - } -} - -if (! function_exists('throw_unless')) { - /** - * Throw the given exception unless the given condition is true. - * - * @param mixed $condition - * @param \Throwable|string $exception - * @param array ...$parameters - * @return mixed - * @throws \Throwable - */ - function throw_unless($condition, $exception, ...$parameters) - { - if (! $condition) { - throw (is_string($exception) ? new $exception(...$parameters) : $exception); - } - - return $condition; - } -} - -if (! function_exists('title_case')) { - /** - * Convert a value to title case. - * - * @param string $value - * @return string - * - * @deprecated Str::title() should be used directly instead. Will be removed in Laravel 5.9. - */ - function title_case($value) - { - return Str::title($value); - } -} - -if (! function_exists('trait_uses_recursive')) { - /** - * Returns all traits used by a trait and its traits. - * - * @param string $trait - * @return array - */ - function trait_uses_recursive($trait) - { - $traits = class_uses($trait); - - foreach ($traits as $trait) { - $traits += trait_uses_recursive($trait); - } - - return $traits; - } -} - -if (! function_exists('transform')) { - /** - * Transform the given value if it is present. - * - * @param mixed $value - * @param callable $callback - * @param mixed $default - * @return mixed|null - */ - function transform($value, callable $callback, $default = null) - { - if (filled($value)) { - return $callback($value); - } - - if (is_callable($default)) { - return $default($value); - } - - return $default; - } -} - -if (! function_exists('value')) { - /** - * Return the default value of the given value. - * - * @param mixed $value - * @return mixed - */ - function value($value) - { - return $value instanceof Closure ? $value() : $value; - } -} - -if (! function_exists('windows_os')) { - /** - * Determine whether the current environment is Windows based. - * - * @return bool - */ - function windows_os() - { - return strtolower(substr(PHP_OS, 0, 3)) === 'win'; - } -} - -if (! function_exists('with')) { - /** - * Return the given value, optionally passed through the given callback. - * - * @param mixed $value - * @param callable|null $callback - * @return mixed - */ - function with($value, callable $callback = null) - { - return is_null($callback) ? $value : $callback($value); - } -} diff --git a/vendor/michelf/php-markdown/.gitignore b/vendor/michelf/php-markdown/.gitignore new file mode 100644 index 0000000000..5bd6475b79 --- /dev/null +++ b/vendor/michelf/php-markdown/.gitignore @@ -0,0 +1,3 @@ +*~ +/composer.lock +/vendor/ diff --git a/vendor/michelf/php-markdown/License.md b/vendor/michelf/php-markdown/License.md new file mode 100644 index 0000000000..b3df08f994 --- /dev/null +++ b/vendor/michelf/php-markdown/License.md @@ -0,0 +1,36 @@ +PHP Markdown Lib +Copyright (c) 2004-2018 Michel Fortin + +All rights reserved. + +Based on Markdown +Copyright (c) 2003-2006 John Gruber + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name "Markdown" nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +This software is provided by the copyright holders and contributors "as +is" and any express or implied warranties, including, but not limited +to, the implied warranties of merchantability and fitness for a +particular purpose are disclaimed. In no event shall the copyright owner +or contributors be liable for any direct, indirect, incidental, special, +exemplary, or consequential damages (including, but not limited to, +procurement of substitute goods or services; loss of use, data, or +profits; or business interruption) however caused and on any theory of +liability, whether in contract, strict liability, or tort (including +negligence or otherwise) arising in any way out of the use of this +software, even if advised of the possibility of such damage. diff --git a/vendor/michelf/php-markdown/Michelf/Markdown.inc.php b/vendor/michelf/php-markdown/Michelf/Markdown.inc.php new file mode 100644 index 0000000000..e2bd3808e8 --- /dev/null +++ b/vendor/michelf/php-markdown/Michelf/Markdown.inc.php @@ -0,0 +1,10 @@ + + * @copyright 2004-2018 Michel Fortin + * @copyright (Original Markdown) 2004-2006 John Gruber + */ + +namespace Michelf; + +/** + * Markdown Parser Class + */ +class Markdown implements MarkdownInterface { + /** + * Define the package version + * @var string + */ + const MARKDOWNLIB_VERSION = "1.8.0"; + + /** + * Simple function interface - Initialize the parser and return the result + * of its transform method. This will work fine for derived classes too. + * + * @api + * + * @param string $text + * @return string + */ + public static function defaultTransform($text) { + // Take parser class on which this function was called. + $parser_class = \get_called_class(); + + // Try to take parser from the static parser list + static $parser_list; + $parser =& $parser_list[$parser_class]; + + // Create the parser it not already set + if (!$parser) { + $parser = new $parser_class; + } + + // Transform text using parser. + return $parser->transform($text); + } + + /** + * Configuration variables + */ + + /** + * Change to ">" for HTML output. + * @var string + */ + public $empty_element_suffix = " />"; + + /** + * The width of indentation of the output markup + * @var int + */ + public $tab_width = 4; + + /** + * Change to `true` to disallow markup or entities. + * @var boolean + */ + public $no_markup = false; + public $no_entities = false; + + + /** + * Change to `true` to enable line breaks on \n without two trailling spaces + * @var boolean + */ + public $hard_wrap = false; + + /** + * Predefined URLs and titles for reference links and images. + * @var array + */ + public $predef_urls = array(); + public $predef_titles = array(); + + /** + * Optional filter function for URLs + * @var callable + */ + public $url_filter_func = null; + + /** + * Optional header id="" generation callback function. + * @var callable + */ + public $header_id_func = null; + + /** + * Optional function for converting code block content to HTML + * @var callable + */ + public $code_block_content_func = null; + + /** + * Optional function for converting code span content to HTML. + * @var callable + */ + public $code_span_content_func = null; + + /** + * Class attribute to toggle "enhanced ordered list" behaviour + * setting this to true will allow ordered lists to start from the index + * number that is defined first. + * + * For example: + * 2. List item two + * 3. List item three + * + * Becomes: + *
    + *
  1. List item two
  2. + *
  3. List item three
  4. + *
+ * + * @var bool + */ + public $enhanced_ordered_list = false; + + /** + * Parser implementation + */ + + /** + * Regex to match balanced [brackets]. + * Needed to insert a maximum bracked depth while converting to PHP. + * @var int + */ + protected $nested_brackets_depth = 6; + protected $nested_brackets_re; + + protected $nested_url_parenthesis_depth = 4; + protected $nested_url_parenthesis_re; + + /** + * Table of hash values for escaped characters: + * @var string + */ + protected $escape_chars = '\`*_{}[]()>#+-.!'; + protected $escape_chars_re; + + /** + * Constructor function. Initialize appropriate member variables. + * @return void + */ + public function __construct() { + $this->_initDetab(); + $this->prepareItalicsAndBold(); + + $this->nested_brackets_re = + str_repeat('(?>[^\[\]]+|\[', $this->nested_brackets_depth). + str_repeat('\])*', $this->nested_brackets_depth); + + $this->nested_url_parenthesis_re = + str_repeat('(?>[^()\s]+|\(', $this->nested_url_parenthesis_depth). + str_repeat('(?>\)))*', $this->nested_url_parenthesis_depth); + + $this->escape_chars_re = '['.preg_quote($this->escape_chars).']'; + + // Sort document, block, and span gamut in ascendent priority order. + asort($this->document_gamut); + asort($this->block_gamut); + asort($this->span_gamut); + } + + + /** + * Internal hashes used during transformation. + * @var array + */ + protected $urls = array(); + protected $titles = array(); + protected $html_hashes = array(); + + /** + * Status flag to avoid invalid nesting. + * @var boolean + */ + protected $in_anchor = false; + + /** + * Status flag to avoid invalid nesting. + * @var boolean + */ + protected $in_emphasis_processing = false; + + /** + * Called before the transformation process starts to setup parser states. + * @return void + */ + protected function setup() { + // Clear global hashes. + $this->urls = $this->predef_urls; + $this->titles = $this->predef_titles; + $this->html_hashes = array(); + $this->in_anchor = false; + $this->in_emphasis_processing = false; + } + + /** + * Called after the transformation process to clear any variable which may + * be taking up memory unnecessarly. + * @return void + */ + protected function teardown() { + $this->urls = array(); + $this->titles = array(); + $this->html_hashes = array(); + } + + /** + * Main function. Performs some preprocessing on the input text and pass + * it through the document gamut. + * + * @api + * + * @param string $text + * @return string + */ + public function transform($text) { + $this->setup(); + + # Remove UTF-8 BOM and marker character in input, if present. + $text = preg_replace('{^\xEF\xBB\xBF|\x1A}', '', $text); + + # Standardize line endings: + # DOS to Unix and Mac to Unix + $text = preg_replace('{\r\n?}', "\n", $text); + + # Make sure $text ends with a couple of newlines: + $text .= "\n\n"; + + # Convert all tabs to spaces. + $text = $this->detab($text); + + # Turn block-level HTML blocks into hash entries + $text = $this->hashHTMLBlocks($text); + + # Strip any lines consisting only of spaces and tabs. + # This makes subsequent regexen easier to write, because we can + # match consecutive blank lines with /\n+/ instead of something + # contorted like /[ ]*\n+/ . + $text = preg_replace('/^[ ]+$/m', '', $text); + + # Run document gamut methods. + foreach ($this->document_gamut as $method => $priority) { + $text = $this->$method($text); + } + + $this->teardown(); + + return $text . "\n"; + } + + /** + * Define the document gamut + * @var array + */ + protected $document_gamut = array( + // Strip link definitions, store in hashes. + "stripLinkDefinitions" => 20, + "runBasicBlockGamut" => 30, + ); + + /** + * Strips link definitions from text, stores the URLs and titles in + * hash references + * @param string $text + * @return string + */ + protected function stripLinkDefinitions($text) { + + $less_than_tab = $this->tab_width - 1; + + // Link defs are in the form: ^[id]: url "optional title" + $text = preg_replace_callback('{ + ^[ ]{0,'.$less_than_tab.'}\[(.+)\][ ]?: # id = $1 + [ ]* + \n? # maybe *one* newline + [ ]* + (?: + <(.+?)> # url = $2 + | + (\S+?) # url = $3 + ) + [ ]* + \n? # maybe one newline + [ ]* + (?: + (?<=\s) # lookbehind for whitespace + ["(] + (.*?) # title = $4 + [")] + [ ]* + )? # title is optional + (?:\n+|\Z) + }xm', + array($this, '_stripLinkDefinitions_callback'), + $text + ); + return $text; + } + + /** + * The callback to strip link definitions + * @param array $matches + * @return string + */ + protected function _stripLinkDefinitions_callback($matches) { + $link_id = strtolower($matches[1]); + $url = $matches[2] == '' ? $matches[3] : $matches[2]; + $this->urls[$link_id] = $url; + $this->titles[$link_id] =& $matches[4]; + return ''; // String that will replace the block + } + + /** + * Hashify HTML blocks + * @param string $text + * @return string + */ + protected function hashHTMLBlocks($text) { + if ($this->no_markup) { + return $text; + } + + $less_than_tab = $this->tab_width - 1; + + /** + * Hashify HTML blocks: + * + * We only want to do this for block-level HTML tags, such as headers, + * lists, and tables. That's because we still want to wrap

s around + * "paragraphs" that are wrapped in non-block-level tags, such as + * anchors, phrase emphasis, and spans. The list of tags we're looking + * for is hard-coded: + * + * * List "a" is made of tags which can be both inline or block-level. + * These will be treated block-level when the start tag is alone on + * its line, otherwise they're not matched here and will be taken as + * inline later. + * * List "b" is made of tags which are always block-level; + */ + $block_tags_a_re = 'ins|del'; + $block_tags_b_re = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|'. + 'script|noscript|style|form|fieldset|iframe|math|svg|'. + 'article|section|nav|aside|hgroup|header|footer|'. + 'figure'; + + // Regular expression for the content of a block tag. + $nested_tags_level = 4; + $attr = ' + (?> # optional tag attributes + \s # starts with whitespace + (?> + [^>"/]+ # text outside quotes + | + /+(?!>) # slash not followed by ">" + | + "[^"]*" # text inside double quotes (tolerate ">") + | + \'[^\']*\' # text inside single quotes (tolerate ">") + )* + )? + '; + $content = + str_repeat(' + (?> + [^<]+ # content without tag + | + <\2 # nested opening tag + '.$attr.' # attributes + (?> + /> + | + >', $nested_tags_level). // end of opening tag + '.*?'. // last level nested tag content + str_repeat(' + # closing nested tag + ) + | + <(?!/\2\s*> # other tags with a different name + ) + )*', + $nested_tags_level); + $content2 = str_replace('\2', '\3', $content); + + /** + * First, look for nested blocks, e.g.: + *

+ *
+ * tags for inner block must be indented. + *
+ *
+ * + * The outermost tags must start at the left margin for this to match, + * and the inner nested divs must be indented. + * We need to do this before the next, more liberal match, because the + * next match will start at the first `
` and stop at the + * first `
`. + */ + $text = preg_replace_callback('{(?> + (?> + (?<=\n) # Starting on its own line + | # or + \A\n? # the at beginning of the doc + ) + ( # save in $1 + + # Match from `\n` to `\n`, handling nested tags + # in between. + + [ ]{0,'.$less_than_tab.'} + <('.$block_tags_b_re.')# start tag = $2 + '.$attr.'> # attributes followed by > and \n + '.$content.' # content, support nesting + # the matching end tag + [ ]* # trailing spaces/tabs + (?=\n+|\Z) # followed by a newline or end of document + + | # Special version for tags of group a. + + [ ]{0,'.$less_than_tab.'} + <('.$block_tags_a_re.')# start tag = $3 + '.$attr.'>[ ]*\n # attributes followed by > + '.$content2.' # content, support nesting + # the matching end tag + [ ]* # trailing spaces/tabs + (?=\n+|\Z) # followed by a newline or end of document + + | # Special case just for
. It was easier to make a special + # case than to make the other regex more complicated. + + [ ]{0,'.$less_than_tab.'} + <(hr) # start tag = $2 + '.$attr.' # attributes + /?> # the matching end tag + [ ]* + (?=\n{2,}|\Z) # followed by a blank line or end of document + + | # Special case for standalone HTML comments: + + [ ]{0,'.$less_than_tab.'} + (?s: + + ) + [ ]* + (?=\n{2,}|\Z) # followed by a blank line or end of document + + | # PHP and ASP-style processor instructions ( + ) + [ ]* + (?=\n{2,}|\Z) # followed by a blank line or end of document + + ) + )}Sxmi', + array($this, '_hashHTMLBlocks_callback'), + $text + ); + + return $text; + } + + /** + * The callback for hashing HTML blocks + * @param string $matches + * @return string + */ + protected function _hashHTMLBlocks_callback($matches) { + $text = $matches[1]; + $key = $this->hashBlock($text); + return "\n\n$key\n\n"; + } + + /** + * Called whenever a tag must be hashed when a function insert an atomic + * element in the text stream. Passing $text to through this function gives + * a unique text-token which will be reverted back when calling unhash. + * + * The $boundary argument specify what character should be used to surround + * the token. By convension, "B" is used for block elements that needs not + * to be wrapped into paragraph tags at the end, ":" is used for elements + * that are word separators and "X" is used in the general case. + * + * @param string $text + * @param string $boundary + * @return string + */ + protected function hashPart($text, $boundary = 'X') { + // Swap back any tag hash found in $text so we do not have to `unhash` + // multiple times at the end. + $text = $this->unhash($text); + + // Then hash the block. + static $i = 0; + $key = "$boundary\x1A" . ++$i . $boundary; + $this->html_hashes[$key] = $text; + return $key; // String that will replace the tag. + } + + /** + * Shortcut function for hashPart with block-level boundaries. + * @param string $text + * @return string + */ + protected function hashBlock($text) { + return $this->hashPart($text, 'B'); + } + + /** + * Define the block gamut - these are all the transformations that form + * block-level tags like paragraphs, headers, and list items. + * @var array + */ + protected $block_gamut = array( + "doHeaders" => 10, + "doHorizontalRules" => 20, + "doLists" => 40, + "doCodeBlocks" => 50, + "doBlockQuotes" => 60, + ); + + /** + * Run block gamut tranformations. + * + * We need to escape raw HTML in Markdown source before doing anything + * else. This need to be done for each block, and not only at the + * begining in the Markdown function since hashed blocks can be part of + * list items and could have been indented. Indented blocks would have + * been seen as a code block in a previous pass of hashHTMLBlocks. + * + * @param string $text + * @return string + */ + protected function runBlockGamut($text) { + $text = $this->hashHTMLBlocks($text); + return $this->runBasicBlockGamut($text); + } + + /** + * Run block gamut tranformations, without hashing HTML blocks. This is + * useful when HTML blocks are known to be already hashed, like in the first + * whole-document pass. + * + * @param string $text + * @return string + */ + protected function runBasicBlockGamut($text) { + + foreach ($this->block_gamut as $method => $priority) { + $text = $this->$method($text); + } + + // Finally form paragraph and restore hashed blocks. + $text = $this->formParagraphs($text); + + return $text; + } + + /** + * Convert horizontal rules + * @param string $text + * @return string + */ + protected function doHorizontalRules($text) { + return preg_replace( + '{ + ^[ ]{0,3} # Leading space + ([-*_]) # $1: First marker + (?> # Repeated marker group + [ ]{0,2} # Zero, one, or two spaces. + \1 # Marker character + ){2,} # Group repeated at least twice + [ ]* # Tailing spaces + $ # End of line. + }mx', + "\n".$this->hashBlock("empty_element_suffix")."\n", + $text + ); + } + + /** + * These are all the transformations that occur *within* block-level + * tags like paragraphs, headers, and list items. + * @var array + */ + protected $span_gamut = array( + // Process character escapes, code spans, and inline HTML + // in one shot. + "parseSpan" => -30, + // Process anchor and image tags. Images must come first, + // because ![foo][f] looks like an anchor. + "doImages" => 10, + "doAnchors" => 20, + // Make links out of things like `` + // Must come after doAnchors, because you can use < and > + // delimiters in inline links like [this](). + "doAutoLinks" => 30, + "encodeAmpsAndAngles" => 40, + "doItalicsAndBold" => 50, + "doHardBreaks" => 60, + ); + + /** + * Run span gamut transformations + * @param string $text + * @return string + */ + protected function runSpanGamut($text) { + foreach ($this->span_gamut as $method => $priority) { + $text = $this->$method($text); + } + + return $text; + } + + /** + * Do hard breaks + * @param string $text + * @return string + */ + protected function doHardBreaks($text) { + if ($this->hard_wrap) { + return preg_replace_callback('/ *\n/', + array($this, '_doHardBreaks_callback'), $text); + } else { + return preg_replace_callback('/ {2,}\n/', + array($this, '_doHardBreaks_callback'), $text); + } + } + + /** + * Trigger part hashing for the hard break (callback method) + * @param array $matches + * @return string + */ + protected function _doHardBreaks_callback($matches) { + return $this->hashPart("empty_element_suffix\n"); + } + + /** + * Turn Markdown link shortcuts into XHTML tags. + * @param string $text + * @return string + */ + protected function doAnchors($text) { + if ($this->in_anchor) { + return $text; + } + $this->in_anchor = true; + + // First, handle reference-style links: [link text] [id] + $text = preg_replace_callback('{ + ( # wrap whole match in $1 + \[ + ('.$this->nested_brackets_re.') # link text = $2 + \] + + [ ]? # one optional space + (?:\n[ ]*)? # one optional newline followed by spaces + + \[ + (.*?) # id = $3 + \] + ) + }xs', + array($this, '_doAnchors_reference_callback'), $text); + + // Next, inline-style links: [link text](url "optional title") + $text = preg_replace_callback('{ + ( # wrap whole match in $1 + \[ + ('.$this->nested_brackets_re.') # link text = $2 + \] + \( # literal paren + [ \n]* + (?: + <(.+?)> # href = $3 + | + ('.$this->nested_url_parenthesis_re.') # href = $4 + ) + [ \n]* + ( # $5 + ([\'"]) # quote char = $6 + (.*?) # Title = $7 + \6 # matching quote + [ \n]* # ignore any spaces/tabs between closing quote and ) + )? # title is optional + \) + ) + }xs', + array($this, '_doAnchors_inline_callback'), $text); + + // Last, handle reference-style shortcuts: [link text] + // These must come last in case you've also got [link text][1] + // or [link text](/foo) + $text = preg_replace_callback('{ + ( # wrap whole match in $1 + \[ + ([^\[\]]+) # link text = $2; can\'t contain [ or ] + \] + ) + }xs', + array($this, '_doAnchors_reference_callback'), $text); + + $this->in_anchor = false; + return $text; + } + + /** + * Callback method to parse referenced anchors + * @param string $matches + * @return string + */ + protected function _doAnchors_reference_callback($matches) { + $whole_match = $matches[1]; + $link_text = $matches[2]; + $link_id =& $matches[3]; + + if ($link_id == "") { + // for shortcut links like [this][] or [this]. + $link_id = $link_text; + } + + // lower-case and turn embedded newlines into spaces + $link_id = strtolower($link_id); + $link_id = preg_replace('{[ ]?\n}', ' ', $link_id); + + if (isset($this->urls[$link_id])) { + $url = $this->urls[$link_id]; + $url = $this->encodeURLAttribute($url); + + $result = "titles[$link_id] ) ) { + $title = $this->titles[$link_id]; + $title = $this->encodeAttribute($title); + $result .= " title=\"$title\""; + } + + $link_text = $this->runSpanGamut($link_text); + $result .= ">$link_text"; + $result = $this->hashPart($result); + } else { + $result = $whole_match; + } + return $result; + } + + /** + * Callback method to parse inline anchors + * @param string $matches + * @return string + */ + protected function _doAnchors_inline_callback($matches) { + $whole_match = $matches[1]; + $link_text = $this->runSpanGamut($matches[2]); + $url = $matches[3] == '' ? $matches[4] : $matches[3]; + $title =& $matches[7]; + + // If the URL was of the form it got caught by the HTML + // tag parser and hashed. Need to reverse the process before using + // the URL. + $unhashed = $this->unhash($url); + if ($unhashed != $url) + $url = preg_replace('/^<(.*)>$/', '\1', $unhashed); + + $url = $this->encodeURLAttribute($url); + + $result = "encodeAttribute($title); + $result .= " title=\"$title\""; + } + + $link_text = $this->runSpanGamut($link_text); + $result .= ">$link_text"; + + return $this->hashPart($result); + } + + /** + * Turn Markdown image shortcuts into tags. + * @param string $text + * @return string + */ + protected function doImages($text) { + // First, handle reference-style labeled images: ![alt text][id] + $text = preg_replace_callback('{ + ( # wrap whole match in $1 + !\[ + ('.$this->nested_brackets_re.') # alt text = $2 + \] + + [ ]? # one optional space + (?:\n[ ]*)? # one optional newline followed by spaces + + \[ + (.*?) # id = $3 + \] + + ) + }xs', + array($this, '_doImages_reference_callback'), $text); + + // Next, handle inline images: ![alt text](url "optional title") + // Don't forget: encode * and _ + $text = preg_replace_callback('{ + ( # wrap whole match in $1 + !\[ + ('.$this->nested_brackets_re.') # alt text = $2 + \] + \s? # One optional whitespace character + \( # literal paren + [ \n]* + (?: + <(\S*)> # src url = $3 + | + ('.$this->nested_url_parenthesis_re.') # src url = $4 + ) + [ \n]* + ( # $5 + ([\'"]) # quote char = $6 + (.*?) # title = $7 + \6 # matching quote + [ \n]* + )? # title is optional + \) + ) + }xs', + array($this, '_doImages_inline_callback'), $text); + + return $text; + } + + /** + * Callback to parse references image tags + * @param array $matches + * @return string + */ + protected function _doImages_reference_callback($matches) { + $whole_match = $matches[1]; + $alt_text = $matches[2]; + $link_id = strtolower($matches[3]); + + if ($link_id == "") { + $link_id = strtolower($alt_text); // for shortcut links like ![this][]. + } + + $alt_text = $this->encodeAttribute($alt_text); + if (isset($this->urls[$link_id])) { + $url = $this->encodeURLAttribute($this->urls[$link_id]); + $result = "\"$alt_text\"";titles[$link_id])) { + $title = $this->titles[$link_id]; + $title = $this->encodeAttribute($title); + $result .= " title=\"$title\""; + } + $result .= $this->empty_element_suffix; + $result = $this->hashPart($result); + } else { + // If there's no such link ID, leave intact: + $result = $whole_match; + } + + return $result; + } + + /** + * Callback to parse inline image tags + * @param array $matches + * @return string + */ + protected function _doImages_inline_callback($matches) { + $whole_match = $matches[1]; + $alt_text = $matches[2]; + $url = $matches[3] == '' ? $matches[4] : $matches[3]; + $title =& $matches[7]; + + $alt_text = $this->encodeAttribute($alt_text); + $url = $this->encodeURLAttribute($url); + $result = "\"$alt_text\"";encodeAttribute($title); + $result .= " title=\"$title\""; // $title already quoted + } + $result .= $this->empty_element_suffix; + + return $this->hashPart($result); + } + + /** + * Parse Markdown heading elements to HTML + * @param string $text + * @return string + */ + protected function doHeaders($text) { + /** + * Setext-style headers: + * Header 1 + * ======== + * + * Header 2 + * -------- + */ + $text = preg_replace_callback('{ ^(.+?)[ ]*\n(=+|-+)[ ]*\n+ }mx', + array($this, '_doHeaders_callback_setext'), $text); + + /** + * atx-style headers: + * # Header 1 + * ## Header 2 + * ## Header 2 with closing hashes ## + * ... + * ###### Header 6 + */ + $text = preg_replace_callback('{ + ^(\#{1,6}) # $1 = string of #\'s + [ ]* + (.+?) # $2 = Header text + [ ]* + \#* # optional closing #\'s (not counted) + \n+ + }xm', + array($this, '_doHeaders_callback_atx'), $text); + + return $text; + } + + /** + * Setext header parsing callback + * @param array $matches + * @return string + */ + protected function _doHeaders_callback_setext($matches) { + // Terrible hack to check we haven't found an empty list item. + if ($matches[2] == '-' && preg_match('{^-(?: |$)}', $matches[1])) { + return $matches[0]; + } + + $level = $matches[2]{0} == '=' ? 1 : 2; + + // ID attribute generation + $idAtt = $this->_generateIdFromHeaderValue($matches[1]); + + $block = "".$this->runSpanGamut($matches[1]).""; + return "\n" . $this->hashBlock($block) . "\n\n"; + } + + /** + * ATX header parsing callback + * @param array $matches + * @return string + */ + protected function _doHeaders_callback_atx($matches) { + // ID attribute generation + $idAtt = $this->_generateIdFromHeaderValue($matches[2]); + + $level = strlen($matches[1]); + $block = "".$this->runSpanGamut($matches[2]).""; + return "\n" . $this->hashBlock($block) . "\n\n"; + } + + /** + * If a header_id_func property is set, we can use it to automatically + * generate an id attribute. + * + * This method returns a string in the form id="foo", or an empty string + * otherwise. + * @param string $headerValue + * @return string + */ + protected function _generateIdFromHeaderValue($headerValue) { + if (!is_callable($this->header_id_func)) { + return ""; + } + + $idValue = call_user_func($this->header_id_func, $headerValue); + if (!$idValue) { + return ""; + } + + return ' id="' . $this->encodeAttribute($idValue) . '"'; + } + + /** + * Form HTML ordered (numbered) and unordered (bulleted) lists. + * @param string $text + * @return string + */ + protected function doLists($text) { + $less_than_tab = $this->tab_width - 1; + + // Re-usable patterns to match list item bullets and number markers: + $marker_ul_re = '[*+-]'; + $marker_ol_re = '\d+[\.]'; + + $markers_relist = array( + $marker_ul_re => $marker_ol_re, + $marker_ol_re => $marker_ul_re, + ); + + foreach ($markers_relist as $marker_re => $other_marker_re) { + // Re-usable pattern to match any entirel ul or ol list: + $whole_list_re = ' + ( # $1 = whole list + ( # $2 + ([ ]{0,'.$less_than_tab.'}) # $3 = number of spaces + ('.$marker_re.') # $4 = first list item marker + [ ]+ + ) + (?s:.+?) + ( # $5 + \z + | + \n{2,} + (?=\S) + (?! # Negative lookahead for another list item marker + [ ]* + '.$marker_re.'[ ]+ + ) + | + (?= # Lookahead for another kind of list + \n + \3 # Must have the same indentation + '.$other_marker_re.'[ ]+ + ) + ) + ) + '; // mx + + // We use a different prefix before nested lists than top-level lists. + //See extended comment in _ProcessListItems(). + + if ($this->list_level) { + $text = preg_replace_callback('{ + ^ + '.$whole_list_re.' + }mx', + array($this, '_doLists_callback'), $text); + } else { + $text = preg_replace_callback('{ + (?:(?<=\n)\n|\A\n?) # Must eat the newline + '.$whole_list_re.' + }mx', + array($this, '_doLists_callback'), $text); + } + } + + return $text; + } + + /** + * List parsing callback + * @param array $matches + * @return string + */ + protected function _doLists_callback($matches) { + // Re-usable patterns to match list item bullets and number markers: + $marker_ul_re = '[*+-]'; + $marker_ol_re = '\d+[\.]'; + $marker_any_re = "(?:$marker_ul_re|$marker_ol_re)"; + $marker_ol_start_re = '[0-9]+'; + + $list = $matches[1]; + $list_type = preg_match("/$marker_ul_re/", $matches[4]) ? "ul" : "ol"; + + $marker_any_re = ( $list_type == "ul" ? $marker_ul_re : $marker_ol_re ); + + $list .= "\n"; + $result = $this->processListItems($list, $marker_any_re); + + $ol_start = 1; + if ($this->enhanced_ordered_list) { + // Get the start number for ordered list. + if ($list_type == 'ol') { + $ol_start_array = array(); + $ol_start_check = preg_match("/$marker_ol_start_re/", $matches[4], $ol_start_array); + if ($ol_start_check){ + $ol_start = $ol_start_array[0]; + } + } + } + + if ($ol_start > 1 && $list_type == 'ol'){ + $result = $this->hashBlock("<$list_type start=\"$ol_start\">\n" . $result . ""); + } else { + $result = $this->hashBlock("<$list_type>\n" . $result . ""); + } + return "\n". $result ."\n\n"; + } + + /** + * Nesting tracker for list levels + * @var integer + */ + protected $list_level = 0; + + /** + * Process the contents of a single ordered or unordered list, splitting it + * into individual list items. + * @param string $list_str + * @param string $marker_any_re + * @return string + */ + protected function processListItems($list_str, $marker_any_re) { + /** + * The $this->list_level global keeps track of when we're inside a list. + * Each time we enter a list, we increment it; when we leave a list, + * we decrement. If it's zero, we're not in a list anymore. + * + * We do this because when we're not inside a list, we want to treat + * something like this: + * + * I recommend upgrading to version + * 8. Oops, now this line is treated + * as a sub-list. + * + * As a single paragraph, despite the fact that the second line starts + * with a digit-period-space sequence. + * + * Whereas when we're inside a list (or sub-list), that line will be + * treated as the start of a sub-list. What a kludge, huh? This is + * an aspect of Markdown's syntax that's hard to parse perfectly + * without resorting to mind-reading. Perhaps the solution is to + * change the syntax rules such that sub-lists must start with a + * starting cardinal number; e.g. "1." or "a.". + */ + $this->list_level++; + + // Trim trailing blank lines: + $list_str = preg_replace("/\n{2,}\\z/", "\n", $list_str); + + $list_str = preg_replace_callback('{ + (\n)? # leading line = $1 + (^[ ]*) # leading whitespace = $2 + ('.$marker_any_re.' # list marker and space = $3 + (?:[ ]+|(?=\n)) # space only required if item is not empty + ) + ((?s:.*?)) # list item text = $4 + (?:(\n+(?=\n))|\n) # tailing blank line = $5 + (?= \n* (\z | \2 ('.$marker_any_re.') (?:[ ]+|(?=\n)))) + }xm', + array($this, '_processListItems_callback'), $list_str); + + $this->list_level--; + return $list_str; + } + + /** + * List item parsing callback + * @param array $matches + * @return string + */ + protected function _processListItems_callback($matches) { + $item = $matches[4]; + $leading_line =& $matches[1]; + $leading_space =& $matches[2]; + $marker_space = $matches[3]; + $tailing_blank_line =& $matches[5]; + + if ($leading_line || $tailing_blank_line || + preg_match('/\n{2,}/', $item)) + { + // Replace marker with the appropriate whitespace indentation + $item = $leading_space . str_repeat(' ', strlen($marker_space)) . $item; + $item = $this->runBlockGamut($this->outdent($item)."\n"); + } else { + // Recursion for sub-lists: + $item = $this->doLists($this->outdent($item)); + $item = $this->formParagraphs($item, false); + } + + return "
  • " . $item . "
  • \n"; + } + + /** + * Process Markdown `
    ` blocks.
    +	 * @param  string $text
    +	 * @return string
    +	 */
    +	protected function doCodeBlocks($text) {
    +		$text = preg_replace_callback('{
    +				(?:\n\n|\A\n?)
    +				(	            # $1 = the code block -- one or more lines, starting with a space/tab
    +				  (?>
    +					[ ]{'.$this->tab_width.'}  # Lines must start with a tab or a tab-width of spaces
    +					.*\n+
    +				  )+
    +				)
    +				((?=^[ ]{0,'.$this->tab_width.'}\S)|\Z)	# Lookahead for non-space at line-start, or end of doc
    +			}xm',
    +			array($this, '_doCodeBlocks_callback'), $text);
    +
    +		return $text;
    +	}
    +
    +	/**
    +	 * Code block parsing callback
    +	 * @param  array $matches
    +	 * @return string
    +	 */
    +	protected function _doCodeBlocks_callback($matches) {
    +		$codeblock = $matches[1];
    +
    +		$codeblock = $this->outdent($codeblock);
    +		if ($this->code_block_content_func) {
    +			$codeblock = call_user_func($this->code_block_content_func, $codeblock, "");
    +		} else {
    +			$codeblock = htmlspecialchars($codeblock, ENT_NOQUOTES);
    +		}
    +
    +		# trim leading newlines and trailing newlines
    +		$codeblock = preg_replace('/\A\n+|\n+\z/', '', $codeblock);
    +
    +		$codeblock = "
    $codeblock\n
    "; + return "\n\n" . $this->hashBlock($codeblock) . "\n\n"; + } + + /** + * Create a code span markup for $code. Called from handleSpanToken. + * @param string $code + * @return string + */ + protected function makeCodeSpan($code) { + if ($this->code_span_content_func) { + $code = call_user_func($this->code_span_content_func, $code); + } else { + $code = htmlspecialchars(trim($code), ENT_NOQUOTES); + } + return $this->hashPart("$code"); + } + + /** + * Define the emphasis operators with their regex matches + * @var array + */ + protected $em_relist = array( + '' => '(?:(? '(? '(? '(?:(? '(? '(? '(?:(? '(? '(?em_relist as $em => $em_re) { + foreach ($this->strong_relist as $strong => $strong_re) { + // Construct list of allowed token expressions. + $token_relist = array(); + if (isset($this->em_strong_relist["$em$strong"])) { + $token_relist[] = $this->em_strong_relist["$em$strong"]; + } + $token_relist[] = $em_re; + $token_relist[] = $strong_re; + + // Construct master expression from list. + $token_re = '{(' . implode('|', $token_relist) . ')}'; + $this->em_strong_prepared_relist["$em$strong"] = $token_re; + } + } + } + + /** + * Convert Markdown italics (emphasis) and bold (strong) to HTML + * @param string $text + * @return string + */ + protected function doItalicsAndBold($text) { + if ($this->in_emphasis_processing) { + return $text; // avoid reentrency + } + $this->in_emphasis_processing = true; + + $token_stack = array(''); + $text_stack = array(''); + $em = ''; + $strong = ''; + $tree_char_em = false; + + while (1) { + // Get prepared regular expression for seraching emphasis tokens + // in current context. + $token_re = $this->em_strong_prepared_relist["$em$strong"]; + + // Each loop iteration search for the next emphasis token. + // Each token is then passed to handleSpanToken. + $parts = preg_split($token_re, $text, 2, PREG_SPLIT_DELIM_CAPTURE); + $text_stack[0] .= $parts[0]; + $token =& $parts[1]; + $text =& $parts[2]; + + if (empty($token)) { + // Reached end of text span: empty stack without emitting. + // any more emphasis. + while ($token_stack[0]) { + $text_stack[1] .= array_shift($token_stack); + $text_stack[0] .= array_shift($text_stack); + } + break; + } + + $token_len = strlen($token); + if ($tree_char_em) { + // Reached closing marker while inside a three-char emphasis. + if ($token_len == 3) { + // Three-char closing marker, close em and strong. + array_shift($token_stack); + $span = array_shift($text_stack); + $span = $this->runSpanGamut($span); + $span = "$span"; + $text_stack[0] .= $this->hashPart($span); + $em = ''; + $strong = ''; + } else { + // Other closing marker: close one em or strong and + // change current token state to match the other + $token_stack[0] = str_repeat($token{0}, 3-$token_len); + $tag = $token_len == 2 ? "strong" : "em"; + $span = $text_stack[0]; + $span = $this->runSpanGamut($span); + $span = "<$tag>$span"; + $text_stack[0] = $this->hashPart($span); + $$tag = ''; // $$tag stands for $em or $strong + } + $tree_char_em = false; + } else if ($token_len == 3) { + if ($em) { + // Reached closing marker for both em and strong. + // Closing strong marker: + for ($i = 0; $i < 2; ++$i) { + $shifted_token = array_shift($token_stack); + $tag = strlen($shifted_token) == 2 ? "strong" : "em"; + $span = array_shift($text_stack); + $span = $this->runSpanGamut($span); + $span = "<$tag>$span"; + $text_stack[0] .= $this->hashPart($span); + $$tag = ''; // $$tag stands for $em or $strong + } + } else { + // Reached opening three-char emphasis marker. Push on token + // stack; will be handled by the special condition above. + $em = $token{0}; + $strong = "$em$em"; + array_unshift($token_stack, $token); + array_unshift($text_stack, ''); + $tree_char_em = true; + } + } else if ($token_len == 2) { + if ($strong) { + // Unwind any dangling emphasis marker: + if (strlen($token_stack[0]) == 1) { + $text_stack[1] .= array_shift($token_stack); + $text_stack[0] .= array_shift($text_stack); + $em = ''; + } + // Closing strong marker: + array_shift($token_stack); + $span = array_shift($text_stack); + $span = $this->runSpanGamut($span); + $span = "$span"; + $text_stack[0] .= $this->hashPart($span); + $strong = ''; + } else { + array_unshift($token_stack, $token); + array_unshift($text_stack, ''); + $strong = $token; + } + } else { + // Here $token_len == 1 + if ($em) { + if (strlen($token_stack[0]) == 1) { + // Closing emphasis marker: + array_shift($token_stack); + $span = array_shift($text_stack); + $span = $this->runSpanGamut($span); + $span = "$span"; + $text_stack[0] .= $this->hashPart($span); + $em = ''; + } else { + $text_stack[0] .= $token; + } + } else { + array_unshift($token_stack, $token); + array_unshift($text_stack, ''); + $em = $token; + } + } + } + $this->in_emphasis_processing = false; + return $text_stack[0]; + } + + /** + * Parse Markdown blockquotes to HTML + * @param string $text + * @return string + */ + protected function doBlockQuotes($text) { + $text = preg_replace_callback('/ + ( # Wrap whole match in $1 + (?> + ^[ ]*>[ ]? # ">" at the start of a line + .+\n # rest of the first line + (.+\n)* # subsequent consecutive lines + \n* # blanks + )+ + ) + /xm', + array($this, '_doBlockQuotes_callback'), $text); + + return $text; + } + + /** + * Blockquote parsing callback + * @param array $matches + * @return string + */ + protected function _doBlockQuotes_callback($matches) { + $bq = $matches[1]; + // trim one level of quoting - trim whitespace-only lines + $bq = preg_replace('/^[ ]*>[ ]?|^[ ]+$/m', '', $bq); + $bq = $this->runBlockGamut($bq); // recurse + + $bq = preg_replace('/^/m', " ", $bq); + // These leading spaces cause problem with
     content,
    +		// so we need to fix that:
    +		$bq = preg_replace_callback('{(\s*
    .+?
    )}sx', + array($this, '_doBlockQuotes_callback2'), $bq); + + return "\n" . $this->hashBlock("
    \n$bq\n
    ") . "\n\n"; + } + + /** + * Blockquote parsing callback + * @param array $matches + * @return string + */ + protected function _doBlockQuotes_callback2($matches) { + $pre = $matches[1]; + $pre = preg_replace('/^ /m', '', $pre); + return $pre; + } + + /** + * Parse paragraphs + * + * @param string $text String to process in paragraphs + * @param boolean $wrap_in_p Whether paragraphs should be wrapped in

    tags + * @return string + */ + protected function formParagraphs($text, $wrap_in_p = true) { + // Strip leading and trailing lines: + $text = preg_replace('/\A\n+|\n+\z/', '', $text); + + $grafs = preg_split('/\n{2,}/', $text, -1, PREG_SPLIT_NO_EMPTY); + + // Wrap

    tags and unhashify HTML blocks + foreach ($grafs as $key => $value) { + if (!preg_match('/^B\x1A[0-9]+B$/', $value)) { + // Is a paragraph. + $value = $this->runSpanGamut($value); + if ($wrap_in_p) { + $value = preg_replace('/^([ ]*)/', "

    ", $value); + $value .= "

    "; + } + $grafs[$key] = $this->unhash($value); + } else { + // Is a block. + // Modify elements of @grafs in-place... + $graf = $value; + $block = $this->html_hashes[$graf]; + $graf = $block; +// if (preg_match('{ +// \A +// ( # $1 =
    tag +//
    ]* +// \b +// markdown\s*=\s* ([\'"]) # $2 = attr quote char +// 1 +// \2 +// [^>]* +// > +// ) +// ( # $3 = contents +// .* +// ) +// (
    ) # $4 = closing tag +// \z +// }xs', $block, $matches)) +// { +// list(, $div_open, , $div_content, $div_close) = $matches; +// +// // We can't call Markdown(), because that resets the hash; +// // that initialization code should be pulled into its own sub, though. +// $div_content = $this->hashHTMLBlocks($div_content); +// +// // Run document gamut methods on the content. +// foreach ($this->document_gamut as $method => $priority) { +// $div_content = $this->$method($div_content); +// } +// +// $div_open = preg_replace( +// '{\smarkdown\s*=\s*([\'"]).+?\1}', '', $div_open); +// +// $graf = $div_open . "\n" . $div_content . "\n" . $div_close; +// } + $grafs[$key] = $graf; + } + } + + return implode("\n\n", $grafs); + } + + /** + * Encode text for a double-quoted HTML attribute. This function + * is *not* suitable for attributes enclosed in single quotes. + * @param string $text + * @return string + */ + protected function encodeAttribute($text) { + $text = $this->encodeAmpsAndAngles($text); + $text = str_replace('"', '"', $text); + return $text; + } + + /** + * Encode text for a double-quoted HTML attribute containing a URL, + * applying the URL filter if set. Also generates the textual + * representation for the URL (removing mailto: or tel:) storing it in $text. + * This function is *not* suitable for attributes enclosed in single quotes. + * + * @param string $url + * @param string &$text Passed by reference + * @return string URL + */ + protected function encodeURLAttribute($url, &$text = null) { + if ($this->url_filter_func) { + $url = call_user_func($this->url_filter_func, $url); + } + + if (preg_match('{^mailto:}i', $url)) { + $url = $this->encodeEntityObfuscatedAttribute($url, $text, 7); + } else if (preg_match('{^tel:}i', $url)) { + $url = $this->encodeAttribute($url); + $text = substr($url, 4); + } else { + $url = $this->encodeAttribute($url); + $text = $url; + } + + return $url; + } + + /** + * Smart processing for ampersands and angle brackets that need to + * be encoded. Valid character entities are left alone unless the + * no-entities mode is set. + * @param string $text + * @return string + */ + protected function encodeAmpsAndAngles($text) { + if ($this->no_entities) { + $text = str_replace('&', '&', $text); + } else { + // Ampersand-encoding based entirely on Nat Irons's Amputator + // MT plugin: + $text = preg_replace('/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/', + '&', $text); + } + // Encode remaining <'s + $text = str_replace('<', '<', $text); + + return $text; + } + + /** + * Parse Markdown automatic links to anchor HTML tags + * @param string $text + * @return string + */ + protected function doAutoLinks($text) { + $text = preg_replace_callback('{<((https?|ftp|dict|tel):[^\'">\s]+)>}i', + array($this, '_doAutoLinks_url_callback'), $text); + + // Email addresses: + $text = preg_replace_callback('{ + < + (?:mailto:)? + ( + (?: + [-!#$%&\'*+/=?^_`.{|}~\w\x80-\xFF]+ + | + ".*?" + ) + \@ + (?: + [-a-z0-9\x80-\xFF]+(\.[-a-z0-9\x80-\xFF]+)*\.[a-z]+ + | + \[[\d.a-fA-F:]+\] # IPv4 & IPv6 + ) + ) + > + }xi', + array($this, '_doAutoLinks_email_callback'), $text); + + return $text; + } + + /** + * Parse URL callback + * @param array $matches + * @return string + */ + protected function _doAutoLinks_url_callback($matches) { + $url = $this->encodeURLAttribute($matches[1], $text); + $link = "$text"; + return $this->hashPart($link); + } + + /** + * Parse email address callback + * @param array $matches + * @return string + */ + protected function _doAutoLinks_email_callback($matches) { + $addr = $matches[1]; + $url = $this->encodeURLAttribute("mailto:$addr", $text); + $link = "$text"; + return $this->hashPart($link); + } + + /** + * Input: some text to obfuscate, e.g. "mailto:foo@example.com" + * + * Output: the same text but with most characters encoded as either a + * decimal or hex entity, in the hopes of foiling most address + * harvesting spam bots. E.g.: + * + * mailto:foo + * @example.co + * m + * + * Note: the additional output $tail is assigned the same value as the + * ouput, minus the number of characters specified by $head_length. + * + * Based by a filter by Matthew Wickline, posted to BBEdit-Talk. + * With some optimizations by Milian Wolff. Forced encoding of HTML + * attribute special characters by Allan Odgaard. + * + * @param string $text + * @param string &$tail + * @param integer $head_length + * @return string + */ + protected function encodeEntityObfuscatedAttribute($text, &$tail = null, $head_length = 0) { + if ($text == "") { + return $tail = ""; + } + + $chars = preg_split('/(? $char) { + $ord = ord($char); + // Ignore non-ascii chars. + if ($ord < 128) { + $r = ($seed * (1 + $key)) % 100; // Pseudo-random function. + // roughly 10% raw, 45% hex, 45% dec + // '@' *must* be encoded. I insist. + // '"' and '>' have to be encoded inside the attribute + if ($r > 90 && strpos('@"&>', $char) === false) { + /* do nothing */ + } else if ($r < 45) { + $chars[$key] = '&#x'.dechex($ord).';'; + } else { + $chars[$key] = '&#'.$ord.';'; + } + } + } + + $text = implode('', $chars); + $tail = $head_length ? implode('', array_slice($chars, $head_length)) : $text; + + return $text; + } + + /** + * Take the string $str and parse it into tokens, hashing embeded HTML, + * escaped characters and handling code spans. + * @param string $str + * @return string + */ + protected function parseSpan($str) { + $output = ''; + + $span_re = '{ + ( + \\\\'.$this->escape_chars_re.' + | + (?no_markup ? '' : ' + | + # comment + | + <\?.*?\?> | <%.*?%> # processing instruction + | + <[!$]?[-a-zA-Z0-9:_]+ # regular tags + (?> + \s + (?>[^"\'>]+|"[^"]*"|\'[^\']*\')* + )? + > + | + <[-a-zA-Z0-9:_]+\s*/> # xml-style empty tag + | + # closing tag + ').' + ) + }xs'; + + while (1) { + // Each loop iteration seach for either the next tag, the next + // openning code span marker, or the next escaped character. + // Each token is then passed to handleSpanToken. + $parts = preg_split($span_re, $str, 2, PREG_SPLIT_DELIM_CAPTURE); + + // Create token from text preceding tag. + if ($parts[0] != "") { + $output .= $parts[0]; + } + + // Check if we reach the end. + if (isset($parts[1])) { + $output .= $this->handleSpanToken($parts[1], $parts[2]); + $str = $parts[2]; + } else { + break; + } + } + + return $output; + } + + /** + * Handle $token provided by parseSpan by determining its nature and + * returning the corresponding value that should replace it. + * @param string $token + * @param string &$str + * @return string + */ + protected function handleSpanToken($token, &$str) { + switch ($token{0}) { + case "\\": + return $this->hashPart("&#". ord($token{1}). ";"); + case "`": + // Search for end marker in remaining text. + if (preg_match('/^(.*?[^`])'.preg_quote($token).'(?!`)(.*)$/sm', + $str, $matches)) + { + $str = $matches[2]; + $codespan = $this->makeCodeSpan($matches[1]); + return $this->hashPart($codespan); + } + return $token; // Return as text since no ending marker found. + default: + return $this->hashPart($token); + } + } + + /** + * Remove one level of line-leading tabs or spaces + * @param string $text + * @return string + */ + protected function outdent($text) { + return preg_replace('/^(\t|[ ]{1,' . $this->tab_width . '})/m', '', $text); + } + + + /** + * String length function for detab. `_initDetab` will create a function to + * handle UTF-8 if the default function does not exist. + * @var string + */ + protected $utf8_strlen = 'mb_strlen'; + + /** + * Replace tabs with the appropriate amount of spaces. + * + * For each line we separate the line in blocks delemited by tab characters. + * Then we reconstruct every line by adding the appropriate number of space + * between each blocks. + * + * @param string $text + * @return string + */ + protected function detab($text) { + $text = preg_replace_callback('/^.*\t.*$/m', + array($this, '_detab_callback'), $text); + + return $text; + } + + /** + * Replace tabs callback + * @param string $matches + * @return string + */ + protected function _detab_callback($matches) { + $line = $matches[0]; + $strlen = $this->utf8_strlen; // strlen function for UTF-8. + + // Split in blocks. + $blocks = explode("\t", $line); + // Add each blocks to the line. + $line = $blocks[0]; + unset($blocks[0]); // Do not add first block twice. + foreach ($blocks as $block) { + // Calculate amount of space, insert spaces, insert block. + $amount = $this->tab_width - + $strlen($line, 'UTF-8') % $this->tab_width; + $line .= str_repeat(" ", $amount) . $block; + } + return $line; + } + + /** + * Check for the availability of the function in the `utf8_strlen` property + * (initially `mb_strlen`). If the function is not available, create a + * function that will loosely count the number of UTF-8 characters with a + * regular expression. + * @return void + */ + protected function _initDetab() { + + if (function_exists($this->utf8_strlen)) { + return; + } + + $this->utf8_strlen = function($text) { + return preg_match_all('/[\x00-\xBF]|[\xC0-\xFF][\x80-\xBF]*/', $text, $m); + }; + } + + /** + * Swap back in all the tags hashed by _HashHTMLBlocks. + * @param string $text + * @return string + */ + protected function unhash($text) { + return preg_replace_callback('/(.)\x1A[0-9]+\1/', + array($this, '_unhash_callback'), $text); + } + + /** + * Unhashing callback + * @param array $matches + * @return string + */ + protected function _unhash_callback($matches) { + return $this->html_hashes[$matches[0]]; + } +} diff --git a/vendor/michelf/php-markdown/Michelf/MarkdownExtra.inc.php b/vendor/michelf/php-markdown/Michelf/MarkdownExtra.inc.php new file mode 100644 index 0000000000..d09bd7a480 --- /dev/null +++ b/vendor/michelf/php-markdown/Michelf/MarkdownExtra.inc.php @@ -0,0 +1,11 @@ + + * @copyright 2004-2018 Michel Fortin + * @copyright (Original Markdown) 2004-2006 John Gruber + */ + +namespace Michelf; + +/** + * Markdown Extra Parser Class + */ +class MarkdownExtra extends \Michelf\Markdown { + /** + * Configuration variables + */ + + /** + * Prefix for footnote ids. + * @var string + */ + public $fn_id_prefix = ""; + + /** + * Optional title attribute for footnote links and backlinks. + * @var string + */ + public $fn_link_title = ""; + public $fn_backlink_title = ""; + + /** + * Optional class attribute for footnote links and backlinks. + * @var string + */ + public $fn_link_class = "footnote-ref"; + public $fn_backlink_class = "footnote-backref"; + + /** + * Content to be displayed within footnote backlinks. The default is '↩'; + * the U+FE0E on the end is a Unicode variant selector used to prevent iOS + * from displaying the arrow character as an emoji. + * @var string + */ + public $fn_backlink_html = '↩︎'; + + /** + * Class name for table cell alignment (%% replaced left/center/right) + * For instance: 'go-%%' becomes 'go-left' or 'go-right' or 'go-center' + * If empty, the align attribute is used instead of a class name. + * @var string + */ + public $table_align_class_tmpl = ''; + + /** + * Optional class prefix for fenced code block. + * @var string + */ + public $code_class_prefix = ""; + + /** + * Class attribute for code blocks goes on the `code` tag; + * setting this to true will put attributes on the `pre` tag instead. + * @var boolean + */ + public $code_attr_on_pre = false; + + /** + * Predefined abbreviations. + * @var array + */ + public $predef_abbr = array(); + + /** + * Only convert atx-style headers if there's a space between the header and # + * @var boolean + */ + public $hashtag_protection = false; + + /** + * Parser implementation + */ + + /** + * Constructor function. Initialize the parser object. + * @return void + */ + public function __construct() { + // Add extra escapable characters before parent constructor + // initialize the table. + $this->escape_chars .= ':|'; + + // Insert extra document, block, and span transformations. + // Parent constructor will do the sorting. + $this->document_gamut += array( + "doFencedCodeBlocks" => 5, + "stripFootnotes" => 15, + "stripAbbreviations" => 25, + "appendFootnotes" => 50, + ); + $this->block_gamut += array( + "doFencedCodeBlocks" => 5, + "doTables" => 15, + "doDefLists" => 45, + ); + $this->span_gamut += array( + "doFootnotes" => 5, + "doAbbreviations" => 70, + ); + + $this->enhanced_ordered_list = true; + parent::__construct(); + } + + + /** + * Extra variables used during extra transformations. + * @var array + */ + protected $footnotes = array(); + protected $footnotes_ordered = array(); + protected $footnotes_ref_count = array(); + protected $footnotes_numbers = array(); + protected $abbr_desciptions = array(); + /** @var string */ + protected $abbr_word_re = ''; + + /** + * Give the current footnote number. + * @var integer + */ + protected $footnote_counter = 1; + + /** + * Setting up Extra-specific variables. + */ + protected function setup() { + parent::setup(); + + $this->footnotes = array(); + $this->footnotes_ordered = array(); + $this->footnotes_ref_count = array(); + $this->footnotes_numbers = array(); + $this->abbr_desciptions = array(); + $this->abbr_word_re = ''; + $this->footnote_counter = 1; + + foreach ($this->predef_abbr as $abbr_word => $abbr_desc) { + if ($this->abbr_word_re) + $this->abbr_word_re .= '|'; + $this->abbr_word_re .= preg_quote($abbr_word); + $this->abbr_desciptions[$abbr_word] = trim($abbr_desc); + } + } + + /** + * Clearing Extra-specific variables. + */ + protected function teardown() { + $this->footnotes = array(); + $this->footnotes_ordered = array(); + $this->footnotes_ref_count = array(); + $this->footnotes_numbers = array(); + $this->abbr_desciptions = array(); + $this->abbr_word_re = ''; + + parent::teardown(); + } + + + /** + * Extra attribute parser + */ + + /** + * Expression to use to catch attributes (includes the braces) + * @var string + */ + protected $id_class_attr_catch_re = '\{((?>[ ]*[#.a-z][-_:a-zA-Z0-9=]+){1,})[ ]*\}'; + + /** + * Expression to use when parsing in a context when no capture is desired + * @var string + */ + protected $id_class_attr_nocatch_re = '\{(?>[ ]*[#.a-z][-_:a-zA-Z0-9=]+){1,}[ ]*\}'; + + /** + * Parse attributes caught by the $this->id_class_attr_catch_re expression + * and return the HTML-formatted list of attributes. + * + * Currently supported attributes are .class and #id. + * + * In addition, this method also supports supplying a default Id value, + * which will be used to populate the id attribute in case it was not + * overridden. + * @param string $tag_name + * @param string $attr + * @param mixed $defaultIdValue + * @param array $classes + * @return string + */ + protected function doExtraAttributes($tag_name, $attr, $defaultIdValue = null, $classes = array()) { + if (empty($attr) && !$defaultIdValue && empty($classes)) return ""; + + // Split on components + preg_match_all('/[#.a-z][-_:a-zA-Z0-9=]+/', $attr, $matches); + $elements = $matches[0]; + + // Handle classes and IDs (only first ID taken into account) + $attributes = array(); + $id = false; + foreach ($elements as $element) { + if ($element{0} == '.') { + $classes[] = substr($element, 1); + } else if ($element{0} == '#') { + if ($id === false) $id = substr($element, 1); + } else if (strpos($element, '=') > 0) { + $parts = explode('=', $element, 2); + $attributes[] = $parts[0] . '="' . $parts[1] . '"'; + } + } + + if (!$id) $id = $defaultIdValue; + + // Compose attributes as string + $attr_str = ""; + if (!empty($id)) { + $attr_str .= ' id="'.$this->encodeAttribute($id) .'"'; + } + if (!empty($classes)) { + $attr_str .= ' class="'. implode(" ", $classes) . '"'; + } + if (!$this->no_markup && !empty($attributes)) { + $attr_str .= ' '.implode(" ", $attributes); + } + return $attr_str; + } + + /** + * Strips link definitions from text, stores the URLs and titles in + * hash references. + * @param string $text + * @return string + */ + protected function stripLinkDefinitions($text) { + $less_than_tab = $this->tab_width - 1; + + // Link defs are in the form: ^[id]: url "optional title" + $text = preg_replace_callback('{ + ^[ ]{0,'.$less_than_tab.'}\[(.+)\][ ]?: # id = $1 + [ ]* + \n? # maybe *one* newline + [ ]* + (?: + <(.+?)> # url = $2 + | + (\S+?) # url = $3 + ) + [ ]* + \n? # maybe one newline + [ ]* + (?: + (?<=\s) # lookbehind for whitespace + ["(] + (.*?) # title = $4 + [")] + [ ]* + )? # title is optional + (?:[ ]* '.$this->id_class_attr_catch_re.' )? # $5 = extra id & class attr + (?:\n+|\Z) + }xm', + array($this, '_stripLinkDefinitions_callback'), + $text); + return $text; + } + + /** + * Strip link definition callback + * @param array $matches + * @return string + */ + protected function _stripLinkDefinitions_callback($matches) { + $link_id = strtolower($matches[1]); + $url = $matches[2] == '' ? $matches[3] : $matches[2]; + $this->urls[$link_id] = $url; + $this->titles[$link_id] =& $matches[4]; + $this->ref_attr[$link_id] = $this->doExtraAttributes("", $dummy =& $matches[5]); + return ''; // String that will replace the block + } + + + /** + * HTML block parser + */ + + /** + * Tags that are always treated as block tags + * @var string + */ + protected $block_tags_re = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|form|fieldset|iframe|hr|legend|article|section|nav|aside|hgroup|header|footer|figcaption|figure'; + + /** + * Tags treated as block tags only if the opening tag is alone on its line + * @var string + */ + protected $context_block_tags_re = 'script|noscript|style|ins|del|iframe|object|source|track|param|math|svg|canvas|audio|video'; + + /** + * Tags where markdown="1" default to span mode: + * @var string + */ + protected $contain_span_tags_re = 'p|h[1-6]|li|dd|dt|td|th|legend|address'; + + /** + * Tags which must not have their contents modified, no matter where + * they appear + * @var string + */ + protected $clean_tags_re = 'script|style|math|svg'; + + /** + * Tags that do not need to be closed. + * @var string + */ + protected $auto_close_tags_re = 'hr|img|param|source|track'; + + /** + * Hashify HTML Blocks and "clean tags". + * + * We only want to do this for block-level HTML tags, such as headers, + * lists, and tables. That's because we still want to wrap

    s around + * "paragraphs" that are wrapped in non-block-level tags, such as anchors, + * phrase emphasis, and spans. The list of tags we're looking for is + * hard-coded. + * + * This works by calling _HashHTMLBlocks_InMarkdown, which then calls + * _HashHTMLBlocks_InHTML when it encounter block tags. When the markdown="1" + * attribute is found within a tag, _HashHTMLBlocks_InHTML calls back + * _HashHTMLBlocks_InMarkdown to handle the Markdown syntax within the tag. + * These two functions are calling each other. It's recursive! + * @param string $text + * @return string + */ + protected function hashHTMLBlocks($text) { + if ($this->no_markup) { + return $text; + } + + // Call the HTML-in-Markdown hasher. + list($text, ) = $this->_hashHTMLBlocks_inMarkdown($text); + + return $text; + } + + /** + * Parse markdown text, calling _HashHTMLBlocks_InHTML for block tags. + * + * * $indent is the number of space to be ignored when checking for code + * blocks. This is important because if we don't take the indent into + * account, something like this (which looks right) won't work as expected: + * + *

    + *
    + * Hello World. <-- Is this a Markdown code block or text? + *
    <-- Is this a Markdown code block or a real tag? + *
    + * + * If you don't like this, just don't indent the tag on which + * you apply the markdown="1" attribute. + * + * * If $enclosing_tag_re is not empty, stops at the first unmatched closing + * tag with that name. Nested tags supported. + * + * * If $span is true, text inside must treated as span. So any double + * newline will be replaced by a single newline so that it does not create + * paragraphs. + * + * Returns an array of that form: ( processed text , remaining text ) + * + * @param string $text + * @param integer $indent + * @param string $enclosing_tag_re + * @param boolean $span + * @return array + */ + protected function _hashHTMLBlocks_inMarkdown($text, $indent = 0, + $enclosing_tag_re = '', $span = false) + { + + if ($text === '') return array('', ''); + + // Regex to check for the presense of newlines around a block tag. + $newline_before_re = '/(?:^\n?|\n\n)*$/'; + $newline_after_re = + '{ + ^ # Start of text following the tag. + (?>[ ]*)? # Optional comment. + [ ]*\n # Must be followed by newline. + }xs'; + + // Regex to match any tag. + $block_tag_re = + '{ + ( # $2: Capture whole tag. + # Tag name. + ' . $this->block_tags_re . ' | + ' . $this->context_block_tags_re . ' | + ' . $this->clean_tags_re . ' | + (?!\s)'.$enclosing_tag_re . ' + ) + (?: + (?=[\s"\'/a-zA-Z0-9]) # Allowed characters after tag name. + (?> + ".*?" | # Double quotes (can contain `>`) + \'.*?\' | # Single quotes (can contain `>`) + .+? # Anything but quotes and `>`. + )*? + )? + > # End of tag. + | + # HTML Comment + | + <\?.*?\?> | <%.*?%> # Processing instruction + | + # CData Block + ' . ( !$span ? ' # If not in span. + | + # Indented code block + (?: ^[ ]*\n | ^ | \n[ ]*\n ) + [ ]{' . ($indent + 4) . '}[^\n]* \n + (?> + (?: [ ]{' . ($indent + 4) . '}[^\n]* | [ ]* ) \n + )* + | + # Fenced code block marker + (?<= ^ | \n ) + [ ]{0,' . ($indent + 3) . '}(?:~{3,}|`{3,}) + [ ]* + (?: \.?[-_:a-zA-Z0-9]+ )? # standalone class name + [ ]* + (?: ' . $this->id_class_attr_nocatch_re . ' )? # extra attributes + [ ]* + (?= \n ) + ' : '' ) . ' # End (if not is span). + | + # Code span marker + # Note, this regex needs to go after backtick fenced + # code blocks but it should also be kept outside of the + # "if not in span" condition adding backticks to the parser + `+ + ) + }xs'; + + + $depth = 0; // Current depth inside the tag tree. + $parsed = ""; // Parsed text that will be returned. + + // Loop through every tag until we find the closing tag of the parent + // or loop until reaching the end of text if no parent tag specified. + do { + // Split the text using the first $tag_match pattern found. + // Text before pattern will be first in the array, text after + // pattern will be at the end, and between will be any catches made + // by the pattern. + $parts = preg_split($block_tag_re, $text, 2, + PREG_SPLIT_DELIM_CAPTURE); + + // If in Markdown span mode, add a empty-string span-level hash + // after each newline to prevent triggering any block element. + if ($span) { + $void = $this->hashPart("", ':'); + $newline = "\n$void"; + $parts[0] = $void . str_replace("\n", $newline, $parts[0]) . $void; + } + + $parsed .= $parts[0]; // Text before current tag. + + // If end of $text has been reached. Stop loop. + if (count($parts) < 3) { + $text = ""; + break; + } + + $tag = $parts[1]; // Tag to handle. + $text = $parts[2]; // Remaining text after current tag. + $tag_re = preg_quote($tag); // For use in a regular expression. + + // Check for: Fenced code block marker. + // Note: need to recheck the whole tag to disambiguate backtick + // fences from code spans + if (preg_match('{^\n?([ ]{0,' . ($indent + 3) . '})(~{3,}|`{3,})[ ]*(?:\.?[-_:a-zA-Z0-9]+)?[ ]*(?:' . $this->id_class_attr_nocatch_re . ')?[ ]*\n?$}', $tag, $capture)) { + // Fenced code block marker: find matching end marker. + $fence_indent = strlen($capture[1]); // use captured indent in re + $fence_re = $capture[2]; // use captured fence in re + if (preg_match('{^(?>.*\n)*?[ ]{' . ($fence_indent) . '}' . $fence_re . '[ ]*(?:\n|$)}', $text, + $matches)) + { + // End marker found: pass text unchanged until marker. + $parsed .= $tag . $matches[0]; + $text = substr($text, strlen($matches[0])); + } + else { + // No end marker: just skip it. + $parsed .= $tag; + } + } + // Check for: Indented code block. + else if ($tag{0} == "\n" || $tag{0} == " ") { + // Indented code block: pass it unchanged, will be handled + // later. + $parsed .= $tag; + } + // Check for: Code span marker + // Note: need to check this after backtick fenced code blocks + else if ($tag{0} == "`") { + // Find corresponding end marker. + $tag_re = preg_quote($tag); + if (preg_match('{^(?>.+?|\n(?!\n))*?(?block_tags_re . ')\b}', $tag) || + ( preg_match('{^<(?:' . $this->context_block_tags_re . ')\b}', $tag) && + preg_match($newline_before_re, $parsed) && + preg_match($newline_after_re, $text) ) + ) + { + // Need to parse tag and following text using the HTML parser. + list($block_text, $text) = + $this->_hashHTMLBlocks_inHTML($tag . $text, "hashBlock", true); + + // Make sure it stays outside of any paragraph by adding newlines. + $parsed .= "\n\n$block_text\n\n"; + } + // Check for: Clean tag (like script, math) + // HTML Comments, processing instructions. + else if (preg_match('{^<(?:' . $this->clean_tags_re . ')\b}', $tag) || + $tag{1} == '!' || $tag{1} == '?') + { + // Need to parse tag and following text using the HTML parser. + // (don't check for markdown attribute) + list($block_text, $text) = + $this->_hashHTMLBlocks_inHTML($tag . $text, "hashClean", false); + + $parsed .= $block_text; + } + // Check for: Tag with same name as enclosing tag. + else if ($enclosing_tag_re !== '' && + // Same name as enclosing tag. + preg_match('{^= 0); + + return array($parsed, $text); + } + + /** + * Parse HTML, calling _HashHTMLBlocks_InMarkdown for block tags. + * + * * Calls $hash_method to convert any blocks. + * * Stops when the first opening tag closes. + * * $md_attr indicate if the use of the `markdown="1"` attribute is allowed. + * (it is not inside clean tags) + * + * Returns an array of that form: ( processed text , remaining text ) + * @param string $text + * @param string $hash_method + * @param string $md_attr + * @return array + */ + protected function _hashHTMLBlocks_inHTML($text, $hash_method, $md_attr) { + if ($text === '') return array('', ''); + + // Regex to match `markdown` attribute inside of a tag. + $markdown_attr_re = ' + { + \s* # Eat whitespace before the `markdown` attribute + markdown + \s*=\s* + (?> + (["\']) # $1: quote delimiter + (.*?) # $2: attribute value + \1 # matching delimiter + | + ([^\s>]*) # $3: unquoted attribute value + ) + () # $4: make $3 always defined (avoid warnings) + }xs'; + + // Regex to match any tag. + $tag_re = '{ + ( # $2: Capture whole tag. + + ".*?" | # Double quotes (can contain `>`) + \'.*?\' | # Single quotes (can contain `>`) + .+? # Anything but quotes and `>`. + )*? + )? + > # End of tag. + | + # HTML Comment + | + <\?.*?\?> | <%.*?%> # Processing instruction + | + # CData Block + ) + }xs'; + + $original_text = $text; // Save original text in case of faliure. + + $depth = 0; // Current depth inside the tag tree. + $block_text = ""; // Temporary text holder for current text. + $parsed = ""; // Parsed text that will be returned. + + // Get the name of the starting tag. + // (This pattern makes $base_tag_name_re safe without quoting.) + if (preg_match('/^<([\w:$]*)\b/', $text, $matches)) + $base_tag_name_re = $matches[1]; + + // Loop through every tag until we find the corresponding closing tag. + do { + // Split the text using the first $tag_match pattern found. + // Text before pattern will be first in the array, text after + // pattern will be at the end, and between will be any catches made + // by the pattern. + $parts = preg_split($tag_re, $text, 2, PREG_SPLIT_DELIM_CAPTURE); + + if (count($parts) < 3) { + // End of $text reached with unbalenced tag(s). + // In that case, we return original text unchanged and pass the + // first character as filtered to prevent an infinite loop in the + // parent function. + return array($original_text{0}, substr($original_text, 1)); + } + + $block_text .= $parts[0]; // Text before current tag. + $tag = $parts[1]; // Tag to handle. + $text = $parts[2]; // Remaining text after current tag. + + // Check for: Auto-close tag (like
    ) + // Comments and Processing Instructions. + if (preg_match('{^auto_close_tags_re . ')\b}', $tag) || + $tag{1} == '!' || $tag{1} == '?') + { + // Just add the tag to the block as if it was text. + $block_text .= $tag; + } + else { + // Increase/decrease nested tag count. Only do so if + // the tag's name match base tag's. + if (preg_match('{^mode = $attr_m[2] . $attr_m[3]; + $span_mode = $this->mode == 'span' || $this->mode != 'block' && + preg_match('{^<(?:' . $this->contain_span_tags_re . ')\b}', $tag); + + // Calculate indent before tag. + if (preg_match('/(?:^|\n)( *?)(?! ).*?$/', $block_text, $matches)) { + $strlen = $this->utf8_strlen; + $indent = $strlen($matches[1], 'UTF-8'); + } else { + $indent = 0; + } + + // End preceding block with this tag. + $block_text .= $tag; + $parsed .= $this->$hash_method($block_text); + + // Get enclosing tag name for the ParseMarkdown function. + // (This pattern makes $tag_name_re safe without quoting.) + preg_match('/^<([\w:$]*)\b/', $tag, $matches); + $tag_name_re = $matches[1]; + + // Parse the content using the HTML-in-Markdown parser. + list ($block_text, $text) + = $this->_hashHTMLBlocks_inMarkdown($text, $indent, + $tag_name_re, $span_mode); + + // Outdent markdown text. + if ($indent > 0) { + $block_text = preg_replace("/^[ ]{1,$indent}/m", "", + $block_text); + } + + // Append tag content to parsed text. + if (!$span_mode) $parsed .= "\n\n$block_text\n\n"; + else $parsed .= "$block_text"; + + // Start over with a new block. + $block_text = ""; + } + else $block_text .= $tag; + } + + } while ($depth > 0); + + // Hash last block text that wasn't processed inside the loop. + $parsed .= $this->$hash_method($block_text); + + return array($parsed, $text); + } + + /** + * Called whenever a tag must be hashed when a function inserts a "clean" tag + * in $text, it passes through this function and is automaticaly escaped, + * blocking invalid nested overlap. + * @param string $text + * @return string + */ + protected function hashClean($text) { + return $this->hashPart($text, 'C'); + } + + /** + * Turn Markdown link shortcuts into XHTML tags. + * @param string $text + * @return string + */ + protected function doAnchors($text) { + if ($this->in_anchor) { + return $text; + } + $this->in_anchor = true; + + // First, handle reference-style links: [link text] [id] + $text = preg_replace_callback('{ + ( # wrap whole match in $1 + \[ + (' . $this->nested_brackets_re . ') # link text = $2 + \] + + [ ]? # one optional space + (?:\n[ ]*)? # one optional newline followed by spaces + + \[ + (.*?) # id = $3 + \] + ) + }xs', + array($this, '_doAnchors_reference_callback'), $text); + + // Next, inline-style links: [link text](url "optional title") + $text = preg_replace_callback('{ + ( # wrap whole match in $1 + \[ + (' . $this->nested_brackets_re . ') # link text = $2 + \] + \( # literal paren + [ \n]* + (?: + <(.+?)> # href = $3 + | + (' . $this->nested_url_parenthesis_re . ') # href = $4 + ) + [ \n]* + ( # $5 + ([\'"]) # quote char = $6 + (.*?) # Title = $7 + \6 # matching quote + [ \n]* # ignore any spaces/tabs between closing quote and ) + )? # title is optional + \) + (?:[ ]? ' . $this->id_class_attr_catch_re . ' )? # $8 = id/class attributes + ) + }xs', + array($this, '_doAnchors_inline_callback'), $text); + + // Last, handle reference-style shortcuts: [link text] + // These must come last in case you've also got [link text][1] + // or [link text](/foo) + $text = preg_replace_callback('{ + ( # wrap whole match in $1 + \[ + ([^\[\]]+) # link text = $2; can\'t contain [ or ] + \] + ) + }xs', + array($this, '_doAnchors_reference_callback'), $text); + + $this->in_anchor = false; + return $text; + } + + /** + * Callback for reference anchors + * @param array $matches + * @return string + */ + protected function _doAnchors_reference_callback($matches) { + $whole_match = $matches[1]; + $link_text = $matches[2]; + $link_id =& $matches[3]; + + if ($link_id == "") { + // for shortcut links like [this][] or [this]. + $link_id = $link_text; + } + + // lower-case and turn embedded newlines into spaces + $link_id = strtolower($link_id); + $link_id = preg_replace('{[ ]?\n}', ' ', $link_id); + + if (isset($this->urls[$link_id])) { + $url = $this->urls[$link_id]; + $url = $this->encodeURLAttribute($url); + + $result = "titles[$link_id] ) ) { + $title = $this->titles[$link_id]; + $title = $this->encodeAttribute($title); + $result .= " title=\"$title\""; + } + if (isset($this->ref_attr[$link_id])) + $result .= $this->ref_attr[$link_id]; + + $link_text = $this->runSpanGamut($link_text); + $result .= ">$link_text"; + $result = $this->hashPart($result); + } + else { + $result = $whole_match; + } + return $result; + } + + /** + * Callback for inline anchors + * @param array $matches + * @return string + */ + protected function _doAnchors_inline_callback($matches) { + $whole_match = $matches[1]; + $link_text = $this->runSpanGamut($matches[2]); + $url = $matches[3] == '' ? $matches[4] : $matches[3]; + $title =& $matches[7]; + $attr = $this->doExtraAttributes("a", $dummy =& $matches[8]); + + // if the URL was of the form it got caught by the HTML + // tag parser and hashed. Need to reverse the process before using the URL. + $unhashed = $this->unhash($url); + if ($unhashed != $url) + $url = preg_replace('/^<(.*)>$/', '\1', $unhashed); + + $url = $this->encodeURLAttribute($url); + + $result = "encodeAttribute($title); + $result .= " title=\"$title\""; + } + $result .= $attr; + + $link_text = $this->runSpanGamut($link_text); + $result .= ">$link_text"; + + return $this->hashPart($result); + } + + /** + * Turn Markdown image shortcuts into tags. + * @param string $text + * @return string + */ + protected function doImages($text) { + // First, handle reference-style labeled images: ![alt text][id] + $text = preg_replace_callback('{ + ( # wrap whole match in $1 + !\[ + (' . $this->nested_brackets_re . ') # alt text = $2 + \] + + [ ]? # one optional space + (?:\n[ ]*)? # one optional newline followed by spaces + + \[ + (.*?) # id = $3 + \] + + ) + }xs', + array($this, '_doImages_reference_callback'), $text); + + // Next, handle inline images: ![alt text](url "optional title") + // Don't forget: encode * and _ + $text = preg_replace_callback('{ + ( # wrap whole match in $1 + !\[ + (' . $this->nested_brackets_re . ') # alt text = $2 + \] + \s? # One optional whitespace character + \( # literal paren + [ \n]* + (?: + <(\S*)> # src url = $3 + | + (' . $this->nested_url_parenthesis_re . ') # src url = $4 + ) + [ \n]* + ( # $5 + ([\'"]) # quote char = $6 + (.*?) # title = $7 + \6 # matching quote + [ \n]* + )? # title is optional + \) + (?:[ ]? ' . $this->id_class_attr_catch_re . ' )? # $8 = id/class attributes + ) + }xs', + array($this, '_doImages_inline_callback'), $text); + + return $text; + } + + /** + * Callback for referenced images + * @param array $matches + * @return string + */ + protected function _doImages_reference_callback($matches) { + $whole_match = $matches[1]; + $alt_text = $matches[2]; + $link_id = strtolower($matches[3]); + + if ($link_id == "") { + $link_id = strtolower($alt_text); // for shortcut links like ![this][]. + } + + $alt_text = $this->encodeAttribute($alt_text); + if (isset($this->urls[$link_id])) { + $url = $this->encodeURLAttribute($this->urls[$link_id]); + $result = "\"$alt_text\"";titles[$link_id])) { + $title = $this->titles[$link_id]; + $title = $this->encodeAttribute($title); + $result .= " title=\"$title\""; + } + if (isset($this->ref_attr[$link_id])) + $result .= $this->ref_attr[$link_id]; + $result .= $this->empty_element_suffix; + $result = $this->hashPart($result); + } + else { + // If there's no such link ID, leave intact: + $result = $whole_match; + } + + return $result; + } + + /** + * Callback for inline images + * @param array $matches + * @return string + */ + protected function _doImages_inline_callback($matches) { + $whole_match = $matches[1]; + $alt_text = $matches[2]; + $url = $matches[3] == '' ? $matches[4] : $matches[3]; + $title =& $matches[7]; + $attr = $this->doExtraAttributes("img", $dummy =& $matches[8]); + + $alt_text = $this->encodeAttribute($alt_text); + $url = $this->encodeURLAttribute($url); + $result = "\"$alt_text\"";encodeAttribute($title); + $result .= " title=\"$title\""; // $title already quoted + } + $result .= $attr; + $result .= $this->empty_element_suffix; + + return $this->hashPart($result); + } + + /** + * Process markdown headers. Redefined to add ID and class attribute support. + * @param string $text + * @return string + */ + protected function doHeaders($text) { + // Setext-style headers: + // Header 1 {#header1} + // ======== + // + // Header 2 {#header2 .class1 .class2} + // -------- + // + $text = preg_replace_callback( + '{ + (^.+?) # $1: Header text + (?:[ ]+ ' . $this->id_class_attr_catch_re . ' )? # $3 = id/class attributes + [ ]*\n(=+|-+)[ ]*\n+ # $3: Header footer + }mx', + array($this, '_doHeaders_callback_setext'), $text); + + // atx-style headers: + // # Header 1 {#header1} + // ## Header 2 {#header2} + // ## Header 2 with closing hashes ## {#header3.class1.class2} + // ... + // ###### Header 6 {.class2} + // + $text = preg_replace_callback('{ + ^(\#{1,6}) # $1 = string of #\'s + [ ]'.($this->hashtag_protection ? '+' : '*').' + (.+?) # $2 = Header text + [ ]* + \#* # optional closing #\'s (not counted) + (?:[ ]+ ' . $this->id_class_attr_catch_re . ' )? # $3 = id/class attributes + [ ]* + \n+ + }xm', + array($this, '_doHeaders_callback_atx'), $text); + + return $text; + } + + /** + * Callback for setext headers + * @param array $matches + * @return string + */ + protected function _doHeaders_callback_setext($matches) { + if ($matches[3] == '-' && preg_match('{^- }', $matches[1])) { + return $matches[0]; + } + + $level = $matches[3]{0} == '=' ? 1 : 2; + + $defaultId = is_callable($this->header_id_func) ? call_user_func($this->header_id_func, $matches[1]) : null; + + $attr = $this->doExtraAttributes("h$level", $dummy =& $matches[2], $defaultId); + $block = "" . $this->runSpanGamut($matches[1]) . ""; + return "\n" . $this->hashBlock($block) . "\n\n"; + } + + /** + * Callback for atx headers + * @param array $matches + * @return string + */ + protected function _doHeaders_callback_atx($matches) { + $level = strlen($matches[1]); + + $defaultId = is_callable($this->header_id_func) ? call_user_func($this->header_id_func, $matches[2]) : null; + $attr = $this->doExtraAttributes("h$level", $dummy =& $matches[3], $defaultId); + $block = "" . $this->runSpanGamut($matches[2]) . ""; + return "\n" . $this->hashBlock($block) . "\n\n"; + } + + /** + * Form HTML tables. + * @param string $text + * @return string + */ + protected function doTables($text) { + $less_than_tab = $this->tab_width - 1; + // Find tables with leading pipe. + // + // | Header 1 | Header 2 + // | -------- | -------- + // | Cell 1 | Cell 2 + // | Cell 3 | Cell 4 + $text = preg_replace_callback(' + { + ^ # Start of a line + [ ]{0,' . $less_than_tab . '} # Allowed whitespace. + [|] # Optional leading pipe (present) + (.+) \n # $1: Header row (at least one pipe) + + [ ]{0,' . $less_than_tab . '} # Allowed whitespace. + [|] ([ ]*[-:]+[-| :]*) \n # $2: Header underline + + ( # $3: Cells + (?> + [ ]* # Allowed whitespace. + [|] .* \n # Row content. + )* + ) + (?=\n|\Z) # Stop at final double newline. + }xm', + array($this, '_doTable_leadingPipe_callback'), $text); + + // Find tables without leading pipe. + // + // Header 1 | Header 2 + // -------- | -------- + // Cell 1 | Cell 2 + // Cell 3 | Cell 4 + $text = preg_replace_callback(' + { + ^ # Start of a line + [ ]{0,' . $less_than_tab . '} # Allowed whitespace. + (\S.*[|].*) \n # $1: Header row (at least one pipe) + + [ ]{0,' . $less_than_tab . '} # Allowed whitespace. + ([-:]+[ ]*[|][-| :]*) \n # $2: Header underline + + ( # $3: Cells + (?> + .* [|] .* \n # Row content + )* + ) + (?=\n|\Z) # Stop at final double newline. + }xm', + array($this, '_DoTable_callback'), $text); + + return $text; + } + + /** + * Callback for removing the leading pipe for each row + * @param array $matches + * @return string + */ + protected function _doTable_leadingPipe_callback($matches) { + $head = $matches[1]; + $underline = $matches[2]; + $content = $matches[3]; + + $content = preg_replace('/^ *[|]/m', '', $content); + + return $this->_doTable_callback(array($matches[0], $head, $underline, $content)); + } + + /** + * Make the align attribute in a table + * @param string $alignname + * @return string + */ + protected function _doTable_makeAlignAttr($alignname) + { + if (empty($this->table_align_class_tmpl)) { + return " align=\"$alignname\""; + } + + $classname = str_replace('%%', $alignname, $this->table_align_class_tmpl); + return " class=\"$classname\""; + } + + /** + * Calback for processing tables + * @param array $matches + * @return string + */ + protected function _doTable_callback($matches) { + $head = $matches[1]; + $underline = $matches[2]; + $content = $matches[3]; + + // Remove any tailing pipes for each line. + $head = preg_replace('/[|] *$/m', '', $head); + $underline = preg_replace('/[|] *$/m', '', $underline); + $content = preg_replace('/[|] *$/m', '', $content); + + // Reading alignement from header underline. + $separators = preg_split('/ *[|] */', $underline); + foreach ($separators as $n => $s) { + if (preg_match('/^ *-+: *$/', $s)) + $attr[$n] = $this->_doTable_makeAlignAttr('right'); + else if (preg_match('/^ *:-+: *$/', $s)) + $attr[$n] = $this->_doTable_makeAlignAttr('center'); + else if (preg_match('/^ *:-+ *$/', $s)) + $attr[$n] = $this->_doTable_makeAlignAttr('left'); + else + $attr[$n] = ''; + } + + // Parsing span elements, including code spans, character escapes, + // and inline HTML tags, so that pipes inside those gets ignored. + $head = $this->parseSpan($head); + $headers = preg_split('/ *[|] */', $head); + $col_count = count($headers); + $attr = array_pad($attr, $col_count, ''); + + // Write column headers. + $text = "\n"; + $text .= "\n"; + $text .= "\n"; + foreach ($headers as $n => $header) + $text .= " " . $this->runSpanGamut(trim($header)) . "\n"; + $text .= "\n"; + $text .= "\n"; + + // Split content by row. + $rows = explode("\n", trim($content, "\n")); + + $text .= "\n"; + foreach ($rows as $row) { + // Parsing span elements, including code spans, character escapes, + // and inline HTML tags, so that pipes inside those gets ignored. + $row = $this->parseSpan($row); + + // Split row by cell. + $row_cells = preg_split('/ *[|] */', $row, $col_count); + $row_cells = array_pad($row_cells, $col_count, ''); + + $text .= "\n"; + foreach ($row_cells as $n => $cell) + $text .= " " . $this->runSpanGamut(trim($cell)) . "\n"; + $text .= "\n"; + } + $text .= "\n"; + $text .= "
    "; + + return $this->hashBlock($text) . "\n"; + } + + /** + * Form HTML definition lists. + * @param string $text + * @return string + */ + protected function doDefLists($text) { + $less_than_tab = $this->tab_width - 1; + + // Re-usable pattern to match any entire dl list: + $whole_list_re = '(?> + ( # $1 = whole list + ( # $2 + [ ]{0,' . $less_than_tab . '} + ((?>.*\S.*\n)+) # $3 = defined term + \n? + [ ]{0,' . $less_than_tab . '}:[ ]+ # colon starting definition + ) + (?s:.+?) + ( # $4 + \z + | + \n{2,} + (?=\S) + (?! # Negative lookahead for another term + [ ]{0,' . $less_than_tab . '} + (?: \S.*\n )+? # defined term + \n? + [ ]{0,' . $less_than_tab . '}:[ ]+ # colon starting definition + ) + (?! # Negative lookahead for another definition + [ ]{0,' . $less_than_tab . '}:[ ]+ # colon starting definition + ) + ) + ) + )'; // mx + + $text = preg_replace_callback('{ + (?>\A\n?|(?<=\n\n)) + ' . $whole_list_re . ' + }mx', + array($this, '_doDefLists_callback'), $text); + + return $text; + } + + /** + * Callback for processing definition lists + * @param array $matches + * @return string + */ + protected function _doDefLists_callback($matches) { + // Re-usable patterns to match list item bullets and number markers: + $list = $matches[1]; + + // Turn double returns into triple returns, so that we can make a + // paragraph for the last item in a list, if necessary: + $result = trim($this->processDefListItems($list)); + $result = "
    \n" . $result . "\n
    "; + return $this->hashBlock($result) . "\n\n"; + } + + /** + * Process the contents of a single definition list, splitting it + * into individual term and definition list items. + * @param string $list_str + * @return string + */ + protected function processDefListItems($list_str) { + + $less_than_tab = $this->tab_width - 1; + + // Trim trailing blank lines: + $list_str = preg_replace("/\n{2,}\\z/", "\n", $list_str); + + // Process definition terms. + $list_str = preg_replace_callback('{ + (?>\A\n?|\n\n+) # leading line + ( # definition terms = $1 + [ ]{0,' . $less_than_tab . '} # leading whitespace + (?!\:[ ]|[ ]) # negative lookahead for a definition + # mark (colon) or more whitespace. + (?> \S.* \n)+? # actual term (not whitespace). + ) + (?=\n?[ ]{0,3}:[ ]) # lookahead for following line feed + # with a definition mark. + }xm', + array($this, '_processDefListItems_callback_dt'), $list_str); + + // Process actual definitions. + $list_str = preg_replace_callback('{ + \n(\n+)? # leading line = $1 + ( # marker space = $2 + [ ]{0,' . $less_than_tab . '} # whitespace before colon + \:[ ]+ # definition mark (colon) + ) + ((?s:.+?)) # definition text = $3 + (?= \n+ # stop at next definition mark, + (?: # next term or end of text + [ ]{0,' . $less_than_tab . '} \:[ ] | +
    | \z + ) + ) + }xm', + array($this, '_processDefListItems_callback_dd'), $list_str); + + return $list_str; + } + + /** + * Callback for
    elements in definition lists + * @param array $matches + * @return string + */ + protected function _processDefListItems_callback_dt($matches) { + $terms = explode("\n", trim($matches[1])); + $text = ''; + foreach ($terms as $term) { + $term = $this->runSpanGamut(trim($term)); + $text .= "\n
    " . $term . "
    "; + } + return $text . "\n"; + } + + /** + * Callback for
    elements in definition lists + * @param array $matches + * @return string + */ + protected function _processDefListItems_callback_dd($matches) { + $leading_line = $matches[1]; + $marker_space = $matches[2]; + $def = $matches[3]; + + if ($leading_line || preg_match('/\n{2,}/', $def)) { + // Replace marker with the appropriate whitespace indentation + $def = str_repeat(' ', strlen($marker_space)) . $def; + $def = $this->runBlockGamut($this->outdent($def . "\n\n")); + $def = "\n". $def ."\n"; + } + else { + $def = rtrim($def); + $def = $this->runSpanGamut($this->outdent($def)); + } + + return "\n
    " . $def . "
    \n"; + } + + /** + * Adding the fenced code block syntax to regular Markdown: + * + * ~~~ + * Code block + * ~~~ + * + * @param string $text + * @return string + */ + protected function doFencedCodeBlocks($text) { + + $less_than_tab = $this->tab_width; + + $text = preg_replace_callback('{ + (?:\n|\A) + # 1: Opening marker + ( + (?:~{3,}|`{3,}) # 3 or more tildes/backticks. + ) + [ ]* + (?: + \.?([-_:a-zA-Z0-9]+) # 2: standalone class name + )? + [ ]* + (?: + ' . $this->id_class_attr_catch_re . ' # 3: Extra attributes + )? + [ ]* \n # Whitespace and newline following marker. + + # 4: Content + ( + (?> + (?!\1 [ ]* \n) # Not a closing marker. + .*\n+ + )+ + ) + + # Closing marker. + \1 [ ]* (?= \n ) + }xm', + array($this, '_doFencedCodeBlocks_callback'), $text); + + return $text; + } + + /** + * Callback to process fenced code blocks + * @param array $matches + * @return string + */ + protected function _doFencedCodeBlocks_callback($matches) { + $classname =& $matches[2]; + $attrs =& $matches[3]; + $codeblock = $matches[4]; + + if ($this->code_block_content_func) { + $codeblock = call_user_func($this->code_block_content_func, $codeblock, $classname); + } else { + $codeblock = htmlspecialchars($codeblock, ENT_NOQUOTES); + } + + $codeblock = preg_replace_callback('/^\n+/', + array($this, '_doFencedCodeBlocks_newlines'), $codeblock); + + $classes = array(); + if ($classname != "") { + if ($classname{0} == '.') + $classname = substr($classname, 1); + $classes[] = $this->code_class_prefix . $classname; + } + $attr_str = $this->doExtraAttributes($this->code_attr_on_pre ? "pre" : "code", $attrs, null, $classes); + $pre_attr_str = $this->code_attr_on_pre ? $attr_str : ''; + $code_attr_str = $this->code_attr_on_pre ? '' : $attr_str; + $codeblock = "$codeblock
    "; + + return "\n\n".$this->hashBlock($codeblock)."\n\n"; + } + + /** + * Replace new lines in fenced code blocks + * @param array $matches + * @return string + */ + protected function _doFencedCodeBlocks_newlines($matches) { + return str_repeat("empty_element_suffix", + strlen($matches[0])); + } + + /** + * Redefining emphasis markers so that emphasis by underscore does not + * work in the middle of a word. + * @var array + */ + protected $em_relist = array( + '' => '(?:(? '(? '(? '(?:(? '(? '(? '(?:(? '(? '(? tags + * @return string HTML output + */ + protected function formParagraphs($text, $wrap_in_p = true) { + // Strip leading and trailing lines: + $text = preg_replace('/\A\n+|\n+\z/', '', $text); + + $grafs = preg_split('/\n{2,}/', $text, -1, PREG_SPLIT_NO_EMPTY); + + // Wrap

    tags and unhashify HTML blocks + foreach ($grafs as $key => $value) { + $value = trim($this->runSpanGamut($value)); + + // Check if this should be enclosed in a paragraph. + // Clean tag hashes & block tag hashes are left alone. + $is_p = $wrap_in_p && !preg_match('/^B\x1A[0-9]+B|^C\x1A[0-9]+C$/', $value); + + if ($is_p) { + $value = "

    $value

    "; + } + $grafs[$key] = $value; + } + + // Join grafs in one text, then unhash HTML tags. + $text = implode("\n\n", $grafs); + + // Finish by removing any tag hashes still present in $text. + $text = $this->unhash($text); + + return $text; + } + + + /** + * Footnotes - Strips link definitions from text, stores the URLs and + * titles in hash references. + * @param string $text + * @return string + */ + protected function stripFootnotes($text) { + $less_than_tab = $this->tab_width - 1; + + // Link defs are in the form: [^id]: url "optional title" + $text = preg_replace_callback('{ + ^[ ]{0,' . $less_than_tab . '}\[\^(.+?)\][ ]?: # note_id = $1 + [ ]* + \n? # maybe *one* newline + ( # text = $2 (no blank lines allowed) + (?: + .+ # actual text + | + \n # newlines but + (?!\[.+?\][ ]?:\s)# negative lookahead for footnote or link definition marker. + (?!\n+[ ]{0,3}\S)# ensure line is not blank and followed + # by non-indented content + )* + ) + }xm', + array($this, '_stripFootnotes_callback'), + $text); + return $text; + } + + /** + * Callback for stripping footnotes + * @param array $matches + * @return string + */ + protected function _stripFootnotes_callback($matches) { + $note_id = $this->fn_id_prefix . $matches[1]; + $this->footnotes[$note_id] = $this->outdent($matches[2]); + return ''; // String that will replace the block + } + + /** + * Replace footnote references in $text [^id] with a special text-token + * which will be replaced by the actual footnote marker in appendFootnotes. + * @param string $text + * @return string + */ + protected function doFootnotes($text) { + if (!$this->in_anchor) { + $text = preg_replace('{\[\^(.+?)\]}', "F\x1Afn:\\1\x1A:", $text); + } + return $text; + } + + /** + * Append footnote list to text + * @param string $text + * @return string + */ + protected function appendFootnotes($text) { + $text = preg_replace_callback('{F\x1Afn:(.*?)\x1A:}', + array($this, '_appendFootnotes_callback'), $text); + + if (!empty($this->footnotes_ordered)) { + $text .= "\n\n"; + $text .= "
    \n"; + $text .= "empty_element_suffix . "\n"; + $text .= "
      \n\n"; + + $attr = ""; + if ($this->fn_backlink_class != "") { + $class = $this->fn_backlink_class; + $class = $this->encodeAttribute($class); + $attr .= " class=\"$class\""; + } + if ($this->fn_backlink_title != "") { + $title = $this->fn_backlink_title; + $title = $this->encodeAttribute($title); + $attr .= " title=\"$title\""; + $attr .= " aria-label=\"$title\""; + } + $attr .= " role=\"doc-backlink\""; + $backlink_text = $this->fn_backlink_html; + $num = 0; + + while (!empty($this->footnotes_ordered)) { + $footnote = reset($this->footnotes_ordered); + $note_id = key($this->footnotes_ordered); + unset($this->footnotes_ordered[$note_id]); + $ref_count = $this->footnotes_ref_count[$note_id]; + unset($this->footnotes_ref_count[$note_id]); + unset($this->footnotes[$note_id]); + + $footnote .= "\n"; // Need to append newline before parsing. + $footnote = $this->runBlockGamut("$footnote\n"); + $footnote = preg_replace_callback('{F\x1Afn:(.*?)\x1A:}', + array($this, '_appendFootnotes_callback'), $footnote); + + $attr = str_replace("%%", ++$num, $attr); + $note_id = $this->encodeAttribute($note_id); + + // Prepare backlink, multiple backlinks if multiple references + $backlink = "$backlink_text"; + for ($ref_num = 2; $ref_num <= $ref_count; ++$ref_num) { + $backlink .= " $backlink_text"; + } + // Add backlink to last paragraph; create new paragraph if needed. + if (preg_match('{

      $}', $footnote)) { + $footnote = substr($footnote, 0, -4) . " $backlink

      "; + } else { + $footnote .= "\n\n

      $backlink

      "; + } + + $text .= "
    1. \n"; + $text .= $footnote . "\n"; + $text .= "
    2. \n\n"; + } + + $text .= "
    \n"; + $text .= "
    "; + } + return $text; + } + + /** + * Callback for appending footnotes + * @param array $matches + * @return string + */ + protected function _appendFootnotes_callback($matches) { + $node_id = $this->fn_id_prefix . $matches[1]; + + // Create footnote marker only if it has a corresponding footnote *and* + // the footnote hasn't been used by another marker. + if (isset($this->footnotes[$node_id])) { + $num =& $this->footnotes_numbers[$node_id]; + if (!isset($num)) { + // Transfer footnote content to the ordered list and give it its + // number + $this->footnotes_ordered[$node_id] = $this->footnotes[$node_id]; + $this->footnotes_ref_count[$node_id] = 1; + $num = $this->footnote_counter++; + $ref_count_mark = ''; + } else { + $ref_count_mark = $this->footnotes_ref_count[$node_id] += 1; + } + + $attr = ""; + if ($this->fn_link_class != "") { + $class = $this->fn_link_class; + $class = $this->encodeAttribute($class); + $attr .= " class=\"$class\""; + } + if ($this->fn_link_title != "") { + $title = $this->fn_link_title; + $title = $this->encodeAttribute($title); + $attr .= " title=\"$title\""; + } + $attr .= " role=\"doc-noteref\""; + + $attr = str_replace("%%", $num, $attr); + $node_id = $this->encodeAttribute($node_id); + + return + "". + "$num". + ""; + } + + return "[^" . $matches[1] . "]"; + } + + + /** + * Abbreviations - strips abbreviations from text, stores titles in hash + * references. + * @param string $text + * @return string + */ + protected function stripAbbreviations($text) { + $less_than_tab = $this->tab_width - 1; + + // Link defs are in the form: [id]*: url "optional title" + $text = preg_replace_callback('{ + ^[ ]{0,' . $less_than_tab . '}\*\[(.+?)\][ ]?: # abbr_id = $1 + (.*) # text = $2 (no blank lines allowed) + }xm', + array($this, '_stripAbbreviations_callback'), + $text); + return $text; + } + + /** + * Callback for stripping abbreviations + * @param array $matches + * @return string + */ + protected function _stripAbbreviations_callback($matches) { + $abbr_word = $matches[1]; + $abbr_desc = $matches[2]; + if ($this->abbr_word_re) { + $this->abbr_word_re .= '|'; + } + $this->abbr_word_re .= preg_quote($abbr_word); + $this->abbr_desciptions[$abbr_word] = trim($abbr_desc); + return ''; // String that will replace the block + } + + /** + * Find defined abbreviations in text and wrap them in elements. + * @param string $text + * @return string + */ + protected function doAbbreviations($text) { + if ($this->abbr_word_re) { + // cannot use the /x modifier because abbr_word_re may + // contain significant spaces: + $text = preg_replace_callback('{' . + '(?abbr_word_re . ')' . + '(?![\w\x1A])' . + '}', + array($this, '_doAbbreviations_callback'), $text); + } + return $text; + } + + /** + * Callback for processing abbreviations + * @param array $matches + * @return string + */ + protected function _doAbbreviations_callback($matches) { + $abbr = $matches[0]; + if (isset($this->abbr_desciptions[$abbr])) { + $desc = $this->abbr_desciptions[$abbr]; + if (empty($desc)) { + return $this->hashPart("$abbr"); + } else { + $desc = $this->encodeAttribute($desc); + return $this->hashPart("$abbr"); + } + } else { + return $matches[0]; + } + } +} diff --git a/vendor/michelf/php-markdown/Michelf/MarkdownInterface.inc.php b/vendor/michelf/php-markdown/Michelf/MarkdownInterface.inc.php new file mode 100644 index 0000000000..c4e9ac7f64 --- /dev/null +++ b/vendor/michelf/php-markdown/Michelf/MarkdownInterface.inc.php @@ -0,0 +1,9 @@ + + * @copyright 2004-2018 Michel Fortin + * @copyright (Original Markdown) 2004-2006 John Gruber + */ + +namespace Michelf; + +/** + * Markdown Parser Interface + */ +interface MarkdownInterface { + /** + * Initialize the parser and return the result of its transform method. + * This will work fine for derived classes too. + * + * @api + * + * @param string $text + * @return string + */ + public static function defaultTransform($text); + + /** + * Main function. Performs some preprocessing on the input text + * and pass it through the document gamut. + * + * @api + * + * @param string $text + * @return string + */ + public function transform($text); +} diff --git a/vendor/michelf/php-markdown/Readme.md b/vendor/michelf/php-markdown/Readme.md new file mode 100644 index 0000000000..c05cd93d47 --- /dev/null +++ b/vendor/michelf/php-markdown/Readme.md @@ -0,0 +1,409 @@ +PHP Markdown +============ + +PHP Markdown Lib 1.8.0 - 14 Jan 2018 + +by Michel Fortin + + +based on Markdown by John Gruber + + + +Introduction +------------ + +This is a library package that includes the PHP Markdown parser and its +sibling PHP Markdown Extra with additional features. + +Markdown is a text-to-HTML conversion tool for web writers. Markdown +allows you to write using an easy-to-read, easy-to-write plain text +format, then convert it to structurally valid XHTML (or HTML). + +"Markdown" is actually two things: a plain text markup syntax, and a +software tool, originally written in Perl, that converts the plain text +markup to HTML. PHP Markdown is a port to PHP of the original Markdown +program by John Gruber. + +* [Full documentation of the Markdown syntax]() + — Daring Fireball (John Gruber) +* [Markdown Extra syntax additions]() + — Michel Fortin + + +Requirement +----------- + +This library package requires PHP 5.3 or later. + +Note: The older plugin/library hybrid package for PHP Markdown and +PHP Markdown Extra is no longer maintained but will work with PHP 4.0.5 and +later. + +Before PHP 5.3.7, pcre.backtrack_limit defaults to 100 000, which is too small +in many situations. You might need to set it to higher values. Later PHP +releases defaults to 1 000 000, which is usually fine. + + +Usage +----- + +To use this library with Composer, first install it with: + + $ composer require michelf/php-markdown + +Then include Composer's generated vendor/autoload.php to [enable autoloading]: + + require 'vendor/autoload.php'; + +Without Composer, for autoloading to work, your project needs an autoloader +compatible with PSR-4 or PSR-0. See the included Readme.php file for a minimal +autoloader setup. (If you cannot use autoloading, see below.) + +With class autoloading in place: + + use Michelf\Markdown; + $my_html = Markdown::defaultTransform($my_text); + +Markdown Extra syntax is also available the same way: + + use Michelf\MarkdownExtra; + $my_html = MarkdownExtra::defaultTransform($my_text); + +If you wish to use PHP Markdown with another text filter function +built to parse HTML, you should filter the text *after* the `transform` +function call. This is an example with [PHP SmartyPants]: + + use Michelf\Markdown, Michelf\SmartyPants; + $my_html = Markdown::defaultTransform($my_text); + $my_html = SmartyPants::defaultTransform($my_html); + +All these examples are using the static `defaultTransform` static function +found inside the parser class. If you want to customize the parser +configuration, you can also instantiate it directly and change some +configuration variables: + + use Michelf\MarkdownExtra; + $parser = new MarkdownExtra; + $parser->fn_id_prefix = "post22-"; + $my_html = $parser->transform($my_text); + +To learn more, see the full list of [configuration variables]. + + [enable autoloading]: https://getcomposer.org/doc/01-basic-usage.md#autoloading + [PHP SmartyPants]: https://michelf.ca/projects/php-smartypants/ + [configuration variables]: https://michelf.ca/projects/php-markdown/configuration/ + + +### Usage without an autoloader + +If you cannot use class autoloading, you can still use `include` or `require` +to access the parser. To load the `Michelf\Markdown` parser, do it this way: + + require_once 'Michelf/Markdown.inc.php'; + +Or, if you need the `Michelf\MarkdownExtra` parser: + + require_once 'Michelf/MarkdownExtra.inc.php'; + +While the plain `.php` files depend on autoloading to work correctly, using the +`.inc.php` files instead will eagerly load the dependencies that would be +loaded on demand if you were using autoloading. + + +Public API and Versioning Policy +--------------------------------- + +Version numbers are of the form *major*.*minor*.*patch*. + +The public API of PHP Markdown consist of the two parser classes `Markdown` +and `MarkdownExtra`, their constructors, the `transform` and `defaultTransform` +functions and their configuration variables. The public API is stable for +a given major version number. It might get additions when the minor version +number increments. + +**Protected members are not considered public API.** This is unconventional +and deserves an explanation. Incrementing the major version number every time +the underlying implementation of something changes is going to give +nonessential version numbers for the vast majority of people who just use the +parser. Protected members are meant to create parser subclasses that behave in +different ways. Very few people create parser subclasses. I don't want to +discourage it by making everything private, but at the same time I can't +guarantee any stable hook between versions if you use protected members. + +**Syntax changes** will increment the minor number for new features, and the +patch number for small corrections. A *new feature* is something that needs a +change in the syntax documentation. Note that since PHP Markdown Lib includes +two parsers, a syntax change for either of them will increment the minor +number. Also note that there is nothing perfectly backward-compatible with the +Markdown syntax: all inputs are always valid, so new features always replace +something that was previously legal, although generally nonsensical to do. + + +Bugs +---- + +To file bug reports please send email to: + + +Please include with your report: (1) the example input; (2) the output you +expected; (3) the output PHP Markdown actually produced. + +If you have a problem where Markdown gives you an empty result, first check +that the backtrack limit is not too low by running `php --info | grep pcre`. +See Installation and Requirement above for details. + + +Development and Testing +----------------------- + +Pull requests for fixing bugs are welcome. Proposed new features are +going to be meticulously reviewed -- taking into account backward compatibility, +potential side effects, and future extensibility -- before deciding on +acceptance or rejection. + +If you make a pull request that includes changes to the parser please add +tests for what is being changed to [MDTest][] and make a pull request there +too. + + [MDTest]: https://github.com/michelf/mdtest/ + + +Donations +--------- + +If you wish to make a donation that will help me devote more time to +PHP Markdown, please visit [michelf.ca/donate] or send Bitcoin to +[1HiuX34czvVPPdhXbUAsAu7pZcesniDCGH]. + + [michelf.ca/donate]: https://michelf.ca/donate/#!Thanks%20for%20PHP%20Markdown + [1HiuX34czvVPPdhXbUAsAu7pZcesniDCGH]: bitcoin:1HiuX34czvVPPdhXbUAsAu7pZcesniDCGH + + +Version History +--------------- + +PHP Markdown Lib 1.8.0 (14 Jan 2018) + +* Autoloading with Composer now uses PSR-4. + +* HTML output for Markdown Extra footnotes now include `role` attributes + with values from [WAI-ARIA](https://www.w3.org/TR/dpub-aria/) to + make them more accessible. + (Thanks to Tobias Bengfort) + +* In Markdown Extra, added the `hashtag_protection` configuration variable. + When set to `true` it prevents ATX-style headers with no space after the initial + hash from being interpreted as headers. This way your precious hashtags + are preserved. + (Thanks to Jaussoin Timothée for the implementation.) + + +PHP Markdown Lib 1.7.0 (29 Oct 2016) + +* Added a `hard_wrap` configuration variable to make all newline characters + in the text become `
    ` tags in the HTML output. By default, according + to the standard Markdown syntax these newlines are ignored unless they a + preceded by two spaces. Thanks to Jonathan Cohlmeyer for the implementation. + +* Improved the parsing of list items to fix problematic cases that came to + light with the addition of `hard_wrap`. This should have no effect on the + output except span-level list items that ended with two spaces (and thus + ended with a line break). + +* Added a `code_span_content_func` configuration variable which takes a + function that will convert the content of the code span to HTML. This can + be useful to implement syntax highlighting. Although contrary to its + code block equivalent, there is no syntax for specifying a language. + Credits to styxit for the implementation. + +* Fixed a Markdown Extra issue where two-space-at-end-of-line hard breaks + wouldn't work inside of HTML block elements such as `

    ` + where the element expects only span-level content. + +* In the parser code, switched to PHPDoc comment format. Thanks to + Robbie Averill for the help. + + +PHP Markdown Lib 1.6.0 (23 Dec 2015) + +Note: this version was incorrectly released as 1.5.1 on Dec 22, a number +that contradicted the versioning policy. + +* For fenced code blocks in Markdown Extra, can now set a class name for the + code block's language before the special attribute block. Previously, this + class name was only allowed in the absence of the special attribute block. + +* Added a `code_block_content_func` configuration variable which takes a + function that will convert the content of the code block to HTML. This is + most useful for syntax highlighting. For fenced code blocks in Markdown + Extra, the function has access to the language class name (the one outside + of the special attribute block). Credits to Mario Konrad for providing the + implementation. + +* The curled arrow character for the backlink in footnotes is now followed + by a Unicode variant selector to prevent it from being displayed in emoji + form on iOS. + + Note that in older browsers the variant selector is often interpreted as a + separate character, making it visible after the arrow. So there is now a + also a `fn_backlink_html` configuration variable that can be used to set + the link text to something else. Credits to Dana for providing the + implementation. + +* Fixed an issue in MarkdownExtra where long header lines followed by a + special attribute block would hit the backtrack limit an cause an empty + string to be returned. + + +PHP Markdown Lib 1.5.0 (1 Mar 2015) + +* Added the ability start ordered lists with a number different from 1 and + and have that reflected in the HTML output. This can be enabled with + the `enhanced_ordered_lists` configuration variable for the Markdown + parser; it is enabled by default for Markdown Extra. + Credits to Matt Gorle for providing the implementation. + +* Added the ability to insert custom HTML attributes with simple values + everywhere an extra attribute block is allowed (links, images, headers). + The value must be unquoted, cannot contains spaces and is limited to + alphanumeric ASCII characters. + Credits to Peter Droogmans for providing the implementation. + +* Added a `header_id_func` configuration variable which takes a function + that can generate an `id` attribute value from the header text. + Credits to Evert Pot for providing the implementation. + +* Added a `url_filter_func` configuration variable which takes a function + that can rewrite any link or image URL to something different. + + +PHP Markdown Lib 1.4.1 (4 May 2014) + +* The HTML block parser will now treat `

    ` as a block-level element + (as it should) and no longer wrap it in `

    ` or parse it's content with + the as Markdown syntax (although with Extra you can use `markdown="1"` + if you wish to use the Markdown syntax inside it). + +* The content of `