/** * @ignore */ function _to_oop_tp($value) { // Only used with OOP wrapping for third-party components. if (is_array($value)) { foreach ($value as &$mapValue) { $mapValue = _to_oop_tp($mapValue); } unset($mapValue); if (!CMap::areKeysSequential($value)) { $value = oop_m($value); } else { $value = oop_a(CArray::fromPArray($value)); } return $value; } if ($value instanceof SplFixedArray) { $len = CArray::length($value); for ($i = 0; $i < $len; $i++) { $value[$i] = _to_oop_tp($value[$i]); } return oop_a($value); } return $value; }
protected static function recurseFindItems($directoryPath, $wc, $sort) { $items = self::findItems(CFilePath::add($directoryPath, $wc), $sort); $dirs = self::findDirectories(CFilePath::add($directoryPath, "*"), $sort); $dirQty = CArray::length($dirs); for ($i = 0; $i < $dirQty; $i++) { CArray::pushArray($items, self::recurseFindItems($dirs[$i], $wc, $sort)); } return $items; }
protected static function recurseFieldValidation($value, $currDepth) { if ($currDepth == self::$ms_maxRecursionDepth) { return; } $currDepth++; if (!is_collection($value)) { assert('is_cstring($value) || is_bool($value) || is_int($value) || is_float($value)', vs(isset($this), get_defined_vars())); return; } if (is_carray($value)) { $len = CArray::length($value); for ($i = 0; $i < $len; $i++) { self::recurseFieldValidation($value[$i], $currDepth); } } else { foreach ($value as $mapValue) { self::recurseFieldValidation($mapValue, $currDepth); } } }
/** * @ignore */ public static function initialize() { $configDp = CFilePath::add($GLOBALS["PHRED_PATH_TO_APP"], "Configuration"); $configEnvsDp = CFilePath::add($configDp, "Environments"); $configs = CArray::make(); $currEnv; if ($GLOBALS["PHRED_TESTS"]) { $currEnv = "tst"; } // Main configuration files. $configFps = CFile::findFiles(CFilePath::add($configDp, "*.json")); $numConfigs = CArray::length($configFps); for ($i = 0; $i < $numConfigs; $i++) { $configFp = $configFps[$i]; $configName = CFilePath::nameOnly($configFp); self::readAndAddConfig($configFp, $configName, $configs); if (!isset($currEnv) && CString::equals($configName, "Application")) { $config = CArray::last($configs); $currEnv = $config[self::$ms_configAliases["Application"]]["environment"]; } } assert('is_cstring($currEnv)', vs(isset($this), get_defined_vars())); // The configuration files from the current environment's directory. $currEnvDp = CFilePath::add($configEnvsDp, $currEnv); assert('CFile::exists($currEnvDp)', vs(isset($this), get_defined_vars())); $configFps = CFile::findFiles(CFilePath::add($currEnvDp, "*.json")); $numConfigs = CArray::length($configFps); for ($i = 0; $i < $numConfigs; $i++) { $configFp = $configFps[$i]; $configName = CFilePath::nameOnly($configFp); self::readAndAddConfig($configFp, $configName, $configs); } self::$ms_config = call_user_func_array("CMap::merge", CArray::toPArray($configs)); self::$ms_isInitialized = true; }
/** * Splits a string into substrings using a specified pattern or patterns as the delimiter(s) and returns the * resulting strings as an array. * * If no delimiter patterns were found, the resulting array contains just one element, which is the original * string. If a delimiter is located at the very start or at the very end of the string or next to another * delimiter, it will accordingly cause some string(s) in the resulting array to be empty. * * As a special case, the delimiter pattern can be empty, which will split the string into its constituting * characters. * * @param string $string The string to be split. * @param string|array|map $delimiterPatternOrPatterns The pattern or array of patterns to be recognized as the * delimiter(s). * * @return CArray The resulting strings. */ public static function split($string, $delimiterPatternOrPatterns) { assert('is_cstring($string) && (is_cstring($delimiterPatternOrPatterns) || ' . 'is_collection($delimiterPatternOrPatterns))', vs(isset($this), get_defined_vars())); if (is_cstring($delimiterPatternOrPatterns)) { $numIdt = self::findGroups($delimiterPatternOrPatterns, "/^([^0-9A-Za-z\\s\\\\])(.*)\\1/", $foundGroups); assert('$numIdt == 2', vs(isset($this), get_defined_vars())); $idt = $foundGroups[1]; if (CString::isEmpty($idt)) { // Special case. if (CString::isEmpty($string)) { $resStrings = CArray::fromElements(""); return $resStrings; } else { if (preg_match("/^([^0-9A-Za-z\\s\\\\])\\1[A-Za-z]*u[A-Za-z]*\\z/", $delimiterPatternOrPatterns) !== 1) { $resStrings = CArray::make(strlen($string)); for ($i = 0; $i < strlen($string); $i++) { $resStrings[$i] = $string[$i]; } return $resStrings; } else { return CUString::splitIntoChars($string); } } } $paResStrings = preg_split($delimiterPatternOrPatterns, $string); $qty = count($paResStrings); $resStrings = CArray::make($qty); for ($i = 0; $i < $qty; $i++) { $resStrings[$i] = $paResStrings[$i]; } return $resStrings; } else { $resStrings = CArray::fromElements($string); foreach ($delimiterPatternOrPatterns as $delimiterPattern) { assert('is_cstring($delimiterPattern)', vs(isset($this), get_defined_vars())); $resStringsNew = CArray::make(); $len = CArray::length($resStrings); for ($i = 0; $i < $len; $i++) { CArray::pushArray($resStringsNew, self::split($resStrings[$i], $delimiterPattern)); } $resStrings = $resStringsNew; } return $resStrings; } }
/** * Determines if the keys in a map are all integer and sequential. * * Sequential keys are a sequence of integers that start with a `0` and go up, incrementing exactly by one. * * This method could be useful to see if a PHP's associative array (a map) can be naturally converted into a * regular array (SplFixedArray) when dealing with interfaces that are using the PHP's associative array in the * role of a regular array. * * As a special case, the method returns `true` for an empty map. * * @param map $map The map to be looked into. * * @return bool `true` if all keys in the map are integer and sequential, `false` otherwise. */ public static function areKeysSequential($map) { assert('is_cmap($map)', vs(isset($this), get_defined_vars())); $map = parray($map); $keys = self::keys($map); $len = CArray::length($keys); for ($i = 0; $i < $len; $i++) { if (!is_int($keys[$i]) || $keys[$i] != $i) { return false; } } return true; }
/** * Normalizes a path by removing any trailing slashes, any redundant slashes, any references to the current * directory, and any references to the parent directory where possible, and returns the new path. * * For example, "/path//./dir-a/.././to//../dir-b/" is normalized to "/path/dir-b". * * @param string $path The path to be normalized (can be absolute or relative). * @param bool $targetIsExecutable **OPTIONAL. Default is** `false`. Tells whether the path's target should be * treated as an executable so that, if the path starts with ".", the resulting path will start with "." too and * the "." will not be removed as a reference to the current directory. * * @return CUStringObject The normalized path. */ public static function normalize($path, $targetIsExecutable = false) { assert('is_cstring($path) && is_bool($targetIsExecutable)', vs(isset($this), get_defined_vars())); assert('!CString::isEmpty($path)', vs(isset($this), get_defined_vars())); $path = CRegex::replace($path, "/\\/{2,}/", "/"); // normalize consecutive slashes $path = CString::stripEnd($path, "/"); // remove the trailing slash, if any if (CString::isEmpty($path)) { return "/"; } $path = CRegex::remove($path, "/\\/\\.(?=\\/|\\z)/"); // remove any "/." followed by a slash or at the end if (CString::isEmpty($path)) { return "/"; } if (!$targetIsExecutable) { $path = CString::stripStart($path, "./"); } $pathIsAbsolute; if (!CString::startsWith($path, "/")) { $pathIsAbsolute = false; } else { $pathIsAbsolute = true; $path = CString::substr($path, 1); } if (!CString::find($path, "/")) { if ($pathIsAbsolute) { if (!CString::equals($path, "..")) { $path = "/{$path}"; } else { $path = "/"; } } return $path; } // Recompose the path. $components = CString::split($path, "/"); $newComponents = CArray::make(); $len = CArray::length($components); for ($i = 0; $i < $len; $i++) { $comp = $components[$i]; $lastAddedComp = ""; $noCompsAddedYet = CArray::isEmpty($newComponents); if (!$noCompsAddedYet) { $lastAddedComp = CArray::last($newComponents); } if (CString::equals($comp, "..")) { if ($noCompsAddedYet || CString::equals($lastAddedComp, "..") || CString::equals($lastAddedComp, ".")) { if (!($noCompsAddedYet && $pathIsAbsolute)) { CArray::push($newComponents, $comp); } } else { CArray::pop($newComponents); } } else { CArray::push($newComponents, $comp); } } $path = CArray::join($newComponents, "/"); if ($pathIsAbsolute) { $path = "/{$path}"; } else { if (CString::isEmpty($path)) { $path = "."; } } return $path; }
protected static function recurseValueBeforeEncoding($value, $currDepth) { if ($currDepth == self::$ms_maxRecursionDepth) { return $value; } $currDepth++; if (is_cstring($value)) { return $value; } if (is_cmap($value)) { $value = parray($value); foreach ($value as &$valueInMap) { $valueInMap = self::recurseValueBeforeEncoding($valueInMap, $currDepth); } unset($valueInMap); $value = (object) $value; } else { if (is_carray($value)) { $value = splarray($value); $len = CArray::length($value); for ($i = 0; $i < $len; $i++) { $value[$i] = self::recurseValueBeforeEncoding($value[$i], $currDepth); } $value = CArray::toPArray($value); } } return $value; }
protected static function recurseValueBeforeFiltering($value, $inputFilterOrFilterCollection, &$success, $currDepth) { assert('$inputFilterOrFilterCollection instanceof CInputFilter || ' . 'is_collection($inputFilterOrFilterCollection)', vs(isset($this), get_defined_vars())); if ($currDepth == self::$ms_maxRecursionDepth) { $success = false; return; } $currDepth++; if (!is_cmap($value)) { // Only interested in PHP arrays. return $value; } if (is_carray($inputFilterOrFilterCollection)) { // The output value is expected to be a CArray; the keys in the arrived PHP array should be sequential. if (!CMap::areKeysSequential($value)) { $success = false; return; } $value = CArray::fromPArray($value); $len = CArray::length($value); if ($len != CArray::length($inputFilterOrFilterCollection)) { $success = false; return; } for ($i = 0; $i < $len; $i++) { $inputValue = $value[$i]; $inputFilterElement = $inputFilterOrFilterCollection[$i]; $inputValue = self::recurseValueBeforeFiltering($inputValue, $inputFilterElement, $success, $currDepth); if (!$success) { return; } $value[$i] = $inputValue; } } else { if (is_cmap($inputFilterOrFilterCollection)) { // The output value is expected to be a CMap; already got one. foreach ($value as $inputKey => &$inputValue) { if (!CMap::hasKey($inputFilterOrFilterCollection, $inputKey)) { $success = false; return; } $inputFilterElement = $inputFilterOrFilterCollection[$inputKey]; $inputValue = self::recurseValueBeforeFiltering($inputValue, $inputFilterElement, $success, $currDepth); if (!$success) { return; } } unset($inputValue); } else { $success = false; return; } } return $value; }
public function testSplit() { // ASCII. $res = CRegex::split("He,llo;th,ere!", "/[,;]/"); $this->assertTrue(CArray::length($res) == 4 && CString::equals($res[0], "He") && CString::equals($res[1], "llo") && CString::equals($res[2], "th") && CString::equals($res[3], "ere!")); $res = CRegex::split("He,llo;th.ere!", CArray::fromElements("/[,;]/", "/\\./")); $this->assertTrue(CArray::length($res) == 4 && CString::equals($res[0], "He") && CString::equals($res[1], "llo") && CString::equals($res[2], "th") && CString::equals($res[3], "ere!")); // Special cases. $res = CRegex::split("", "/[,;]/"); $this->assertTrue(CArray::length($res) == 1 && CString::equals($res[0], "")); $res = CRegex::split("Hey", "//"); $this->assertTrue(CArray::length($res) == 3 && CString::equals($res[0], "H") && CString::equals($res[1], "e") && CString::equals($res[2], "y")); $res = CRegex::split("", "//"); $this->assertTrue(CArray::length($res) == 1 && CString::equals($res[0], "")); // Unicode. $res = CRegex::split("¡He,llo·se,ñor!", "/[,·]/u"); $this->assertTrue(CArray::length($res) == 4 && CUString::equals($res[0], "¡He") && CUString::equals($res[1], "llo") && CUString::equals($res[2], "se") && CUString::equals($res[3], "ñor!")); $res = CRegex::split("¡He,llo·se.ñor!", CArray::fromElements("/[,·]/u", "/\\./u")); $this->assertTrue(CArray::length($res) == 4 && CUString::equals($res[0], "¡He") && CUString::equals($res[1], "llo") && CUString::equals($res[2], "se") && CUString::equals($res[3], "ñor!")); // Special cases. $res = CRegex::split("", "/[,·]/u"); $this->assertTrue(CArray::length($res) == 1 && CUString::equals($res[0], "")); $res = CRegex::split("Héy", "//u"); $this->assertTrue(CArray::length($res) == 3 && CUString::equals($res[0], "H") && CUString::equals($res[1], "é") && CUString::equals($res[2], "y")); $res = CRegex::split("", "//u"); $this->assertTrue(CArray::length($res) == 1 && CUString::equals($res[0], "")); }
/** * Splits a string into substrings using a specified substring or substrings as the delimiter(s) and returns the * resulting strings as an array. * * If no delimiter substrings were found, the resulting array contains just one element, which is the original * string. If a delimiter is located at the very start or at the very end of the string or next to another * delimiter, it will accordingly cause some string(s) in the resulting array to be empty. * * As a special case, the delimiter substring can be empty, which will split the string into its constituting * characters. * * @param string $string The string to be split. * @param string|array|map $delimiterOrDelimiters The substring or array of substrings to be recognized as the * delimiter(s). * * @return CArray The resulting strings. */ public static function split($string, $delimiterOrDelimiters) { assert('is_cstring($string) && ' . '(is_cstring($delimiterOrDelimiters) || is_collection($delimiterOrDelimiters))', vs(isset($this), get_defined_vars())); if (is_cstring($delimiterOrDelimiters)) { if (self::isEmpty($delimiterOrDelimiters)) { // Special case. if (self::isEmpty($string)) { $resStrings = CArray::fromElements(""); return $resStrings; } else { $resStrings = CArray::make(strlen($string)); for ($i = 0; $i < strlen($string); $i++) { $resStrings[$i] = $string[$i]; } return $resStrings; } } $resStrings = CArray::make(self::numSubstrings($string, $delimiterOrDelimiters) + 1); $startPos = 0; $i = 0; while (true) { $endPos = self::indexOf($string, $delimiterOrDelimiters, $startPos); if ($endPos != -1) { $resStrings[$i++] = self::substring($string, $startPos, $endPos); $startPos = $endPos + strlen($delimiterOrDelimiters); } else { $resStrings[$i] = self::substr($string, $startPos); break; } } return $resStrings; } else { $resStrings = CArray::fromElements($string); foreach ($delimiterOrDelimiters as $delimiter) { assert('is_cstring($delimiter)', vs(isset($this), get_defined_vars())); $resStringsNew = CArray::make(); $len = CArray::length($resStrings); for ($i = 0; $i < $len; $i++) { CArray::pushArray($resStringsNew, self::split($resStrings[$i], $delimiter)); } $resStrings = $resStringsNew; } return $resStrings; } }
/** * Determines if a locale name is valid and known. * * Scripts, variants, and keyword-value pairs are ignored. * * @param string $localeName The locale name to be looked into. * * @return bool `true` if the locale name is valid and known, `false` otherwise. */ public static function isValid($localeName) { assert('is_cstring($localeName)', vs(isset($this), get_defined_vars())); if (!CRegex::findGroups($localeName, "/^([a-z]{2,3}(?![^_\\-]))(?|[_\\-]([a-z]{2,3}(?![^_\\-]))|[_\\-][a-z]{4}(?![^_\\-])[_\\-]([a-z]{2,3}" . "(?![^_\\-]))|(?:\\z|[_\\-][a-z])).*\\z(?<=[a-z0-9])/i", $foundGroups)) { return false; } $rfc2616 = $foundGroups[0]; if (CArray::length($foundGroups) > 1) { $rfc2616 .= "-" . $foundGroups[1]; } return is_cstring(Locale::acceptFromHttp($rfc2616)); }
public function testFindBinary() { $array = CArray::fromElements("oua", "vnf", "fnf", "aod", "tvi", "nbt", "jny", "vor", "rfd", "cvm", "hyh", "kng", "ggo", "uea", "hkb", "qbk", "xla", "uod", "jzi", "chw", "ssy", "olr", "bzl", "oux", "ltk", "bah", "khu", "msr", "pqv", "npb", "mtb", "eku", "vcv", "vbv", "wuo", "lrw", "bkw", "ezz", "jtc", "dwk", "dsq", "kzu", "oey", "vbi", "seh", "klz", "asj", "gzg", "ccs", "qop"); $arrayOrig = CArray::makeCopy($array); $len = CArray::length($arrayOrig); // Sort the array first. CArray::sort($array, CComparator::ORDER_ASC); // Using the default comparators. for ($i = 0; $i < $len; $i += 3) { $string = $arrayOrig[$i]; $foundAtPos0; CArray::find($array, $string, CComparator::EQUALITY, $foundAtPos0); $foundAtPos1; $found = CArray::findBinary($array, $string, CComparator::ORDER_ASC, $foundAtPos1); $this->assertTrue($found); $this->assertTrue($foundAtPos1 == $foundAtPos0); } // Using custom comparators. $comparatorEquality = function ($string0, $string1) { return CString::toLowerCase($string0) === CString::toLowerCase($string1); }; $comparatorOrderAsc = function ($string0, $string1) { return CString::compare(CString::toLowerCase($string0), CString::toLowerCase($string1)); }; for ($i = 0; $i < $len; $i += 5) { $string = CString::toUpperCase($arrayOrig[$i]); $foundAtPos0; CArray::find($array, $string, $comparatorEquality, $foundAtPos0); $foundAtPos1; $found = CArray::findBinary($array, $string, $comparatorOrderAsc, $foundAtPos1); $this->assertTrue($found); $this->assertTrue($foundAtPos1 == $foundAtPos0); } // Special cases. $array = CArray::fromElements("a", "b"); $found = CArray::findBinary($array, "a"); $this->assertTrue($found); $found = CArray::findBinary($array, "b"); $this->assertTrue($found); $found = CArray::findBinary($array, "c"); $this->assertFalse($found); $array = CArray::fromElements("a"); $found = CArray::findBinary($array, "a"); $this->assertTrue($found); $array = CArray::make(); $found = CArray::findBinary($array, "a"); $this->assertFalse($found); }
public function leaveNode(PhpParser\Node $node) { if ($node->hasAttribute("_insertGetMMethodAfterMe") || $node->hasAttribute("_insertSetMMethodAfterMe")) { $statements = [$node]; if ($node->hasAttribute("_insertGetMMethodAfterMe")) { $subStatements = CMap::make(); $len = CArray::length($this->m_propsToWrap); for ($i = 0; $i < $len; $i++) { $propName = $this->m_propsToWrap[$i]; $subCondition = new PhpParser\Node\Expr\BooleanNot(new PhpParser\Node\Expr\FuncCall(new PhpParser\Node\Name(self::$ms_isFwCallFuncName))); $return0 = new PhpParser\Node\Stmt\Return_(new PhpParser\Node\Expr\PropertyFetch(new PhpParser\Node\Expr\Variable("this"), $propName)); $return1 = new PhpParser\Node\Stmt\Return_(new PhpParser\Node\Expr\FuncCall(new PhpParser\Node\Name(self::$ms_toOopFuncName), [new PhpParser\Node\Expr\PropertyFetch(new PhpParser\Node\Expr\Variable("this"), $propName)])); $else = new PhpParser\Node\Stmt\Else_([$return1]); $subIf = new PhpParser\Node\Stmt\If_($subCondition, ["stmts" => [$return0], "else" => $else]); $condition = new PhpParser\Node\Expr\BinaryOp\Identical(new PhpParser\Node\Expr\Variable("name"), new PhpParser\Node\Scalar\String($propName)); $if = new PhpParser\Node\Stmt\If_($condition, ["stmts" => [$subIf]]); CMap::insertValue($subStatements, $if); } $method = new PhpParser\Node\Stmt\ClassMethod("__get", ["type" => PhpParser\Node\Stmt\Class_::MODIFIER_PUBLIC, "byRef" => true, "params" => [new PhpParser\Node\Param("name")], "stmts" => $subStatements]); CMap::insertValue($statements, $method); } if ($node->hasAttribute("_insertSetMMethodAfterMe")) { $subStatements = CMap::make(); $len = CArray::length($this->m_propsToWrap); for ($i = 0; $i < $len; $i++) { $propName = $this->m_propsToWrap[$i]; $subCondition = new PhpParser\Node\Expr\BooleanNot(new PhpParser\Node\Expr\FuncCall(new PhpParser\Node\Name(self::$ms_isFwCallFuncName))); $assignment0 = new PhpParser\Node\Expr\Assign(new PhpParser\Node\Expr\PropertyFetch(new PhpParser\Node\Expr\Variable("this"), $propName), new PhpParser\Node\Expr\Variable("value")); $assignment1 = new PhpParser\Node\Expr\Assign(new PhpParser\Node\Expr\PropertyFetch(new PhpParser\Node\Expr\Variable("this"), $propName), new PhpParser\Node\Expr\FuncCall(new PhpParser\Node\Name(self::$ms_fromOopFuncName), [new PhpParser\Node\Expr\Variable("value")])); $else = new PhpParser\Node\Stmt\Else_([$assignment1]); $subIf = new PhpParser\Node\Stmt\If_($subCondition, ["stmts" => [$assignment0], "else" => $else]); $condition = new PhpParser\Node\Expr\BinaryOp\Identical(new PhpParser\Node\Expr\Variable("name"), new PhpParser\Node\Scalar\String($propName)); $if = new PhpParser\Node\Stmt\If_($condition, ["stmts" => [$subIf]]); CMap::insertValue($subStatements, $if); } $method = new PhpParser\Node\Stmt\ClassMethod("__set", ["type" => PhpParser\Node\Stmt\Class_::MODIFIER_PUBLIC, "params" => [new PhpParser\Node\Param("name"), new PhpParser\Node\Param("value")], "stmts" => $subStatements]); CMap::insertValue($statements, $method); } return $statements; } }
/** * Sends a message to the recipient(s). * * @param reference $failedAddresses **OPTIONAL. OUTPUT.** After the method is called with this parameter * provided, the parameter's value, which is of type `CArrayObject`, is an array containing the email addresses of * the recipients who failed to receive the message. * * @return int The number of recipients who have successfully received the message. */ public function send(&$failedAddresses = null) { assert('isset($this->m_swiftMailer) && isset($this->m_swiftMessage)', vs(isset($this), get_defined_vars())); assert('(isset($this->m_from) || isset($this->m_sender) || isset($this->m_returnAddress)) && ' . '(isset($this->m_to) || isset($this->m_cc) || isset($this->m_bcc))', vs(isset($this), get_defined_vars())); $message = $this->m_swiftMessage; if (isset($this->m_from)) { $message->setFrom($this->m_from); } if (isset($this->m_to)) { $message->setTo($this->m_to); } if (isset($this->m_cc)) { $message->setCc($this->m_cc); } if (isset($this->m_bcc)) { $message->setBcc($this->m_bcc); } if (isset($this->m_sender)) { $message->setSender($this->m_sender); } if (isset($this->m_returnAddress)) { $message->setReturnPath($this->m_returnAddress); } if (isset($this->m_replyAddress)) { $message->setReplyTo($this->m_replyAddress); } if (isset($this->m_body)) { if (CString::equals($this->m_bodyType, CMimeType::PLAIN_TEXT)) { $this->m_body = $this->maybeWrapText($this->m_body); } $message->setBody($this->m_body, $this->m_bodyType); } if (isset($this->m_altBodiesAndTypes)) { $len = CArray::length($this->m_altBodiesAndTypes); for ($i = 0; $i < $len; $i++) { $bodyAndType = $this->m_altBodiesAndTypes[$i]; $body = $bodyAndType[0]; $type = $bodyAndType[1]; if (CString::equals($type, CMimeType::PLAIN_TEXT)) { $body = $this->maybeWrapText($body); } $message->addPart($body, $type); } } $paFailedAddresses; $res = $this->m_swiftMailer->send($message, $paFailedAddresses); if (is_cmap($paFailedAddresses)) { $failedAddresses = oop_a(CArray::fromPArray($paFailedAddresses)); } $res = is_int($res) ? $res : 0; return $res; }
/** * Composes a URL path into a string ready to be used as a part of a URL and returns it. * * Any characters that cannot be represented literally in a valid path part of a URL come out percent-encoded. The * resulting path always starts with "/". * * Because the characters in path components are stored in their literal representations, the resulting path string * is always normalized, with only those characters appearing percent-encoded that really require it for the path * string to be valid and with the hexadecimal letters in percent-encoded characters appearing uppercased. * * @return CUStringObject A string containing the URL path. */ public function pathString() { $components = CArray::makeCopy($this->m_components); $len = CArray::length($components); for ($i = 0; $i < $len; $i++) { $components[$i] = CUrl::enterTdNew($components[$i]); } return "/" . CArray::join($components, "/"); }
protected static function recurseCollectionFiltering($inputCollection, $filterOrFilterCollection, &$success, $currDepth) { assert('is_a($filterOrFilterCollection, get_called_class()) || is_collection($filterOrFilterCollection)', vs(isset($this), get_defined_vars())); if ($currDepth == self::$ms_maxRecursionDepth) { $success = false; return; } $currDepth++; if (is_carray($inputCollection)) { if (!is_carray($filterOrFilterCollection)) { $success = false; return; } $len = CArray::length($inputCollection); if ($len != CArray::length($filterOrFilterCollection)) { $success = false; return; } for ($i = 0; $i < $len; $i++) { $inputValue = $inputCollection[$i]; $filterElement = $filterOrFilterCollection[$i]; if (!is_collection($inputValue)) { $strInputValue = self::collectionElementToString($inputValue, $success); if (!$success) { return; } if (!is_a($filterElement, get_called_class())) { $success = false; return; } $inputValue = $filterElement->filter($strInputValue, $success); if (!$success) { return; } } else { $inputValue = self::recurseCollectionFiltering($inputValue, $filterElement, $success, $currDepth); if (!$success) { return; } } $inputCollection[$i] = $inputValue; } } else { if (!is_cmap($filterOrFilterCollection)) { $success = false; return; } foreach ($inputCollection as $inputKey => &$inputValue) { if (!CMap::hasKey($filterOrFilterCollection, $inputKey)) { $success = false; return; } $filterElement = $filterOrFilterCollection[$inputKey]; if (!is_collection($inputValue)) { $strInputValue = self::collectionElementToString($inputValue, $success); if (!$success) { return; } if (!is_a($filterElement, get_called_class())) { $success = false; return; } $inputValue = $filterElement->filter($strInputValue, $success); if (!$success) { return; } } else { $inputValue = self::recurseCollectionFiltering($inputValue, $filterElement, $success, $currDepth); if (!$success) { return; } } } unset($inputValue); } return $inputCollection; }
protected function addHeaderWithoutOverriding($headers, $headerName, $value) { $headerLine; $headerName = CString::trim($headerName); $value = CString::trim($value); $foundHeaderPos; $alreadyExists = CArray::find($headers, $headerName, function ($element0, $element1) { return CRegex::find($element0, "/^\\h*" . CRegex::enterTd($element1) . "\\h*:/i"); }, $foundHeaderPos); if (!$alreadyExists) { $headerLine = "{$headerName}: {$value}"; } else { // The header already exists. Combine the header values, removing duplicates based on case-insensitive // equality. $currValue = CRegex::remove($headers[$foundHeaderPos], "/^.*?:\\h*/"); CArray::remove($headers, $foundHeaderPos); $values = CString::split("{$currValue}, {$value}", ","); $len = CArray::length($values); for ($i = 0; $i < $len; $i++) { $values[$i] = CString::trim($values[$i]); } $values = CArray::filter($values, function ($element) { return !CString::isEmpty($element); }); $values = CArray::unique($values, function ($element0, $element1) { return CString::equalsCi($element0, $element1); }); $combinedValue = CArray::join($values, ", "); $headerLine = "{$headerName}: {$combinedValue}"; } CArray::push($headers, $headerLine); }
/** * Starts a session by sending out the added requests. * * @param reference $success **OPTIONAL. OUTPUT.** After the method is called with this parameter provided, the * parameter's value tells whether the session was successful. * * @return void */ public function start(&$success = null) { $success = true; if ($this->m_hasError) { $success = false; return; } if (CArray::isEmpty($this->m_requestRecordsQueue)) { // Nothing to do. return; } // Current policy is to disable HTTP pipelining. $res = curl_multi_setopt($this->m_multiCurl, CURLMOPT_PIPELINING, 0); if (!$res) { // Should never get in here as long as cURL options are being set correctly, hence the assertion. assert('false', vs(isset($this), get_defined_vars())); $this->m_hasError = true; $this->m_errorMessage = "The 'curl_multi_setopt' function failed."; $success = false; $this->finalize(); return; } $anySuccessfulRequests = false; // Disable the script's execution timeout before getting into the session. $timeoutPause = new CTimeoutPause(); $numRunningRequests = 0; // also the index of the next request to send while (true) { // From the request queue, add as many normal cURL handles to the multi cURL handle as it is allowed by the // maximum number of concurrent requests, priorly setting internal options for every request. while ($numRunningRequests < CArray::length($this->m_requestRecordsQueue) && $numRunningRequests < $this->m_maxNumConcurrentRequests) { $requestRecord = $this->m_requestRecordsQueue[$numRunningRequests]; $request = $requestRecord[0]; $onCompleteCallback = $requestRecord[1]; $newCookieSession = $requestRecord[2]; $requestCurl = $request->curl(); // Set cURL options for the normal cURL handle, having created a temporary file for cookie storage if // needed. $requestSetOptSuccess; if ($this->m_cookiesAreEnabled && $request->isHttp()) { if (!isset($this->m_cookiesFp)) { $this->m_cookiesFp = CFile::createTemporary(); } $request->setInternalOptions($requestSetOptSuccess, $this->m_cookiesFp, $newCookieSession); } else { $request->setInternalOptions($requestSetOptSuccess); } if (!$requestSetOptSuccess) { if (isset($onCompleteCallback)) { call_user_func($onCompleteCallback, false, "", $request, $this); } CArray::remove($this->m_requestRecordsQueue, $numRunningRequests); continue; } // Add the normal cURL handle to the multi cURL handle. $res = curl_multi_add_handle($this->m_multiCurl, $requestCurl); if ($res != 0) { $this->m_hasError = true; $curlError = curl_multi_strerror($res); $this->m_errorMessage = is_cstring($curlError) && !CString::isEmpty($curlError) ? $curlError : "The 'curl_multi_add_handle' function failed."; $success = false; $timeoutPause->end(); $this->finalize(); return; } $numRunningRequests++; } if ($numRunningRequests == 0) { break; } // Process the currently added requests until complete or no more data is available. Although // `CURLM_CALL_MULTI_PERFORM` is deprecated since libcurl 7.20, keep it for compatibility reasons. $numRunningTransfers; do { $multiExecRes = curl_multi_exec($this->m_multiCurl, $numRunningTransfers); } while ($multiExecRes == CURLM_CALL_MULTI_PERFORM); if ($multiExecRes != CURLM_OK) { $this->m_hasError = true; $curlError = curl_multi_strerror($multiExecRes); $this->m_errorMessage = is_cstring($curlError) && !CString::isEmpty($curlError) ? $curlError : "The 'curl_multi_exec' function failed."; $success = false; $timeoutPause->end(); $this->finalize(); return; } // Check for completed requests, call the callback function for any completed one (if such a function is // defined), finalize completed requests, and remove completed requests from the queue. while (true) { $completedRequestInfo = curl_multi_info_read($this->m_multiCurl); if (!is_cmap($completedRequestInfo)) { break; } // A request has completed. assert('$completedRequestInfo["msg"] == CURLMSG_DONE', vs(isset($this), get_defined_vars())); $requestCurl = $completedRequestInfo["handle"]; $requestRes = $completedRequestInfo["result"]; $requestRecordPos; $found = CArray::find($this->m_requestRecordsQueue, $requestCurl, function ($requestRecord, $requestCurl) { $request = $requestRecord[0]; return $request->curl() == $requestCurl; }, $requestRecordPos); assert('$found', vs(isset($this), get_defined_vars())); $requestRecord = $this->m_requestRecordsQueue[$requestRecordPos]; $request = $requestRecord[0]; $onCompleteCallback = $requestRecord[1]; // Remove the normal cURL handle from the multi cURL handle. $res = curl_multi_remove_handle($this->m_multiCurl, $requestCurl); if ($res != 0) { $this->m_hasError = true; $curlError = curl_multi_strerror($res); $this->m_errorMessage = is_cstring($curlError) && !CString::isEmpty($curlError) ? $curlError : "The 'curl_multi_remove_handle' function failed."; $success = false; $timeoutPause->end(); $this->finalize(); return; } if ($requestRes == CURLE_OK) { // The request has succeeded. if (isset($onCompleteCallback)) { $response; if ($request->isReturnTransferSet()) { $response = curl_multi_getcontent($requestCurl); assert('is_cstring($response)', vs(isset($this), get_defined_vars())); } else { $response = ""; } $request->onRequestCompleteOk(); // also close the normal cURL handle call_user_func($onCompleteCallback, true, $response, $request, $this); } else { $request->onRequestCompleteOk(); // also close the normal cURL handle } $anySuccessfulRequests = true; } else { // The request has failed. $curlError = curl_strerror($requestRes); if (!is_cstring($curlError)) { $curlError = ""; } $request->onRequestCompleteWithError($curlError); // also close the normal cURL handle if (isset($onCompleteCallback)) { call_user_func($onCompleteCallback, false, "", $request, $this); } } CArray::remove($this->m_requestRecordsQueue, $requestRecordPos); $numRunningRequests--; } assert('$numRunningRequests == $numRunningTransfers', vs(isset($this), get_defined_vars())); if ($numRunningTransfers > 0) { // Some requests are still being processed (by remote machines). Wait for more data to appear on // sockets, without getting hard on the CPU. do { $multiSelectRes = curl_multi_select($this->m_multiCurl); } while ($multiSelectRes == -1); } else { // No requests are being processed. Check if any requests are pending. if (CArray::isEmpty($this->m_requestRecordsQueue)) { // No requests are pending. break; } } } // Set the script's execution time limit like the session has never happened. $timeoutPause->end(); if (!$anySuccessfulRequests) { $this->m_hasError = true; $this->m_errorMessage = "None of the session's requests succeeded."; $success = false; } $this->finalize(); }