diff options
author | Ludovic Pouzenc <ludovic@pouzenc.fr> | 2012-08-02 11:09:40 +0000 |
---|---|---|
committer | Ludovic Pouzenc <ludovic@pouzenc.fr> | 2012-08-02 11:09:40 +0000 |
commit | 6dfd5d507d9863f987b30b0a5ab4268aea2ed875 (patch) | |
tree | 9c3de66b4aaa1e6bfa3c6442d807ec70bc479d11 /poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility | |
parent | f4792ba1a7785220fef5adb1cb3e7ce8ac40152f (diff) | |
download | 2012-php-weave-6dfd5d507d9863f987b30b0a5ab4268aea2ed875.tar.gz 2012-php-weave-6dfd5d507d9863f987b30b0a5ab4268aea2ed875.tar.bz2 2012-php-weave-6dfd5d507d9863f987b30b0a5ab4268aea2ed875.zip |
J'étais parti sur un download pourri de Cake. Les gars on abusé sur GitHub.
git-svn-id: file:///var/svn/2012-php-weave/trunk@7 d972a294-176a-4cf9-8ea1-fcd5b0c30f5c
Diffstat (limited to 'poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility')
15 files changed, 9213 insertions, 0 deletions
diff --git a/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/CakeNumber.php b/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/CakeNumber.php new file mode 100644 index 0000000..3b21cbc --- /dev/null +++ b/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/CakeNumber.php @@ -0,0 +1,296 @@ +<?php +/** + * CakeNumber Utility. + * + * Methods to make numbers more readable. + * + * PHP 5 + * + * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) + * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * Redistributions of files must retain the above copyright notice. + * + * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://cakephp.org CakePHP(tm) Project + * @package Cake.Utility + * @since CakePHP(tm) v 0.10.0.1076 + * @license MIT License (http://www.opensource.org/licenses/mit-license.php) + */ + +/** + * Number helper library. + * + * Methods to make numbers more readable. + * + * @package Cake.Utility + * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/number.html + */ +class CakeNumber { + +/** + * Currencies supported by the helper. You can add additional currency formats + * with CakeNumber::addFormat + * + * @var array + */ + protected static $_currencies = array( + 'USD' => array( + 'wholeSymbol' => '$', 'wholePosition' => 'before', 'fractionSymbol' => 'c', 'fractionPosition' => 'after', + 'zero' => 0, 'places' => 2, 'thousands' => ',', 'decimals' => '.', 'negative' => '()', 'escape' => true + ), + 'GBP' => array( + 'wholeSymbol' => '£', 'wholePosition' => 'before', 'fractionSymbol' => 'p', 'fractionPosition' => 'after', + 'zero' => 0, 'places' => 2, 'thousands' => ',', 'decimals' => '.', 'negative' => '()','escape' => false + ), + 'EUR' => array( + 'wholeSymbol' => '€', 'wholePosition' => 'before', 'fractionSymbol' => false, 'fractionPosition' => 'after', + 'zero' => 0, 'places' => 2, 'thousands' => '.', 'decimals' => ',', 'negative' => '()', 'escape' => false + ) + ); + +/** + * Default options for currency formats + * + * @var array + */ + protected static $_currencyDefaults = array( + 'wholeSymbol' => '', 'wholePosition' => 'before', 'fractionSymbol' => '', 'fractionPosition' => 'after', + 'zero' => '0', 'places' => 2, 'thousands' => ',', 'decimals' => '.','negative' => '()', 'escape' => true, + ); + +/** + * If native number_format() should be used. If >= PHP5.4 + * + * @var boolean + */ + protected static $_numberFormatSupport = null; + +/** + * Formats a number with a level of precision. + * + * @param float $number A floating point number. + * @param integer $precision The precision of the returned number. + * @return float Formatted float. + * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/number.html#NumberHelper::precision + */ + public static function precision($number, $precision = 3) { + return sprintf("%01.{$precision}F", $number); + } + +/** + * Returns a formatted-for-humans file size. + * + * @param integer $size Size in bytes + * @return string Human readable size + * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/number.html#NumberHelper::toReadableSize + */ + public static function toReadableSize($size) { + switch (true) { + case $size < 1024: + return __dn('cake', '%d Byte', '%d Bytes', $size, $size); + case round($size / 1024) < 1024: + return __d('cake', '%d KB', self::precision($size / 1024, 0)); + case round($size / 1024 / 1024, 2) < 1024: + return __d('cake', '%.2f MB', self::precision($size / 1024 / 1024, 2)); + case round($size / 1024 / 1024 / 1024, 2) < 1024: + return __d('cake', '%.2f GB', self::precision($size / 1024 / 1024 / 1024, 2)); + default: + return __d('cake', '%.2f TB', self::precision($size / 1024 / 1024 / 1024 / 1024, 2)); + } + } + +/** + * Formats a number into a percentage string. + * + * @param float $number A floating point number + * @param integer $precision The precision of the returned number + * @return string Percentage string + * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/number.html#NumberHelper::toPercentage + */ + public static function toPercentage($number, $precision = 2) { + return self::precision($number, $precision) . '%'; + } + +/** + * Formats a number into a currency format. + * + * @param float $number A floating point number + * @param integer $options if int then places, if string then before, if (,.-) then use it + * or array with places and before keys + * @return string formatted number + * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/number.html#NumberHelper::format + */ + public static function format($number, $options = false) { + $places = 0; + if (is_int($options)) { + $places = $options; + } + + $separators = array(',', '.', '-', ':'); + + $before = $after = null; + if (is_string($options) && !in_array($options, $separators)) { + $before = $options; + } + $thousands = ','; + if (!is_array($options) && in_array($options, $separators)) { + $thousands = $options; + } + $decimals = '.'; + if (!is_array($options) && in_array($options, $separators)) { + $decimals = $options; + } + + $escape = true; + if (is_array($options)) { + $options = array_merge(array('before' => '$', 'places' => 2, 'thousands' => ',', 'decimals' => '.'), $options); + extract($options); + } + + $out = $before . self::_numberFormat($number, $places, $decimals, $thousands) . $after; + + if ($escape) { + return h($out); + } + return $out; + } + +/** + * Alternative number_format() to accommodate multibyte decimals and thousands < PHP 5.4 + * + * @param float $number + * @param integer $places + * @param string $decimals + * @param string $thousands + * @return string + */ + protected static function _numberFormat($number, $places = 0, $decimals = '.', $thousands = ',') { + if (!isset(self::$_numberFormatSupport)) { + self::$_numberFormatSupport = version_compare(PHP_VERSION, '5.4.0', '>='); + } + if (self::$_numberFormatSupport) { + return number_format($number, $places, $decimals, $thousands); + } + $number = number_format($number, $places, '.', ''); + $after = ''; + $foundDecimal = strpos($number, '.'); + if ($foundDecimal !== false) { + $after = substr($number, $foundDecimal); + $number = substr($number, 0, $foundDecimal); + } + while (($foundThousand = preg_replace('/(\d+)(\d\d\d)/', '\1 \2', $number)) != $number) { + $number = $foundThousand; + } + $number .= $after; + return strtr($number, array(' ' => $thousands, '.' => $decimals)); + } + +/** + * Formats a number into a currency format. + * + * ### Options + * + * - `wholeSymbol` - The currency symbol to use for whole numbers, + * greater than 1, or less than -1. + * - `wholePosition` - The position the whole symbol should be placed + * valid options are 'before' & 'after'. + * - `fractionSymbol` - The currency symbol to use for fractional numbers. + * - `fractionPosition` - The position the fraction symbol should be placed + * valid options are 'before' & 'after'. + * - `before` - The currency symbol to place before whole numbers + * ie. '$'. `before` is an alias for `wholeSymbol`. + * - `after` - The currency symbol to place after decimal numbers + * ie. 'c'. Set to boolean false to use no decimal symbol. + * eg. 0.35 => $0.35. `after` is an alias for `fractionSymbol` + * - `zero` - The text to use for zero values, can be a + * string or a number. ie. 0, 'Free!' + * - `places` - Number of decimal places to use. ie. 2 + * - `thousands` - Thousands separator ie. ',' + * - `decimals` - Decimal separator symbol ie. '.' + * - `negative` - Symbol for negative numbers. If equal to '()', + * the number will be wrapped with ( and ) + * - `escape` - Should the output be htmlentity escaped? Defaults to true + * + * @param float $number + * @param string $currency Shortcut to default options. Valid values are + * 'USD', 'EUR', 'GBP', otherwise set at least 'before' and 'after' options. + * @param array $options + * @return string Number formatted as a currency. + * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/number.html#NumberHelper::currency + */ + public static function currency($number, $currency = 'USD', $options = array()) { + $default = self::$_currencyDefaults; + + if (isset(self::$_currencies[$currency])) { + $default = self::$_currencies[$currency]; + } elseif (is_string($currency)) { + $options['before'] = $currency; + } + + $options = array_merge($default, $options); + + if (isset($options['before']) && $options['before'] !== '') { + $options['wholeSymbol'] = $options['before']; + } + if (isset($options['after']) && !$options['after'] !== '') { + $options['fractionSymbol'] = $options['after']; + } + + $result = $options['before'] = $options['after'] = null; + + $symbolKey = 'whole'; + if ($number == 0 ) { + if ($options['zero'] !== 0 ) { + return $options['zero']; + } + } elseif ($number < 1 && $number > -1 ) { + if ($options['fractionSymbol'] !== false) { + $multiply = intval('1' . str_pad('', $options['places'], '0')); + $number = $number * $multiply; + $options['places'] = null; + $symbolKey = 'fraction'; + } + } + + $position = $options[$symbolKey . 'Position'] != 'after' ? 'before' : 'after'; + $options[$position] = $options[$symbolKey . 'Symbol']; + + $abs = abs($number); + $result = self::format($abs, $options); + + if ($number < 0 ) { + if ($options['negative'] == '()') { + $result = '(' . $result . ')'; + } else { + $result = $options['negative'] . $result; + } + } + return $result; + } + +/** + * Add a currency format to the Number helper. Makes reusing + * currency formats easier. + * + * {{{ $number->addFormat('NOK', array('before' => 'Kr. ')); }}} + * + * You can now use `NOK` as a shortform when formatting currency amounts. + * + * {{{ $number->currency($value, 'NOK'); }}} + * + * Added formats are merged with the defaults defined in CakeNumber::$_currencyDefaults + * See CakeNumber::currency() for more information on the various options and their function. + * + * @param string $formatName The format name to be used in the future. + * @param array $options The array of options for this format. + * @return void + * @see NumberHelper::currency() + * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/number.html#NumberHelper::addFormat + */ + public static function addFormat($formatName, $options) { + self::$_currencies[$formatName] = $options + self::$_currencyDefaults; + } + +} diff --git a/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/CakeTime.php b/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/CakeTime.php new file mode 100644 index 0000000..4788d53 --- /dev/null +++ b/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/CakeTime.php @@ -0,0 +1,1057 @@ +<?php +/** + * CakeTime utility class file. + * + * PHP 5 + * + * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) + * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * Redistributions of files must retain the above copyright notice. + * + * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://cakephp.org CakePHP(tm) Project + * @package Cake.Utility + * @since CakePHP(tm) v 0.10.0.1076 + * @license MIT License (http://www.opensource.org/licenses/mit-license.php) + */ + +App::uses('Multibyte', 'I18n'); + +/** + * Time Helper class for easy use of time data. + * + * Manipulation of time data. + * + * @package Cake.Utility + * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/time.html + */ +class CakeTime { + +/** + * The format to use when formatting a time using `CakeTime::nice()` + * + * The format should use the locale strings as defined in the PHP docs under + * `strftime` (http://php.net/manual/en/function.strftime.php) + * + * @var string + * @see CakeTime::format() + */ + public static $niceFormat = '%a, %b %eS %Y, %H:%M'; + +/** + * The format to use when formatting a time using `CakeTime::timeAgoInWords()` + * and the difference is more than `CakeTime::$wordEnd` + * + * @var string + * @see CakeTime::timeAgoInWords() + */ + public static $wordFormat = 'j/n/y'; + +/** + * The format to use when formatting a time using `CakeTime::niceShort()` + * and the difference is between 3 and 7 days + * + * @var string + * @see CakeTime::niceShort() + */ + public static $niceShortFormat = '%d/%m, %H:%M'; + +/** + * The format to use when formatting a time using `CakeTime::timeAgoInWords()` + * and the difference is less than `CakeTime::$wordEnd` + * + * @var array + * @see CakeTime::timeAgoInWords() + */ + public static $wordAccuracy = array( + 'year' => "day", + 'month' => "day", + 'week' => "day", + 'day' => "hour", + 'hour' => "minute", + 'minute' => "minute", + 'second' => "second", + ); + +/** + * The end of relative time telling + * + * @var string + * @see CakeTime::timeAgoInWords() + */ + public static $wordEnd = '+1 month'; + +/** + * Temporary variable containing timestamp value, used internally convertSpecifiers() + */ + protected static $_time = null; + +/** + * Magic set method for backward compatibility. + * + * Used by TimeHelper to modify static variables in CakeTime + */ + public function __set($name, $value) { + switch ($name) { + case 'niceFormat': + self::${$name} = $value; + break; + default: + break; + } + } + +/** + * Magic set method for backward compatibility. + * + * Used by TimeHelper to get static variables in CakeTime + */ + public function __get($name) { + switch ($name) { + case 'niceFormat': + return self::${$name}; + break; + default: + return null; + break; + } + } + +/** + * Converts a string representing the format for the function strftime and returns a + * windows safe and i18n aware format. + * + * @param string $format Format with specifiers for strftime function. + * Accepts the special specifier %S which mimics the modifier S for date() + * @param string $time UNIX timestamp + * @return string windows safe and date() function compatible format for strftime + * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/time.html#formatting + */ + public static function convertSpecifiers($format, $time = null) { + if (!$time) { + $time = time(); + } + self::$_time = $time; + return preg_replace_callback('/\%(\w+)/', array('CakeTime', '_translateSpecifier'), $format); + } + +/** + * Auxiliary function to translate a matched specifier element from a regular expression into + * a windows safe and i18n aware specifier + * + * @param array $specifier match from regular expression + * @return string converted element + */ + protected static function _translateSpecifier($specifier) { + switch ($specifier[1]) { + case 'a': + $abday = __dc('cake', 'abday', 5); + if (is_array($abday)) { + return $abday[date('w', self::$_time)]; + } + break; + case 'A': + $day = __dc('cake', 'day', 5); + if (is_array($day)) { + return $day[date('w', self::$_time)]; + } + break; + case 'c': + $format = __dc('cake', 'd_t_fmt', 5); + if ($format != 'd_t_fmt') { + return self::convertSpecifiers($format, self::$_time); + } + break; + case 'C': + return sprintf("%02d", date('Y', self::$_time) / 100); + case 'D': + return '%m/%d/%y'; + case 'e': + if (DS === '/') { + return '%e'; + } + $day = date('j', self::$_time); + if ($day < 10) { + $day = ' ' . $day; + } + return $day; + case 'eS' : + return date('jS', self::$_time); + case 'b': + case 'h': + $months = __dc('cake', 'abmon', 5); + if (is_array($months)) { + return $months[date('n', self::$_time) - 1]; + } + return '%b'; + case 'B': + $months = __dc('cake', 'mon', 5); + if (is_array($months)) { + return $months[date('n', self::$_time) - 1]; + } + break; + case 'n': + return "\n"; + case 'p': + case 'P': + $default = array('am' => 0, 'pm' => 1); + $meridiem = $default[date('a', self::$_time)]; + $format = __dc('cake', 'am_pm', 5); + if (is_array($format)) { + $meridiem = $format[$meridiem]; + return ($specifier[1] == 'P') ? strtolower($meridiem) : strtoupper($meridiem); + } + break; + case 'r': + $complete = __dc('cake', 't_fmt_ampm', 5); + if ($complete != 't_fmt_ampm') { + return str_replace('%p', self::_translateSpecifier(array('%p', 'p')), $complete); + } + break; + case 'R': + return date('H:i', self::$_time); + case 't': + return "\t"; + case 'T': + return '%H:%M:%S'; + case 'u': + return ($weekDay = date('w', self::$_time)) ? $weekDay : 7; + case 'x': + $format = __dc('cake', 'd_fmt', 5); + if ($format != 'd_fmt') { + return self::convertSpecifiers($format, self::$_time); + } + break; + case 'X': + $format = __dc('cake', 't_fmt', 5); + if ($format != 't_fmt') { + return self::convertSpecifiers($format, self::$_time); + } + break; + } + return $specifier[0]; + } + +/** + * Converts given time (in server's time zone) to user's local time, given his/her timezone. + * + * @param string $serverTime UNIX timestamp + * @param string|DateTimeZone $timezone User's timezone string or DateTimeZone object + * @return integer UNIX timestamp + * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/time.html#formatting + */ + public static function convert($serverTime, $timezone) { + static $serverTimezone = null; + if (is_null($serverTimezone) || (date_default_timezone_get() !== $serverTimezone->getName())) { + $serverTimezone = new DateTimeZone(date_default_timezone_get()); + } + $serverOffset = $serverTimezone->getOffset(new DateTime('@' . $serverTime)); + $gmtTime = $serverTime - $serverOffset; + if (is_numeric($timezone)) { + $userOffset = $timezone * (60 * 60); + } else { + $timezone = self::timezone($timezone); + $userOffset = $timezone->getOffset(new DateTime('@' . $gmtTime)); + } + $userTime = $gmtTime + $userOffset; + return (int)$userTime; + } + +/** + * Returns a timezone object from a string or the user's timezone object + * + * @param string|DateTimeZone $timezone Timezone string or DateTimeZone object + * If null it tries to get timezone from 'Config.timezone' config var + * @return DateTimeZone Timezone object + */ + public static function timezone($timezone = null) { + static $tz = null; + + if (is_object($timezone)) { + if ($tz === null || $tz->getName() !== $timezone->getName()) { + $tz = $timezone; + } + } else { + if ($timezone === null) { + $timezone = Configure::read('Config.timezone'); + if ($timezone === null) { + $timezone = date_default_timezone_get(); + } + } + + if ($tz === null || $tz->getName() !== $timezone) { + $tz = new DateTimeZone($timezone); + } + } + + return $tz; + } + +/** + * Returns server's offset from GMT in seconds. + * + * @return integer Offset + * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/time.html#formatting + */ + public static function serverOffset() { + return date('Z', time()); + } + +/** + * Returns a UNIX timestamp, given either a UNIX timestamp or a valid strtotime() date string. + * + * @param integer|string|DateTime $dateString UNIX timestamp, strtotime() valid string or DateTime object + * @param string|DateTimeZone $timezone Timezone string or DateTimeZone object + * @return string Parsed timestamp + * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/time.html#formatting + */ + public static function fromString($dateString, $timezone = null) { + if (empty($dateString)) { + return false; + } + + if (is_integer($dateString) || is_numeric($dateString)) { + $date = intval($dateString); + } elseif (is_object($dateString) && $dateString instanceof DateTime) { + $clone = clone $dateString; + $clone->setTimezone(new DateTimeZone(date_default_timezone_get())); + $date = (int)$clone->format('U') + $clone->getOffset(); + } else { + $date = strtotime($dateString); + } + + if ($date === -1 || empty($date)) { + return false; + } + + if ($timezone === null) { + $timezone = Configure::read('Config.timezone'); + } + + if ($timezone !== null) { + return self::convert($date, $timezone); + } + return $date; + } + +/** + * Returns a nicely formatted date string for given Datetime string. + * + * See http://php.net/manual/en/function.strftime.php for information on formatting + * using locale strings. + * + * @param integer|string|DateTime $dateString UNIX timestamp, strtotime() valid string or DateTime object + * @param string|DateTimeZone $timezone Timezone string or DateTimeZone object + * @param string $format The format to use. If null, `TimeHelper::$niceFormat` is used + * @return string Formatted date string + * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/time.html#formatting + */ + public static function nice($dateString = null, $timezone = null, $format = null) { + if (!$dateString) { + $dateString = time(); + } + $date = self::fromString($dateString, $timezone); + + if (!$format) { + $format = self::$niceFormat; + } + $format = self::convertSpecifiers($format, $date); + return self::_strftime($format, $date); + } + +/** + * Returns a formatted descriptive date string for given datetime string. + * + * If the given date is today, the returned string could be "Today, 16:54". + * If the given date is tomorrow, the returned string could be "Tomorrow, 16:54". + * If the given date was yesterday, the returned string could be "Yesterday, 16:54". + * If the given date is within next or last week, the returned string could be "On Thursday, 16:54". + * If $dateString's year is the current year, the returned string does not + * include mention of the year. + * + * @param integer|string|DateTime $dateString UNIX timestamp, strtotime() valid string or DateTime object + * @param string|DateTimeZone $timezone Timezone string or DateTimeZone object + * @return string Described, relative date string + * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/time.html#formatting + */ + public static function niceShort($dateString = null, $timezone = null) { + if (!$dateString) { + $dateString = time(); + } + $date = self::fromString($dateString, $timezone); + + $y = self::isThisYear($date) ? '' : ' %Y'; + + $d = self::_strftime("%w", $date); + $day = array( + __d('cake', 'Sunday'), + __d('cake', 'Monday'), + __d('cake', 'Tuesday'), + __d('cake', 'Wednesday'), + __d('cake', 'Thursday'), + __d('cake', 'Friday'), + __d('cake', 'Saturday') + ); + + if (self::isToday($dateString, $timezone)) { + $ret = __d('cake', 'Today, %s', self::_strftime("%H:%M", $date)); + } elseif (self::wasYesterday($dateString, $timezone)) { + $ret = __d('cake', 'Yesterday, %s', self::_strftime("%H:%M", $date)); + } elseif (self::isTomorrow($dateString, $timezone)) { + $ret = __d('cake', 'Tomorrow, %s', self::_strftime("%H:%M", $date)); + } elseif (self::wasWithinLast('7 days', $dateString, $timezone)) { + $ret = sprintf('%s %s', $day[$d], self::_strftime(self::$niceShortFormat, $date)); + } elseif (self::isWithinNext('7 days', $dateString, $timezone)) { + $ret = __d('cake', 'On %s %s', $day[$d], self::_strftime(self::$niceShortFormat, $date)); + } else { + $format = self::convertSpecifiers("%b %eS{$y}, %H:%M", $date); + $ret = self::_strftime($format, $date); + } + return $ret; + } + +/** + * Returns a partial SQL string to search for all records between two dates. + * + * @param integer|string|DateTime $begin UNIX timestamp, strtotime() valid string or DateTime object + * @param integer|string|DateTime $end UNIX timestamp, strtotime() valid string or DateTime object + * @param string $fieldName Name of database field to compare with + * @param string|DateTimeZone $timezone Timezone string or DateTimeZone object + * @return string Partial SQL string. + * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/time.html#formatting + */ + public static function daysAsSql($begin, $end, $fieldName, $timezone = null) { + $begin = self::fromString($begin, $timezone); + $end = self::fromString($end, $timezone); + $begin = date('Y-m-d', $begin) . ' 00:00:00'; + $end = date('Y-m-d', $end) . ' 23:59:59'; + + return "($fieldName >= '$begin') AND ($fieldName <= '$end')"; + } + +/** + * Returns a partial SQL string to search for all records between two times + * occurring on the same day. + * + * @param integer|string|DateTime $dateString UNIX timestamp, strtotime() valid string or DateTime object + * @param string $fieldName Name of database field to compare with + * @param string|DateTimeZone $timezone Timezone string or DateTimeZone object + * @return string Partial SQL string. + * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/time.html#formatting + */ + public static function dayAsSql($dateString, $fieldName, $timezone = null) { + return self::daysAsSql($dateString, $dateString, $fieldName); + } + +/** + * Returns true if given datetime string is today. + * + * @param integer|string|DateTime $dateString UNIX timestamp, strtotime() valid string or DateTime object + * @param string|DateTimeZone $timezone Timezone string or DateTimeZone object + * @return boolean True if datetime string is today + * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/time.html#testing-time + */ + public static function isToday($dateString, $timezone = null) { + $date = self::fromString($dateString, $timezone); + return date('Y-m-d', $date) == date('Y-m-d', time()); + } + +/** + * Returns true if given datetime string is within this week. + * + * @param integer|string|DateTime $dateString UNIX timestamp, strtotime() valid string or DateTime object + * @param string|DateTimeZone $timezone Timezone string or DateTimeZone object + * @return boolean True if datetime string is within current week + * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/time.html#testing-time + */ + public static function isThisWeek($dateString, $timezone = null) { + $date = self::fromString($dateString, $timezone); + return date('W o', $date) == date('W o', time()); + } + +/** + * Returns true if given datetime string is within this month + * @param integer|string|DateTime $dateString UNIX timestamp, strtotime() valid string or DateTime object + * @param string|DateTimeZone $timezone Timezone string or DateTimeZone object + * @return boolean True if datetime string is within current month + * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/time.html#testing-time + */ + public static function isThisMonth($dateString, $timezone = null) { + $date = self::fromString($dateString); + return date('m Y', $date) == date('m Y', time()); + } + +/** + * Returns true if given datetime string is within current year. + * + * @param integer|string|DateTime $dateString UNIX timestamp, strtotime() valid string or DateTime object + * @param string|DateTimeZone $timezone Timezone string or DateTimeZone object + * @return boolean True if datetime string is within current year + * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/time.html#testing-time + */ + public static function isThisYear($dateString, $timezone = null) { + $date = self::fromString($dateString, $timezone); + return date('Y', $date) == date('Y', time()); + } + +/** + * Returns true if given datetime string was yesterday. + * + * @param integer|string|DateTime $dateString UNIX timestamp, strtotime() valid string or DateTime object + * @param string|DateTimeZone $timezone Timezone string or DateTimeZone object + * @return boolean True if datetime string was yesterday + * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/time.html#testing-time + * + */ + public static function wasYesterday($dateString, $timezone = null) { + $date = self::fromString($dateString, $timezone); + return date('Y-m-d', $date) == date('Y-m-d', strtotime('yesterday')); + } + +/** + * Returns true if given datetime string is tomorrow. + * + * @param integer|string|DateTime $dateString UNIX timestamp, strtotime() valid string or DateTime object + * @param string|DateTimeZone $timezone Timezone string or DateTimeZone object + * @return boolean True if datetime string was yesterday + * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/time.html#testing-time + */ + public static function isTomorrow($dateString, $timezone = null) { + $date = self::fromString($dateString, $timezone); + return date('Y-m-d', $date) == date('Y-m-d', strtotime('tomorrow')); + } + +/** + * Returns the quarter + * + * @param integer|string|DateTime $dateString UNIX timestamp, strtotime() valid string or DateTime object + * @param boolean $range if true returns a range in Y-m-d format + * @return mixed 1, 2, 3, or 4 quarter of year or array if $range true + * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/time.html#formatting + */ + public static function toQuarter($dateString, $range = false) { + $time = self::fromString($dateString); + $date = ceil(date('m', $time) / 3); + + if ($range === true) { + $range = 'Y-m-d'; + } + + if ($range !== false) { + $year = date('Y', $time); + + switch ($date) { + case 1: + $date = array($year . '-01-01', $year . '-03-31'); + break; + case 2: + $date = array($year . '-04-01', $year . '-06-30'); + break; + case 3: + $date = array($year . '-07-01', $year . '-09-30'); + break; + case 4: + $date = array($year . '-10-01', $year . '-12-31'); + break; + } + } + return $date; + } + +/** + * Returns a UNIX timestamp from a textual datetime description. Wrapper for PHP function strtotime(). + * @param integer|string|DateTime $dateString UNIX timestamp, strtotime() valid string or DateTime object + * @param string|DateTimeZone $timezone Timezone string or DateTimeZone object + * @return integer Unix timestamp + * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/time.html#formatting + */ + public static function toUnix($dateString, $timezone = null) { + return self::fromString($dateString, $timezone); + } + +/** + * Returns a formatted date in server's timezone. + * + * If a DateTime object is given or the dateString has a timezone + * segment, the timezone parameter will be ignored. + * + * If no timezone parameter is given and no DateTime object, the passed $dateString will be + * considered to be in the UTC timezone. + * + * @param integer|string|DateTime $dateString UNIX timestamp, strtotime() valid string or DateTime object + * @param string|DateTimeZone $timezone Timezone string or DateTimeZone object + * @param string $format date format string + * @return mixed Formatted date + */ + public static function toServer($dateString, $timezone = null, $format = 'Y-m-d H:i:s') { + if ($timezone === null) { + $timezone = new DateTimeZone('UTC'); + } elseif (is_string($timezone)) { + $timezone = new DateTimeZone($timezone); + } elseif (!($timezone instanceof DateTimeZone)) { + return false; + } + + if ($dateString instanceof DateTime) { + $date = $dateString; + } elseif (is_integer($dateString) || is_numeric($dateString)) { + $dateString = (int)$dateString; + + $date = new DateTime('@' . $dateString); + $date->setTimezone($timezone); + } else { + $date = new DateTime($dateString, $timezone); + } + + $date->setTimezone(new DateTimeZone(date_default_timezone_get())); + return $date->format($format); + } + +/** + * Returns a date formatted for Atom RSS feeds. + * + * @param string $dateString Datetime string or Unix timestamp + * @param string|DateTimeZone $timezone Timezone string or DateTimeZone object + * @return string Formatted date string + * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/time.html#formatting + */ + public static function toAtom($dateString, $timezone = null) { + $date = self::fromString($dateString, $timezone); + return date('Y-m-d\TH:i:s\Z', $date); + } + +/** + * Formats date for RSS feeds + * + * @param integer|string|DateTime $dateString UNIX timestamp, strtotime() valid string or DateTime object + * @param string|DateTimeZone $timezone Timezone string or DateTimeZone object + * @return string Formatted date string + * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/time.html#formatting + */ + public static function toRSS($dateString, $timezone = null) { + $date = self::fromString($dateString, $timezone); + + if (!is_null($timezone)) { + if (is_numeric($timezone)) { + $userOffset = $timezone; + } else { + if (!is_object($timezone)) { + $timezone = new DateTimeZone($timezone); + } + $currentDate = new DateTime('@' . $date); + $currentDate->setTimezone($timezone); + $userOffset = $timezone->getOffset($currentDate) / 60 / 60; + } + if ($userOffset == 0) { + $timezone = '+0000'; + } else { + $hours = (int)floor(abs($userOffset)); + $minutes = (int)(fmod(abs($userOffset), $hours) * 60); + $timezone = ($userOffset < 0 ? '-' : '+') . str_pad($hours, 2, '0', STR_PAD_LEFT) . str_pad($minutes, 2, '0', STR_PAD_LEFT); + } + return date('D, d M Y H:i:s', $date) . ' ' . $timezone; + } + return date("r", $date); + } + +/** + * Returns either a relative date or a formatted date depending + * on the difference between the current time and given datetime. + * $datetime should be in a *strtotime* - parsable format, like MySQL's datetime datatype. + * + * ### Options: + * + * - `format` => a fall back format if the relative time is longer than the duration specified by end + * - `accuracy` => Specifies how accurate the date should be described (array) + * - year => The format if years > 0 (default "day") + * - month => The format if months > 0 (default "day") + * - week => The format if weeks > 0 (default "day") + * - day => The format if weeks > 0 (default "hour") + * - hour => The format if hours > 0 (default "minute") + * - minute => The format if minutes > 0 (default "minute") + * - second => The format if seconds > 0 (default "second") + * - `end` => The end of relative time telling + * - `userOffset` => Users offset from GMT (in hours) *Deprecated* use timezone intead. + * - `timezone` => The user timezone the timestamp should be formatted in. + * + * Relative dates look something like this: + * + * - 3 weeks, 4 days ago + * - 15 seconds ago + * + * Default date formatting is d/m/yy e.g: on 18/2/09 + * + * The returned string includes 'ago' or 'on' and assumes you'll properly add a word + * like 'Posted ' before the function output. + * + * NOTE: If the difference is one week or more, the lowest level of accuracy is day + * + * @param integer|string|DateTime $dateTime Datetime UNIX timestamp, strtotime() valid string or DateTime object + * @param array $options Default format if timestamp is used in $dateString + * @return string Relative time string. + * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/time.html#formatting + */ + public static function timeAgoInWords($dateTime, $options = array()) { + $timezone = null; + $format = self::$wordFormat; + $end = self::$wordEnd; + $accuracy = self::$wordAccuracy; + + if (is_array($options)) { + if (isset($options['timezone'])) { + $timezone = $options['timezone']; + } elseif (isset($options['userOffset'])) { + $timezone = $options['userOffset']; + } + + if (isset($options['accuracy'])) { + if (is_array($options['accuracy'])) { + $accuracy = array_merge($accuracy, $options['accuracy']); + } else { + foreach ($accuracy as $key => $level) { + $accuracy[$key] = $options['accuracy']; + } + } + } + + if (isset($options['format'])) { + $format = $options['format']; + } + if (isset($options['end'])) { + $end = $options['end']; + } + unset($options['end'], $options['format']); + } else { + $format = $options; + } + + $now = self::fromString(time(), $timezone); + $inSeconds = self::fromString($dateTime, $timezone); + $backwards = ($inSeconds > $now); + + if ($backwards) { + $futureTime = $inSeconds; + $pastTime = $now; + } else { + $futureTime = $now; + $pastTime = $inSeconds; + } + $diff = $futureTime - $pastTime; + + // If more than a week, then take into account the length of months + if ($diff >= 604800) { + list($future['H'], $future['i'], $future['s'], $future['d'], $future['m'], $future['Y']) = explode('/', date('H/i/s/d/m/Y', $futureTime)); + + list($past['H'], $past['i'], $past['s'], $past['d'], $past['m'], $past['Y']) = explode('/', date('H/i/s/d/m/Y', $pastTime)); + $years = $months = $weeks = $days = $hours = $minutes = $seconds = 0; + + $years = $future['Y'] - $past['Y']; + $months = $future['m'] + ((12 * $years) - $past['m']); + + if ($months >= 12) { + $years = floor($months / 12); + $months = $months - ($years * 12); + } + if ($future['m'] < $past['m'] && $future['Y'] - $past['Y'] == 1) { + $years--; + } + + if ($future['d'] >= $past['d']) { + $days = $future['d'] - $past['d']; + } else { + $daysInPastMonth = date('t', $pastTime); + $daysInFutureMonth = date('t', mktime(0, 0, 0, $future['m'] - 1, 1, $future['Y'])); + + if (!$backwards) { + $days = ($daysInPastMonth - $past['d']) + $future['d']; + } else { + $days = ($daysInFutureMonth - $past['d']) + $future['d']; + } + + if ($future['m'] != $past['m']) { + $months--; + } + } + + if ($months == 0 && $years >= 1 && $diff < ($years * 31536000)) { + $months = 11; + $years--; + } + + if ($months >= 12) { + $years = $years + 1; + $months = $months - 12; + } + + if ($days >= 7) { + $weeks = floor($days / 7); + $days = $days - ($weeks * 7); + } + } else { + $years = $months = $weeks = 0; + $days = floor($diff / 86400); + + $diff = $diff - ($days * 86400); + + $hours = floor($diff / 3600); + $diff = $diff - ($hours * 3600); + + $minutes = floor($diff / 60); + $diff = $diff - ($minutes * 60); + $seconds = $diff; + } + $relativeDate = ''; + $diff = $futureTime - $pastTime; + + if ($diff > abs($now - self::fromString($end))) { + $relativeDate = __d('cake', 'on %s', date($format, $inSeconds)); + } else { + if ($years > 0) { + $f = $accuracy['year']; + } elseif (abs($months) > 0) { + $f = $accuracy['month']; + } elseif (abs($weeks) > 0) { + $f = $accuracy['week']; + } elseif (abs($days) > 0) { + $f = $accuracy['day']; + } elseif (abs($hours) > 0) { + $f = $accuracy['hour']; + } elseif (abs($minutes) > 0) { + $f = $accuracy['minute']; + } else { + $f = $accuracy['second']; + } + + $f = str_replace(array('year', 'month', 'week', 'day', 'hour', 'minute', 'second'), array(1, 2, 3, 4, 5, 6, 7), $f); + + $relativeDate .= $f >= 1 && $years > 0 ? ($relativeDate ? ', ' : '') . __dn('cake', '%d year', '%d years', $years, $years) : ''; + $relativeDate .= $f >= 2 && $months > 0 ? ($relativeDate ? ', ' : '') . __dn('cake', '%d month', '%d months', $months, $months) : ''; + $relativeDate .= $f >= 3 && $weeks > 0 ? ($relativeDate ? ', ' : '') . __dn('cake', '%d week', '%d weeks', $weeks, $weeks) : ''; + $relativeDate .= $f >= 4 && $days > 0 ? ($relativeDate ? ', ' : '') . __dn('cake', '%d day', '%d days', $days, $days) : ''; + $relativeDate .= $f >= 5 && $hours > 0 ? ($relativeDate ? ', ' : '') . __dn('cake', '%d hour', '%d hours', $hours, $hours) : ''; + $relativeDate .= $f >= 6 && $minutes > 0 ? ($relativeDate ? ', ' : '') . __dn('cake', '%d minute', '%d minutes', $minutes, $minutes) : ''; + $relativeDate .= $f >= 7 && $seconds > 0 ? ($relativeDate ? ', ' : '') . __dn('cake', '%d second', '%d seconds', $seconds, $seconds) : ''; + + if (!$backwards) { + $relativeDate = __d('cake', '%s ago', $relativeDate); + } + } + + // If now + if ($diff == 0) { + $relativeDate = __d('cake', 'just now', 'just now'); + } + return $relativeDate; + } + +/** + * Returns true if specified datetime was within the interval specified, else false. + * + * @param string|integer $timeInterval the numeric value with space then time type. + * Example of valid types: 6 hours, 2 days, 1 minute. + * @param integer|string|DateTime $dateString UNIX timestamp, strtotime() valid string or DateTime object + * @param string|DateTimeZone $timezone Timezone string or DateTimeZone object + * @return boolean + * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/time.html#testing-time + */ + public static function wasWithinLast($timeInterval, $dateString, $timezone = null) { + $tmp = str_replace(' ', '', $timeInterval); + if (is_numeric($tmp)) { + $timeInterval = $tmp . ' ' . __d('cake', 'days'); + } + + $date = self::fromString($dateString, $timezone); + $interval = self::fromString('-' . $timeInterval); + + if ($date >= $interval && $date <= time()) { + return true; + } + return false; + } + +/** + * Returns true if specified datetime is within the interval specified, else false. + * + * @param string|integer $timeInterval the numeric value with space then time type. + * Example of valid types: 6 hours, 2 days, 1 minute. + * @param integer|string|DateTime $dateString UNIX timestamp, strtotime() valid string or DateTime object + * @param string|DateTimeZone $timezone Timezone string or DateTimeZone object + * @return boolean + * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/time.html#testing-time + */ + public static function isWithinNext($timeInterval, $dateString, $timezone = null) { + $tmp = str_replace(' ', '', $timeInterval); + if (is_numeric($tmp)) { + $timeInterval = $tmp . ' ' . __d('cake', 'days'); + } + + $date = self::fromString($dateString, $timezone); + $interval = self::fromString('+' . $timeInterval); + + if ($date <= $interval && $date >= time()) { + return true; + } + return false; + } + +/** + * Returns gmt as a UNIX timestamp. + * + * @param integer|string|DateTime $dateString UNIX timestamp, strtotime() valid string or DateTime object + * @return integer UNIX timestamp + * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/time.html#formatting + */ + public static function gmt($dateString = null) { + if ($dateString != null) { + $time = self::fromString($dateString); + } else { + $time = time(); + } + $hour = intval(date("G", $time)); + $minute = intval(date("i", $time)); + $second = intval(date("s", $time)); + $month = intval(date("n", $time)); + $day = intval(date("j", $time)); + $year = intval(date("Y", $time)); + return gmmktime($hour, $minute, $second, $month, $day, $year); + } + +/** + * Returns a formatted date string, given either a UNIX timestamp or a valid strtotime() date string. + * This function also accepts a time string and a format string as first and second parameters. + * In that case this function behaves as a wrapper for TimeHelper::i18nFormat() + * + * ## Examples: + * {{{ + * CakeTime::format('2012-02-15', '%m-%d-%Y'); // returns 02-15-2012 + * CakeTime::format('2012-02-15 23:01:01', '%c'); // returns preferred date and time based on configured locale + * CakeTime::format('0000-00-00', '%d-%m-%Y', 'N/A'); // return N/A becuase an invalid date was passed + * CakeTime::format('2012-02-15 23:01:01', '%c', 'N/A', 'America/New_York'); // converts passed date to timezone + * }}} + * + * @param integer|string|DateTime $date UNIX timestamp, strtotime() valid string or DateTime object (or a date format string) + * @param integer|string|DateTime $format date format string (or UNIX timestamp, strtotime() valid string or DateTime object) + * @param boolean|string $default if an invalid date is passed it will output supplied default value. Pass false if you want raw conversion value + * @param string|DateTimeZone $timezone Timezone string or DateTimeZone object + * @return string Formatted date string + * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/time.html#formatting + */ + public static function format($date, $format = null, $default = false, $timezone = null) { + //Backwards compatible params order + $time = self::fromString($format, $timezone); + $_time = is_numeric($time) ? false : self::fromString($date, $timezone); + + if (is_numeric($_time) && $time === false) { + return self::i18nFormat($_time, $format, $default, $timezone); + } + if ($time === false && $default !== false) { + return $default; + } + return date($date, $time); + } + +/** + * Returns a formatted date string, given either a UNIX timestamp or a valid strtotime() date string. + * It take in account the default date format for the current language if a LC_TIME file is used. + * + * @param integer|string|DateTime $date UNIX timestamp, strtotime() valid string or DateTime object + * @param string $format strftime format string. + * @param boolean|string $default if an invalid date is passed it will output supplied default value. Pass false if you want raw conversion value + * @param string|DateTimeZone $timezone Timezone string or DateTimeZone object + * @return string Formatted and translated date string + * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/time.html#formatting + */ + public static function i18nFormat($date, $format = null, $default = false, $timezone = null) { + $date = self::fromString($date, $timezone); + if ($date === false && $default !== false) { + return $default; + } + if (empty($format)) { + $format = '%x'; + } + $format = self::convertSpecifiers($format, $date); + return self::_strftime($format, $date); + } + +/** + * Get list of timezone identifiers + * + * @param integer|string $filter A regex to filter identifer + * Or one of DateTimeZone class constants (PHP 5.3 and above) + * @param string $country A two-letter ISO 3166-1 compatible country code. + * This option is only used when $filter is set to DateTimeZone::PER_COUNTRY (available only in PHP 5.3 and above) + * @param boolean $group If true (default value) groups the identifiers list by primary region + * @return array List of timezone identifiers + * @since 2.2 + */ + public static function listTimezones($filter = null, $country = null, $group = true) { + $regex = null; + if (is_string($filter)) { + $regex = $filter; + $filter = null; + } + if (version_compare(PHP_VERSION, '5.3.0', '<')) { + if ($regex === null) { + $regex = '#^((Africa|America|Antartica|Arctic|Asia|Atlantic|Australia|Europe|Indian|Pacific)/|UTC)#'; + } + $identifiers = DateTimeZone::listIdentifiers(); + } else { + if ($filter === null) { + $filter = DateTimeZone::ALL; + } + $identifiers = DateTimeZone::listIdentifiers($filter, $country); + } + + if ($regex) { + foreach ($identifiers as $key => $tz) { + if (!preg_match($regex, $tz)) { + unset($identifiers[$key]); + } + } + } + + if ($group) { + $return = array(); + foreach ($identifiers as $key => $tz) { + $item = explode('/', $tz, 2); + if (isset($item[1])) { + $return[$item[0]][$tz] = $item[1]; + } else { + $return[$item[0]] = array($tz => $item[0]); + } + } + return $return; + } else { + return array_combine($identifiers, $identifiers); + } + } + +/** + * Multibyte wrapper for strftime. + * + * Handles utf8_encoding the result of strftime when necessary. + * + * @param string $format Format string. + * @param integer $date Timestamp to format. + * @return string formatted string with correct encoding. + */ + protected static function _strftime($format, $date) { + $format = strftime($format, $date); + $encoding = Configure::read('App.encoding'); + + if (!empty($encoding) && $encoding === 'UTF-8') { + if (function_exists('mb_check_encoding')) { + $valid = mb_check_encoding($format, $encoding); + } else { + $valid = !Multibyte::checkMultibyte($format); + } + if (!$valid) { + $format = utf8_encode($format); + } + } + return $format; + } + +} diff --git a/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/ClassRegistry.php b/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/ClassRegistry.php new file mode 100644 index 0000000..da7b125 --- /dev/null +++ b/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/ClassRegistry.php @@ -0,0 +1,368 @@ +<?php +/** + * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) + * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * Redistributions of files must retain the above copyright notice. + * + * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://cakephp.org CakePHP(tm) Project + * @package Cake.Utility + * @since CakePHP(tm) v 0.9.2 + * @license MIT License (http://www.opensource.org/licenses/mit-license.php) + */ + +/** + * Included libraries. + */ +App::uses('Model', 'Model'); +App::uses('AppModel', 'Model'); +App::uses('ConnectionManager', 'Model'); + +/** + * Class Collections. + * + * A repository for class objects, each registered with a key. + * If you try to add an object with the same key twice, nothing will come of it. + * If you need a second instance of an object, give it another key. + * + * @package Cake.Utility + */ +class ClassRegistry { + +/** + * Names of classes with their objects. + * + * @var array + */ + protected $_objects = array(); + +/** + * Names of class names mapped to the object in the registry. + * + * @var array + */ + protected $_map = array(); + +/** + * Default constructor parameter settings, indexed by type + * + * @var array + */ + protected $_config = array(); + +/** + * Return a singleton instance of the ClassRegistry. + * + * @return ClassRegistry instance + */ + public static function &getInstance() { + static $instance = array(); + if (!$instance) { + $instance[0] = new ClassRegistry(); + } + return $instance[0]; + } + +/** + * Loads a class, registers the object in the registry and returns instance of the object. ClassRegistry::init() + * is used as a factory for models, and handle correct injecting of settings, that assist in testing. + * + * Examples + * Simple Use: Get a Post model instance ```ClassRegistry::init('Post');``` + * + * Expanded: ```array('class' => 'ClassName', 'alias' => 'AliasNameStoredInTheRegistry', 'type' => 'Model');``` + * + * Model Classes can accept optional ```array('id' => $id, 'table' => $table, 'ds' => $ds, 'alias' => $alias);``` + * + * When $class is a numeric keyed array, multiple class instances will be stored in the registry, + * no instance of the object will be returned + * {{{ + * array( + * array('class' => 'ClassName', 'alias' => 'AliasNameStoredInTheRegistry'), + * array('class' => 'ClassName', 'alias' => 'AliasNameStoredInTheRegistry'), + * array('class' => 'ClassName', 'alias' => 'AliasNameStoredInTheRegistry') + * ); + * }}} + * @param string|array $class as a string or a single key => value array instance will be created, + * stored in the registry and returned. + * @param boolean $strict if set to true it will return false if the class was not found instead + * of trying to create an AppModel + * @return object instance of ClassName. + * @throws CakeException when you try to construct an interface or abstract class. + */ + public static function init($class, $strict = false) { + $_this = ClassRegistry::getInstance(); + $false = false; + $true = true; + + if (is_array($class)) { + $objects = $class; + if (!isset($class[0])) { + $objects = array($class); + } + } else { + $objects = array(array('class' => $class)); + } + $defaults = isset($_this->_config['Model']) ? $_this->_config['Model'] : array(); + $count = count($objects); + $availableDs = array_keys(ConnectionManager::enumConnectionObjects()); + + foreach ($objects as $key => $settings) { + if (is_array($settings)) { + $pluginPath = null; + $settings = array_merge($defaults, $settings); + $class = $settings['class']; + + list($plugin, $class) = pluginSplit($class); + if ($plugin) { + $pluginPath = $plugin . '.'; + } + + if (empty($settings['alias'])) { + $settings['alias'] = $class; + } + $alias = $settings['alias']; + + if ($model = $_this->_duplicate($alias, $class)) { + $_this->map($alias, $class); + return $model; + } + + App::uses($plugin . 'AppModel', $pluginPath . 'Model'); + App::uses($class, $pluginPath . 'Model'); + + if (class_exists($class) || interface_exists($class)) { + $reflection = new ReflectionClass($class); + if ($reflection->isAbstract() || $reflection->isInterface()) { + throw new CakeException(__d('cake_dev', 'Cannot create instance of %s, as it is abstract or is an interface', $class)); + } + $testing = isset($settings['testing']) ? $settings['testing'] : false; + if ($testing) { + $settings['ds'] = 'test'; + $defaultProperties = $reflection->getDefaultProperties(); + if (isset($defaultProperties['useDbConfig'])) { + $useDbConfig = $defaultProperties['useDbConfig']; + if (in_array('test_' . $useDbConfig, $availableDs)) { + $useDbConfig = 'test_' . $useDbConfig; + } + if (strpos($useDbConfig, 'test') === 0) { + $settings['ds'] = $useDbConfig; + } + } + } + if ($reflection->getConstructor()) { + $instance = $reflection->newInstance($settings); + } else { + $instance = $reflection->newInstance(); + } + if ($strict) { + $instance = ($instance instanceof Model) ? $instance : null; + } + } + if (!isset($instance)) { + if ($strict) { + return false; + } elseif ($plugin && class_exists($plugin . 'AppModel')) { + $appModel = $plugin . 'AppModel'; + } else { + $appModel = 'AppModel'; + } + if (!empty($appModel)) { + $settings['name'] = $class; + $instance = new $appModel($settings); + } + + if (!isset($instance)) { + trigger_error(__d('cake_dev', '(ClassRegistry::init() could not create instance of %1$s class %2$s ', $class, $type), E_USER_WARNING); + return $false; + } + } + $_this->map($alias, $class); + } elseif (is_numeric($settings)) { + trigger_error(__d('cake_dev', '(ClassRegistry::init() Attempted to create instance of a class with a numeric name'), E_USER_WARNING); + return $false; + } + } + + if ($count > 1) { + return $true; + } + return $instance; + } + +/** + * Add $object to the registry, associating it with the name $key. + * + * @param string $key Key for the object in registry + * @param object $object Object to store + * @return boolean True if the object was written, false if $key already exists + */ + public static function addObject($key, $object) { + $_this = ClassRegistry::getInstance(); + $key = Inflector::underscore($key); + if (!isset($_this->_objects[$key])) { + $_this->_objects[$key] = $object; + return true; + } + return false; + } + +/** + * Remove object which corresponds to given key. + * + * @param string $key Key of object to remove from registry + * @return void + */ + public static function removeObject($key) { + $_this = ClassRegistry::getInstance(); + $key = Inflector::underscore($key); + if (isset($_this->_objects[$key])) { + unset($_this->_objects[$key]); + } + } + +/** + * Returns true if given key is present in the ClassRegistry. + * + * @param string $key Key to look for + * @return boolean true if key exists in registry, false otherwise + */ + public static function isKeySet($key) { + $_this = ClassRegistry::getInstance(); + $key = Inflector::underscore($key); + if (isset($_this->_objects[$key])) { + return true; + } elseif (isset($_this->_map[$key])) { + return true; + } + return false; + } + +/** + * Get all keys from the registry. + * + * @return array Set of keys stored in registry + */ + public static function keys() { + $_this = ClassRegistry::getInstance(); + return array_keys($_this->_objects); + } + +/** + * Return object which corresponds to given key. + * + * @param string $key Key of object to look for + * @return mixed Object stored in registry or boolean false if the object does not exist. + */ + public static function &getObject($key) { + $_this = ClassRegistry::getInstance(); + $key = Inflector::underscore($key); + $return = false; + if (isset($_this->_objects[$key])) { + $return = $_this->_objects[$key]; + } else { + $key = $_this->_getMap($key); + if (isset($_this->_objects[$key])) { + $return = $_this->_objects[$key]; + } + } + return $return; + } + +/** + * Sets the default constructor parameter for an object type + * + * @param string $type Type of object. If this parameter is omitted, defaults to "Model" + * @param array $param The parameter that will be passed to object constructors when objects + * of $type are created + * @return mixed Void if $param is being set. Otherwise, if only $type is passed, returns + * the previously-set value of $param, or null if not set. + */ + public static function config($type, $param = array()) { + $_this = ClassRegistry::getInstance(); + + if (empty($param) && is_array($type)) { + $param = $type; + $type = 'Model'; + } elseif (is_null($param)) { + unset($_this->_config[$type]); + } elseif (empty($param) && is_string($type)) { + return isset($_this->_config[$type]) ? $_this->_config[$type] : null; + } + if (isset($_this->_config[$type]['testing'])) { + $param['testing'] = true; + } + $_this->_config[$type] = $param; + } + +/** + * Checks to see if $alias is a duplicate $class Object + * + * @param string $alias + * @param string $class + * @return boolean + */ + protected function &_duplicate($alias, $class) { + $duplicate = false; + if ($this->isKeySet($alias)) { + $model = $this->getObject($alias); + if (is_object($model) && (is_a($model, $class) || $model->alias === $class)) { + $duplicate = $model; + } + unset($model); + } + return $duplicate; + } + +/** + * Add a key name pair to the registry to map name to class in the registry. + * + * @param string $key Key to include in map + * @param string $name Key that is being mapped + * @return void + */ + public static function map($key, $name) { + $_this = ClassRegistry::getInstance(); + $key = Inflector::underscore($key); + $name = Inflector::underscore($name); + if (!isset($_this->_map[$key])) { + $_this->_map[$key] = $name; + } + } + +/** + * Get all keys from the map in the registry. + * + * @return array Keys of registry's map + */ + public static function mapKeys() { + $_this = ClassRegistry::getInstance(); + return array_keys($_this->_map); + } + +/** + * Return the name of a class in the registry. + * + * @param string $key Key to find in map + * @return string Mapped value + */ + protected function _getMap($key) { + if (isset($this->_map[$key])) { + return $this->_map[$key]; + } + } + +/** + * Flushes all objects from the ClassRegistry. + * + * @return void + */ + public static function flush() { + $_this = ClassRegistry::getInstance(); + $_this->_objects = array(); + $_this->_map = array(); + } + +} diff --git a/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/Debugger.php b/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/Debugger.php new file mode 100644 index 0000000..1d7410a --- /dev/null +++ b/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/Debugger.php @@ -0,0 +1,817 @@ +<?php +/** + * Framework debugging and PHP error-handling class + * + * Provides enhanced logging, stack traces, and rendering debug views + * + * PHP 5 + * + * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) + * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * Redistributions of files must retain the above copyright notice. + * + * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://cakephp.org CakePHP(tm) Project + * @package Cake.Utility + * @since CakePHP(tm) v 1.2.4560 + * @license MIT License (http://www.opensource.org/licenses/mit-license.php) + */ + +App::uses('CakeLog', 'Log'); +App::uses('String', 'Utility'); + +/** + * Provide custom logging and error handling. + * + * Debugger overrides PHP's default error handling to provide stack traces and enhanced logging + * + * @package Cake.Utility + * @link http://book.cakephp.org/2.0/en/development/debugging.html#debugger-class + */ +class Debugger { + +/** + * A list of errors generated by the application. + * + * @var array + */ + public $errors = array(); + +/** + * The current output format. + * + * @var string + */ + protected $_outputFormat = 'js'; + +/** + * Templates used when generating trace or error strings. Can be global or indexed by the format + * value used in $_outputFormat. + * + * @var string + */ + protected $_templates = array( + 'log' => array( + 'trace' => '{:reference} - {:path}, line {:line}', + 'error' => "{:error} ({:code}): {:description} in [{:file}, line {:line}]" + ), + 'js' => array( + 'error' => '', + 'info' => '', + 'trace' => '<pre class="stack-trace">{:trace}</pre>', + 'code' => '', + 'context' => '', + 'links' => array(), + 'escapeContext' => true, + ), + 'html' => array( + 'trace' => '<pre class="cake-error trace"><b>Trace</b> <p>{:trace}</p></pre>', + 'context' => '<pre class="cake-error context"><b>Context</b> <p>{:context}</p></pre>', + 'escapeContext' => true, + ), + 'txt' => array( + 'error' => "{:error}: {:code} :: {:description} on line {:line} of {:path}\n{:info}", + 'code' => '', + 'info' => '' + ), + 'base' => array( + 'traceLine' => '{:reference} - {:path}, line {:line}', + 'trace' => "Trace:\n{:trace}\n", + 'context' => "Context:\n{:context}\n", + ), + 'log' => array(), + ); + +/** + * Holds current output data when outputFormat is false. + * + * @var string + */ + protected $_data = array(); + +/** + * Constructor. + * + */ + public function __construct() { + $docRef = ini_get('docref_root'); + + if (empty($docRef) && function_exists('ini_set')) { + ini_set('docref_root', 'http://php.net/'); + } + if (!defined('E_RECOVERABLE_ERROR')) { + define('E_RECOVERABLE_ERROR', 4096); + } + + $e = '<pre class="cake-error">'; + $e .= '<a href="javascript:void(0);" onclick="document.getElementById(\'{:id}-trace\')'; + $e .= '.style.display = (document.getElementById(\'{:id}-trace\').style.display == '; + $e .= '\'none\' ? \'\' : \'none\');"><b>{:error}</b> ({:code})</a>: {:description} '; + $e .= '[<b>{:path}</b>, line <b>{:line}</b>]'; + + $e .= '<div id="{:id}-trace" class="cake-stack-trace" style="display: none;">'; + $e .= '{:links}{:info}</div>'; + $e .= '</pre>'; + $this->_templates['js']['error'] = $e; + + $t = '<div id="{:id}-trace" class="cake-stack-trace" style="display: none;">'; + $t .= '{:context}{:code}{:trace}</div>'; + $this->_templates['js']['info'] = $t; + + $links = array(); + $link = '<a href="javascript:void(0);" onclick="document.getElementById(\'{:id}-code\')'; + $link .= '.style.display = (document.getElementById(\'{:id}-code\').style.display == '; + $link .= '\'none\' ? \'\' : \'none\')">Code</a>'; + $links['code'] = $link; + + $link = '<a href="javascript:void(0);" onclick="document.getElementById(\'{:id}-context\')'; + $link .= '.style.display = (document.getElementById(\'{:id}-context\').style.display == '; + $link .= '\'none\' ? \'\' : \'none\')">Context</a>'; + $links['context'] = $link; + + $this->_templates['js']['links'] = $links; + + $this->_templates['js']['context'] = '<pre id="{:id}-context" class="cake-context" '; + $this->_templates['js']['context'] .= 'style="display: none;">{:context}</pre>'; + + $this->_templates['js']['code'] = '<pre id="{:id}-code" class="cake-code-dump" '; + $this->_templates['js']['code'] .= 'style="display: none;">{:code}</pre>'; + + $e = '<pre class="cake-error"><b>{:error}</b> ({:code}) : {:description} '; + $e .= '[<b>{:path}</b>, line <b>{:line}]</b></pre>'; + $this->_templates['html']['error'] = $e; + + $this->_templates['html']['context'] = '<pre class="cake-context"><b>Context</b> '; + $this->_templates['html']['context'] .= '<p>{:context}</p></pre>'; + } + +/** + * Returns a reference to the Debugger singleton object instance. + * + * @param string $class + * @return object + */ + public static function &getInstance($class = null) { + static $instance = array(); + if (!empty($class)) { + if (!$instance || strtolower($class) != strtolower(get_class($instance[0]))) { + $instance[0] = new $class(); + } + } + if (!$instance) { + $instance[0] = new Debugger(); + } + return $instance[0]; + } + +/** + * Recursively formats and outputs the contents of the supplied variable. + * + * + * @param mixed $var the variable to dump + * @return void + * @see Debugger::exportVar() + * @link http://book.cakephp.org/2.0/en/development/debugging.html#Debugger::dump + */ + public static function dump($var) { + pr(self::exportVar($var)); + } + +/** + * Creates an entry in the log file. The log entry will contain a stack trace from where it was called. + * as well as export the variable using exportVar. By default the log is written to the debug log. + * + * @param mixed $var Variable or content to log + * @param integer $level type of log to use. Defaults to LOG_DEBUG + * @return void + * @link http://book.cakephp.org/2.0/en/development/debugging.html#Debugger::log + */ + public static function log($var, $level = LOG_DEBUG) { + $source = self::trace(array('start' => 1)) . "\n"; + CakeLog::write($level, "\n" . $source . self::exportVar($var)); + } + +/** + * Overrides PHP's default error handling. + * + * @param integer $code Code of error + * @param string $description Error description + * @param string $file File on which error occurred + * @param integer $line Line that triggered the error + * @param array $context Context + * @return boolean true if error was handled + * @deprecated This function is superseded by Debugger::outputError() + */ + public static function showError($code, $description, $file = null, $line = null, $context = null) { + $self = Debugger::getInstance(); + + if (empty($file)) { + $file = '[internal]'; + } + if (empty($line)) { + $line = '??'; + } + $path = self::trimPath($file); + + $info = compact('code', 'description', 'file', 'line'); + if (!in_array($info, $self->errors)) { + $self->errors[] = $info; + } else { + return; + } + + switch ($code) { + case E_PARSE: + case E_ERROR: + case E_CORE_ERROR: + case E_COMPILE_ERROR: + case E_USER_ERROR: + $error = 'Fatal Error'; + $level = LOG_ERR; + break; + case E_WARNING: + case E_USER_WARNING: + case E_COMPILE_WARNING: + case E_RECOVERABLE_ERROR: + $error = 'Warning'; + $level = LOG_WARNING; + break; + case E_NOTICE: + case E_USER_NOTICE: + $error = 'Notice'; + $level = LOG_NOTICE; + break; + case E_DEPRECATED: + case E_USER_DEPRECATED: + $error = 'Deprecated'; + $level = LOG_NOTICE; + break; + default: + return; + break; + } + + $data = compact( + 'level', 'error', 'code', 'description', 'file', 'path', 'line', 'context' + ); + echo $self->outputError($data); + + if ($error == 'Fatal Error') { + exit(); + } + return true; + } + +/** + * Outputs a stack trace based on the supplied options. + * + * ### Options + * + * - `depth` - The number of stack frames to return. Defaults to 999 + * - `format` - The format you want the return. Defaults to the currently selected format. If + * format is 'array' or 'points' the return will be an array. + * - `args` - Should arguments for functions be shown? If true, the arguments for each method call + * will be displayed. + * - `start` - The stack frame to start generating a trace from. Defaults to 0 + * + * @param array $options Format for outputting stack trace + * @return mixed Formatted stack trace + * @link http://book.cakephp.org/2.0/en/development/debugging.html#Debugger::trace + */ + public static function trace($options = array()) { + $self = Debugger::getInstance(); + $defaults = array( + 'depth' => 999, + 'format' => $self->_outputFormat, + 'args' => false, + 'start' => 0, + 'scope' => null, + 'exclude' => array('call_user_func_array', 'trigger_error') + ); + $options = Hash::merge($defaults, $options); + + $backtrace = debug_backtrace(); + $count = count($backtrace); + $back = array(); + + $_trace = array( + 'line' => '??', + 'file' => '[internal]', + 'class' => null, + 'function' => '[main]' + ); + + for ($i = $options['start']; $i < $count && $i < $options['depth']; $i++) { + $trace = array_merge(array('file' => '[internal]', 'line' => '??'), $backtrace[$i]); + $signature = $reference = '[main]'; + + if (isset($backtrace[$i + 1])) { + $next = array_merge($_trace, $backtrace[$i + 1]); + $signature = $reference = $next['function']; + + if (!empty($next['class'])) { + $signature = $next['class'] . '::' . $next['function']; + $reference = $signature . '('; + if ($options['args'] && isset($next['args'])) { + $args = array(); + foreach ($next['args'] as $arg) { + $args[] = Debugger::exportVar($arg); + } + $reference .= join(', ', $args); + } + $reference .= ')'; + } + } + if (in_array($signature, $options['exclude'])) { + continue; + } + if ($options['format'] == 'points' && $trace['file'] != '[internal]') { + $back[] = array('file' => $trace['file'], 'line' => $trace['line']); + } elseif ($options['format'] == 'array') { + $back[] = $trace; + } else { + if (isset($self->_templates[$options['format']]['traceLine'])) { + $tpl = $self->_templates[$options['format']]['traceLine']; + } else { + $tpl = $self->_templates['base']['traceLine']; + } + $trace['path'] = self::trimPath($trace['file']); + $trace['reference'] = $reference; + unset($trace['object'], $trace['args']); + $back[] = String::insert($tpl, $trace, array('before' => '{:', 'after' => '}')); + } + } + + if ($options['format'] == 'array' || $options['format'] == 'points') { + return $back; + } + return implode("\n", $back); + } + +/** + * Shortens file paths by replacing the application base path with 'APP', and the CakePHP core + * path with 'CORE'. + * + * @param string $path Path to shorten + * @return string Normalized path + */ + public static function trimPath($path) { + if (!defined('CAKE_CORE_INCLUDE_PATH') || !defined('APP')) { + return $path; + } + + if (strpos($path, APP) === 0) { + return str_replace(APP, 'APP' . DS, $path); + } elseif (strpos($path, CAKE_CORE_INCLUDE_PATH) === 0) { + return str_replace(CAKE_CORE_INCLUDE_PATH, 'CORE', $path); + } elseif (strpos($path, ROOT) === 0) { + return str_replace(ROOT, 'ROOT', $path); + } + + if (strpos($path, CAKE) === 0) { + return str_replace($corePath, 'CORE' . DS, $path); + } + return $path; + } + +/** + * Grabs an excerpt from a file and highlights a given line of code. + * + * Usage: + * + * `Debugger::excerpt('/path/to/file', 100, 4);` + * + * The above would return an array of 8 items. The 4th item would be the provided line, + * and would be wrapped in `<span class="code-highlight"></span>`. All of the lines + * are processed with highlight_string() as well, so they have basic PHP syntax highlighting + * applied. + * + * @param string $file Absolute path to a PHP file + * @param integer $line Line number to highlight + * @param integer $context Number of lines of context to extract above and below $line + * @return array Set of lines highlighted + * @see http://php.net/highlight_string + * @link http://book.cakephp.org/2.0/en/development/debugging.html#Debugger::excerpt + */ + public static function excerpt($file, $line, $context = 2) { + $lines = array(); + if (!file_exists($file)) { + return array(); + } + $data = @explode("\n", file_get_contents($file)); + + if (empty($data) || !isset($data[$line])) { + return; + } + for ($i = $line - ($context + 1); $i < $line + $context; $i++) { + if (!isset($data[$i])) { + continue; + } + $string = str_replace(array("\r\n", "\n"), "", self::_highlight($data[$i])); + if ($i == $line) { + $lines[] = '<span class="code-highlight">' . $string . '</span>'; + } else { + $lines[] = $string; + } + } + return $lines; + } + +/** + * Wraps the highlight_string funciton in case the server API does not + * implement the function as it is the case of the HipHop interpreter + * + * @param string $str the string to convert + * @return string + */ + protected static function _highlight($str) { + static $supportHighlight = null; + if (!$supportHighlight && function_exists('hphp_log')) { + $supportHighlight = false; + return htmlentities($str); + } + $supportHighlight = true; + return highlight_string($str, true); + } + +/** + * Converts a variable to a string for debug output. + * + * *Note:* The following keys will have their contents + * replaced with `*****`: + * + * - password + * - login + * - host + * - database + * - port + * - prefix + * - schema + * + * This is done to protect database credentials, which could be accidentally + * shown in an error message if CakePHP is deployed in development mode. + * + * @param string $var Variable to convert + * @param integer $depth The depth to output to. Defaults to 3. + * @return string Variable as a formatted string + * @link http://book.cakephp.org/2.0/en/development/debugging.html#Debugger::exportVar + */ + public static function exportVar($var, $depth = 3) { + return self::_export($var, $depth, 0); + } + +/** + * Protected export function used to keep track of indentation and recursion. + * + * @param mixed $var The variable to dump. + * @param integer $depth The remaining depth. + * @param integer $indent The current indentation level. + * @return string The dumped variable. + */ + protected static function _export($var, $depth, $indent) { + switch (self::getType($var)) { + case 'boolean': + return ($var) ? 'true' : 'false'; + break; + case 'integer': + return '(int) ' . $var; + case 'float': + return '(float) ' . $var; + break; + case 'string': + if (trim($var) == '') { + return "''"; + } + return "'" . $var . "'"; + break; + case 'array': + return self::_array($var, $depth - 1, $indent + 1); + break; + case 'resource': + return strtolower(gettype($var)); + break; + case 'null': + return 'null'; + default: + return self::_object($var, $depth - 1, $indent + 1); + break; + } + } + +/** + * Export an array type object. Filters out keys used in datasource configuration. + * + * The following keys are replaced with ***'s + * + * - password + * - login + * - host + * - database + * - port + * - prefix + * - schema + * + * @param array $var The array to export. + * @param integer $depth The current depth, used for recursion tracking. + * @param integer $indent The current indentation level. + * @return string Exported array. + */ + protected static function _array(array $var, $depth, $indent) { + $secrets = array( + 'password' => '*****', + 'login' => '*****', + 'host' => '*****', + 'database' => '*****', + 'port' => '*****', + 'prefix' => '*****', + 'schema' => '*****' + ); + $replace = array_intersect_key($secrets, $var); + $var = $replace + $var; + + $out = "array("; + $n = $break = $end = null; + if (!empty($var)) { + $n = "\n"; + $break = "\n" . str_repeat("\t", $indent); + $end = "\n" . str_repeat("\t", $indent - 1); + } + $vars = array(); + + if ($depth >= 0) { + foreach ($var as $key => $val) { + $vars[] = $break . self::exportVar($key) . + ' => ' . + self::_export($val, $depth, $indent); + } + } else { + $vars[] = $break . '[maximum depth reached]'; + } + return $out . implode(',', $vars) . $end . ')'; + } + +/** + * Handles object to string conversion. + * + * @param string $var Object to convert + * @param integer $depth The current depth, used for tracking recursion. + * @param integer $indent The current indentation level. + * @return string + * @see Debugger::exportVar() + */ + protected static function _object($var, $depth, $indent) { + $out = ''; + $props = array(); + + $className = get_class($var); + $out .= 'object(' . $className . ') {'; + + if ($depth > 0) { + $end = "\n" . str_repeat("\t", $indent - 1); + $break = "\n" . str_repeat("\t", $indent); + $objectVars = get_object_vars($var); + foreach ($objectVars as $key => $value) { + $value = self::_export($value, $depth - 1, $indent); + $props[] = "$key => " . $value; + } + $out .= $break . implode($break, $props) . $end; + } + $out .= '}'; + return $out; + } + +/** + * Get/Set the output format for Debugger error rendering. + * + * @param string $format The format you want errors to be output as. + * Leave null to get the current format. + * @return mixed Returns null when setting. Returns the current format when getting. + * @throws CakeException when choosing a format that doesn't exist. + */ + public static function outputAs($format = null) { + $self = Debugger::getInstance(); + if ($format === null) { + return $self->_outputFormat; + } + if ($format !== false && !isset($self->_templates[$format])) { + throw new CakeException(__d('cake_dev', 'Invalid Debugger output format.')); + } + $self->_outputFormat = $format; + } + +/** + * Add an output format or update a format in Debugger. + * + * `Debugger::addFormat('custom', $data);` + * + * Where $data is an array of strings that use String::insert() variable + * replacement. The template vars should be in a `{:id}` style. + * An error formatter can have the following keys: + * + * - 'error' - Used for the container for the error message. Gets the following template + * variables: `id`, `error`, `code`, `description`, `path`, `line`, `links`, `info` + * - 'info' - A combination of `code`, `context` and `trace`. Will be set with + * the contents of the other template keys. + * - 'trace' - The container for a stack trace. Gets the following template + * variables: `trace` + * - 'context' - The container element for the context variables. + * Gets the following templates: `id`, `context` + * - 'links' - An array of HTML links that are used for creating links to other resources. + * Typically this is used to create javascript links to open other sections. + * Link keys, are: `code`, `context`, `help`. See the js output format for an + * example. + * - 'traceLine' - Used for creating lines in the stacktrace. Gets the following + * template variables: `reference`, `path`, `line` + * + * Alternatively if you want to use a custom callback to do all the formatting, you can use + * the callback key, and provide a callable: + * + * `Debugger::addFormat('custom', array('callback' => array($foo, 'outputError'));` + * + * The callback can expect two parameters. The first is an array of all + * the error data. The second contains the formatted strings generated using + * the other template strings. Keys like `info`, `links`, `code`, `context` and `trace` + * will be present depending on the other templates in the format type. + * + * @param string $format Format to use, including 'js' for JavaScript-enhanced HTML, 'html' for + * straight HTML output, or 'txt' for unformatted text. + * @param array $strings Template strings, or a callback to be used for the output format. + * @return The resulting format string set. + */ + public static function addFormat($format, array $strings) { + $self = Debugger::getInstance(); + if (isset($self->_templates[$format])) { + if (isset($strings['links'])) { + $self->_templates[$format]['links'] = array_merge( + $self->_templates[$format]['links'], + $strings['links'] + ); + unset($strings['links']); + } + $self->_templates[$format] = array_merge($self->_templates[$format], $strings); + } else { + $self->_templates[$format] = $strings; + } + return $self->_templates[$format]; + } + +/** + * Switches output format, updates format strings. + * Can be used to switch the active output format: + * + * @param string $format Format to use, including 'js' for JavaScript-enhanced HTML, 'html' for + * straight HTML output, or 'txt' for unformatted text. + * @param array $strings Template strings to be used for the output format. + * @return string + * @deprecated Use Debugger::outputAs() and Debugger::addFormat(). Will be removed + * in 3.0 + */ + public function output($format = null, $strings = array()) { + $self = Debugger::getInstance(); + $data = null; + + if (is_null($format)) { + return Debugger::outputAs(); + } + + if (!empty($strings)) { + return Debugger::addFormat($format, $strings); + } + + if ($format === true && !empty($self->_data)) { + $data = $self->_data; + $self->_data = array(); + $format = false; + } + Debugger::outputAs($format); + return $data; + } + +/** + * Takes a processed array of data from an error and displays it in the chosen format. + * + * @param string $data + * @return void + */ + public function outputError($data) { + $defaults = array( + 'level' => 0, + 'error' => 0, + 'code' => 0, + 'description' => '', + 'file' => '', + 'line' => 0, + 'context' => array(), + 'start' => 2, + ); + $data += $defaults; + + $files = $this->trace(array('start' => $data['start'], 'format' => 'points')); + $code = ''; + if (isset($files[1]['file'])) { + $code = $this->excerpt($files[1]['file'], $files[1]['line'] - 1, 1); + } + $trace = $this->trace(array('start' => $data['start'], 'depth' => '20')); + $insertOpts = array('before' => '{:', 'after' => '}'); + $context = array(); + $links = array(); + $info = ''; + + foreach ((array)$data['context'] as $var => $value) { + $context[] = "\${$var} = " . $this->exportVar($value, 1); + } + + switch ($this->_outputFormat) { + case false: + $this->_data[] = compact('context', 'trace') + $data; + return; + case 'log': + $this->log(compact('context', 'trace') + $data); + return; + } + + $data['trace'] = $trace; + $data['id'] = 'cakeErr' . uniqid(); + $tpl = array_merge($this->_templates['base'], $this->_templates[$this->_outputFormat]); + + if (isset($tpl['links'])) { + foreach ($tpl['links'] as $key => $val) { + $links[$key] = String::insert($val, $data, $insertOpts); + } + } + + if (!empty($tpl['escapeContext'])) { + $context = h($context); + } + + $infoData = compact('code', 'context', 'trace'); + foreach ($infoData as $key => $value) { + if (empty($value) || !isset($tpl[$key])) { + continue; + } + if (is_array($value)) { + $value = join("\n", $value); + } + $info .= String::insert($tpl[$key], array($key => $value) + $data, $insertOpts); + } + $links = join(' ', $links); + + if (isset($tpl['callback']) && is_callable($tpl['callback'])) { + return call_user_func($tpl['callback'], $data, compact('links', 'info')); + } + echo String::insert($tpl['error'], compact('links', 'info') + $data, $insertOpts); + } + +/** + * Get the type of the given variable. Will return the classname + * for objects. + * + * @param mixed $var The variable to get the type of + * @return string The type of variable. + */ + public static function getType($var) { + if (is_object($var)) { + return get_class($var); + } + if (is_null($var)) { + return 'null'; + } + if (is_string($var)) { + return 'string'; + } + if (is_array($var)) { + return 'array'; + } + if (is_int($var)) { + return 'integer'; + } + if (is_bool($var)) { + return 'boolean'; + } + if (is_float($var)) { + return 'float'; + } + if (is_resource($var)) { + return 'resource'; + } + return 'unknown'; + } + +/** + * Verifies that the application's salt and cipher seed value has been changed from the default value. + * + * @return void + */ + public static function checkSecurityKeys() { + if (Configure::read('Security.salt') == 'DYhG93b0qyJfIxfs2guVoUubWwvniR2G0FgaC9mi') { + trigger_error(__d('cake_dev', 'Please change the value of \'Security.salt\' in app/Config/core.php to a salt value specific to your application'), E_USER_NOTICE); + } + + if (Configure::read('Security.cipherSeed') === '76859309657453542496749683645') { + trigger_error(__d('cake_dev', 'Please change the value of \'Security.cipherSeed\' in app/Config/core.php to a numeric (digits only) seed value specific to your application'), E_USER_NOTICE); + } + } + +} diff --git a/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/File.php b/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/File.php new file mode 100644 index 0000000..6fe9399 --- /dev/null +++ b/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/File.php @@ -0,0 +1,568 @@ +<?php +/** + * Convenience class for reading, writing and appending to files. + * + * PHP 5 + * + * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) + * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * Redistributions of files must retain the above copyright notice. + * + * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://cakephp.org CakePHP(tm) Project + * @package Cake.Utility + * @since CakePHP(tm) v 0.2.9 + * @license MIT License (http://www.opensource.org/licenses/mit-license.php) + */ + +App::uses('Folder', 'Utility'); + +/** + * Convenience class for reading, writing and appending to files. + * + * @package Cake.Utility + */ +class File { + +/** + * Folder object of the File + * + * @var Folder + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::$Folder + */ + public $Folder = null; + +/** + * Filename + * + * @var string + * http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::$name + */ + public $name = null; + +/** + * File info + * + * @var array + * http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::$info + */ + public $info = array(); + +/** + * Holds the file handler resource if the file is opened + * + * @var resource + * http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::$handle + */ + public $handle = null; + +/** + * Enable locking for file reading and writing + * + * @var boolean + * http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::$lock + */ + public $lock = null; + +/** + * Path property + * + * Current file's absolute path + * + * @var mixed null + * http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::$path + */ + public $path = null; + +/** + * Constructor + * + * @param string $path Path to file + * @param boolean $create Create file if it does not exist (if true) + * @param integer $mode Mode to apply to the folder holding the file + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File + */ + public function __construct($path, $create = false, $mode = 0755) { + $this->Folder = new Folder(dirname($path), $create, $mode); + if (!is_dir($path)) { + $this->name = basename($path); + } + $this->pwd(); + $create && !$this->exists() && $this->safe($path) && $this->create(); + } + +/** + * Closes the current file if it is opened + * + */ + public function __destruct() { + $this->close(); + } + +/** + * Creates the File. + * + * @return boolean Success + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::create + */ + public function create() { + $dir = $this->Folder->pwd(); + if (is_dir($dir) && is_writable($dir) && !$this->exists()) { + if (touch($this->path)) { + return true; + } + } + return false; + } + +/** + * Opens the current file with a given $mode + * + * @param string $mode A valid 'fopen' mode string (r|w|a ...) + * @param boolean $force If true then the file will be re-opened even if its already opened, otherwise it won't + * @return boolean True on success, false on failure + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::open + */ + public function open($mode = 'r', $force = false) { + if (!$force && is_resource($this->handle)) { + return true; + } + clearstatcache(); + if ($this->exists() === false) { + if ($this->create() === false) { + return false; + } + } + + $this->handle = fopen($this->path, $mode); + if (is_resource($this->handle)) { + return true; + } + return false; + } + +/** + * Return the contents of this File as a string. + * + * @param string $bytes where to start + * @param string $mode A `fread` compatible mode. + * @param boolean $force If true then the file will be re-opened even if its already opened, otherwise it won't + * @return mixed string on success, false on failure + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::read + */ + public function read($bytes = false, $mode = 'rb', $force = false) { + if ($bytes === false && $this->lock === null) { + return file_get_contents($this->path); + } + if ($this->open($mode, $force) === false) { + return false; + } + if ($this->lock !== null && flock($this->handle, LOCK_SH) === false) { + return false; + } + if (is_int($bytes)) { + return fread($this->handle, $bytes); + } + + $data = ''; + while (!feof($this->handle)) { + $data .= fgets($this->handle, 4096); + } + + if ($this->lock !== null) { + flock($this->handle, LOCK_UN); + } + if ($bytes === false) { + $this->close(); + } + return trim($data); + } + +/** + * Sets or gets the offset for the currently opened file. + * + * @param integer|boolean $offset The $offset in bytes to seek. If set to false then the current offset is returned. + * @param integer $seek PHP Constant SEEK_SET | SEEK_CUR | SEEK_END determining what the $offset is relative to + * @return mixed True on success, false on failure (set mode), false on failure or integer offset on success (get mode) + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::offset + */ + public function offset($offset = false, $seek = SEEK_SET) { + if ($offset === false) { + if (is_resource($this->handle)) { + return ftell($this->handle); + } + } elseif ($this->open() === true) { + return fseek($this->handle, $offset, $seek) === 0; + } + return false; + } + +/** + * Prepares a ascii string for writing. Converts line endings to the + * correct terminator for the current platform. If windows "\r\n" will be used + * all other platforms will use "\n" + * + * @param string $data Data to prepare for writing. + * @param boolean $forceWindows + * @return string The with converted line endings. + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::prepare + */ + public static function prepare($data, $forceWindows = false) { + $lineBreak = "\n"; + if (DIRECTORY_SEPARATOR == '\\' || $forceWindows === true) { + $lineBreak = "\r\n"; + } + return strtr($data, array("\r\n" => $lineBreak, "\n" => $lineBreak, "\r" => $lineBreak)); + } + +/** + * Write given data to this File. + * + * @param string $data Data to write to this File. + * @param string $mode Mode of writing. {@link http://php.net/fwrite See fwrite()}. + * @param string $force force the file to open + * @return boolean Success + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::write + */ + public function write($data, $mode = 'w', $force = false) { + $success = false; + if ($this->open($mode, $force) === true) { + if ($this->lock !== null) { + if (flock($this->handle, LOCK_EX) === false) { + return false; + } + } + + if (fwrite($this->handle, $data) !== false) { + $success = true; + } + if ($this->lock !== null) { + flock($this->handle, LOCK_UN); + } + } + return $success; + } + +/** + * Append given data string to this File. + * + * @param string $data Data to write + * @param string $force force the file to open + * @return boolean Success + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::append + */ + public function append($data, $force = false) { + return $this->write($data, 'a', $force); + } + +/** + * Closes the current file if it is opened. + * + * @return boolean True if closing was successful or file was already closed, otherwise false + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::close + */ + public function close() { + if (!is_resource($this->handle)) { + return true; + } + return fclose($this->handle); + } + +/** + * Deletes the File. + * + * @return boolean Success + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::delete + */ + public function delete() { + clearstatcache(); + if (is_resource($this->handle)) { + fclose($this->handle); + $this->handle = null; + } + if ($this->exists()) { + return unlink($this->path); + } + return false; + } + +/** + * Returns the File info as an array with the following keys: + * + * - dirname + * - basename + * - extension + * - filename + * - filesize + * - mime + * + * @return array File information. + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::info + */ + public function info() { + if ($this->info == null) { + $this->info = pathinfo($this->path); + } + if (!isset($this->info['filename'])) { + $this->info['filename'] = $this->name(); + } + if (!isset($this->info['filesize'])) { + $this->info['filesize'] = $this->size(); + } + if (!isset($this->info['mime'])) { + $this->info['mime'] = $this->mime(); + } + return $this->info; + } + +/** + * Returns the File extension. + * + * @return string The File extension + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::ext + */ + public function ext() { + if ($this->info == null) { + $this->info(); + } + if (isset($this->info['extension'])) { + return $this->info['extension']; + } + return false; + } + +/** + * Returns the File name without extension. + * + * @return string The File name without extension. + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::name + */ + public function name() { + if ($this->info == null) { + $this->info(); + } + if (isset($this->info['extension'])) { + return basename($this->name, '.' . $this->info['extension']); + } elseif ($this->name) { + return $this->name; + } + return false; + } + +/** + * makes filename safe for saving + * + * @param string $name The name of the file to make safe if different from $this->name + * @param string $ext The name of the extension to make safe if different from $this->ext + * @return string $ext the extension of the file + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::safe + */ + public function safe($name = null, $ext = null) { + if (!$name) { + $name = $this->name; + } + if (!$ext) { + $ext = $this->ext(); + } + return preg_replace("/(?:[^\w\.-]+)/", "_", basename($name, $ext)); + } + +/** + * Get md5 Checksum of file with previous check of Filesize + * + * @param integer|boolean $maxsize in MB or true to force + * @return string md5 Checksum {@link http://php.net/md5_file See md5_file()} + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::md5 + */ + public function md5($maxsize = 5) { + if ($maxsize === true) { + return md5_file($this->path); + } + + $size = $this->size(); + if ($size && $size < ($maxsize * 1024) * 1024) { + return md5_file($this->path); + } + + return false; + } + +/** + * Returns the full path of the File. + * + * @return string Full path to file + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::pwd + */ + public function pwd() { + if (is_null($this->path)) { + $this->path = $this->Folder->slashTerm($this->Folder->pwd()) . $this->name; + } + return $this->path; + } + +/** + * Returns true if the File exists. + * + * @return boolean true if it exists, false otherwise + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::exists + */ + public function exists() { + return (file_exists($this->path) && is_file($this->path)); + } + +/** + * Returns the "chmod" (permissions) of the File. + * + * @return string Permissions for the file + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::perms + */ + public function perms() { + if ($this->exists()) { + return substr(sprintf('%o', fileperms($this->path)), -4); + } + return false; + } + +/** + * Returns the Filesize + * + * @return integer size of the file in bytes, or false in case of an error + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::size + */ + public function size() { + if ($this->exists()) { + return filesize($this->path); + } + return false; + } + +/** + * Returns true if the File is writable. + * + * @return boolean true if its writable, false otherwise + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::writable + */ + public function writable() { + return is_writable($this->path); + } + +/** + * Returns true if the File is executable. + * + * @return boolean true if its executable, false otherwise + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::executable + */ + public function executable() { + return is_executable($this->path); + } + +/** + * Returns true if the File is readable. + * + * @return boolean true if file is readable, false otherwise + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::readable + */ + public function readable() { + return is_readable($this->path); + } + +/** + * Returns the File's owner. + * + * @return integer the Fileowner + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::owner + */ + public function owner() { + if ($this->exists()) { + return fileowner($this->path); + } + return false; + } + +/** + * Returns the File's group. + * + * @return integer the Filegroup + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::group + */ + public function group() { + if ($this->exists()) { + return filegroup($this->path); + } + return false; + } + +/** + * Returns last access time. + * + * @return integer timestamp Timestamp of last access time + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::lastAccess + */ + public function lastAccess() { + if ($this->exists()) { + return fileatime($this->path); + } + return false; + } + +/** + * Returns last modified time. + * + * @return integer timestamp Timestamp of last modification + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::lastChange + */ + public function lastChange() { + if ($this->exists()) { + return filemtime($this->path); + } + return false; + } + +/** + * Returns the current folder. + * + * @return Folder Current folder + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::Folder + */ + public function &folder() { + return $this->Folder; + } + +/** + * Copy the File to $dest + * + * @param string $dest destination for the copy + * @param boolean $overwrite Overwrite $dest if exists + * @return boolean Success + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::copy + */ + public function copy($dest, $overwrite = true) { + if (!$this->exists() || is_file($dest) && !$overwrite) { + return false; + } + return copy($this->path, $dest); + } + +/** + * Get the mime type of the file. Uses the finfo extension if + * its available, otherwise falls back to mime_content_type + * + * @return false|string The mimetype of the file, or false if reading fails. + */ + public function mime() { + if (!$this->exists()) { + return false; + } + if (function_exists('finfo_open')) { + $finfo = finfo_open(FILEINFO_MIME); + list($type, $charset) = explode(';', finfo_file($finfo, $this->pwd())); + return $type; + } elseif (function_exists('mime_content_type')) { + return mime_content_type($this->pwd()); + } + return false; + } + +} diff --git a/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/Folder.php b/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/Folder.php new file mode 100644 index 0000000..08895bf --- /dev/null +++ b/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/Folder.php @@ -0,0 +1,780 @@ +<?php +/** + * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) + * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * Redistributions of files must retain the above copyright notice. + * + * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://cakephp.org CakePHP(tm) Project + * @package Cake.Utility + * @since CakePHP(tm) v 0.2.9 + * @license MIT License (http://www.opensource.org/licenses/mit-license.php) + */ + +/** + * Folder structure browser, lists folders and files. + * Provides an Object interface for Common directory related tasks. + * + * @package Cake.Utility + */ +class Folder { + +/** + * Path to Folder. + * + * @var string + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#Folder::$path + */ + public $path = null; + +/** + * Sortedness. Whether or not list results + * should be sorted by name. + * + * @var boolean + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#Folder::$sort + */ + public $sort = false; + +/** + * Mode to be used on create. Does nothing on windows platforms. + * + * @var integer + * http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#Folder::$mode + */ + public $mode = 0755; + +/** + * Holds messages from last method. + * + * @var array + */ + protected $_messages = array(); + +/** + * Holds errors from last method. + * + * @var array + */ + protected $_errors = array(); + +/** + * Holds array of complete directory paths. + * + * @var array + */ + protected $_directories; + +/** + * Holds array of complete file paths. + * + * @var array + */ + protected $_files; + +/** + * Constructor. + * + * @param string $path Path to folder + * @param boolean $create Create folder if not found + * @param string|boolean $mode Mode (CHMOD) to apply to created folder, false to ignore + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#Folder + */ + public function __construct($path = false, $create = false, $mode = false) { + if (empty($path)) { + $path = TMP; + } + if ($mode) { + $this->mode = $mode; + } + + if (!file_exists($path) && $create === true) { + $this->create($path, $this->mode); + } + if (!Folder::isAbsolute($path)) { + $path = realpath($path); + } + if (!empty($path)) { + $this->cd($path); + } + } + +/** + * Return current path. + * + * @return string Current path + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#Folder::pwd + */ + public function pwd() { + return $this->path; + } + +/** + * Change directory to $path. + * + * @param string $path Path to the directory to change to + * @return string The new path. Returns false on failure + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#Folder::cd + */ + public function cd($path) { + $path = $this->realpath($path); + if (is_dir($path)) { + return $this->path = $path; + } + return false; + } + +/** + * Returns an array of the contents of the current directory. + * The returned array holds two arrays: One of directories and one of files. + * + * @param boolean $sort Whether you want the results sorted, set this and the sort property + * to false to get unsorted results. + * @param array|boolean $exceptions Either an array or boolean true will not grab dot files + * @param boolean $fullPath True returns the full path + * @return mixed Contents of current directory as an array, an empty array on failure + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#Folder::read + */ + public function read($sort = true, $exceptions = false, $fullPath = false) { + $dirs = $files = array(); + + if (!$this->pwd()) { + return array($dirs, $files); + } + if (is_array($exceptions)) { + $exceptions = array_flip($exceptions); + } + $skipHidden = isset($exceptions['.']) || $exceptions === true; + + try { + $iterator = new DirectoryIterator($this->path); + } catch (Exception $e) { + return array($dirs, $files); + } + + foreach ($iterator as $item) { + if ($item->isDot()) { + continue; + } + $name = $item->getFileName(); + if ($skipHidden && $name[0] === '.' || isset($exceptions[$name])) { + continue; + } + if ($fullPath) { + $name = $item->getPathName(); + } + if ($item->isDir()) { + $dirs[] = $name; + } else { + $files[] = $name; + } + } + if ($sort || $this->sort) { + sort($dirs); + sort($files); + } + return array($dirs, $files); + } + +/** + * Returns an array of all matching files in current directory. + * + * @param string $regexpPattern Preg_match pattern (Defaults to: .*) + * @param boolean $sort Whether results should be sorted. + * @return array Files that match given pattern + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#Folder::find + */ + public function find($regexpPattern = '.*', $sort = false) { + list($dirs, $files) = $this->read($sort); + return array_values(preg_grep('/^' . $regexpPattern . '$/i', $files)); + } + +/** + * Returns an array of all matching files in and below current directory. + * + * @param string $pattern Preg_match pattern (Defaults to: .*) + * @param boolean $sort Whether results should be sorted. + * @return array Files matching $pattern + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#Folder::findRecursive + */ + public function findRecursive($pattern = '.*', $sort = false) { + if (!$this->pwd()) { + return array(); + } + $startsOn = $this->path; + $out = $this->_findRecursive($pattern, $sort); + $this->cd($startsOn); + return $out; + } + +/** + * Private helper function for findRecursive. + * + * @param string $pattern Pattern to match against + * @param boolean $sort Whether results should be sorted. + * @return array Files matching pattern + */ + protected function _findRecursive($pattern, $sort = false) { + list($dirs, $files) = $this->read($sort); + $found = array(); + + foreach ($files as $file) { + if (preg_match('/^' . $pattern . '$/i', $file)) { + $found[] = Folder::addPathElement($this->path, $file); + } + } + $start = $this->path; + + foreach ($dirs as $dir) { + $this->cd(Folder::addPathElement($start, $dir)); + $found = array_merge($found, $this->findRecursive($pattern, $sort)); + } + return $found; + } + +/** + * Returns true if given $path is a Windows path. + * + * @param string $path Path to check + * @return boolean true if windows path, false otherwise + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#Folder::isWindowsPath + */ + public static function isWindowsPath($path) { + return (preg_match('/^[A-Z]:\\\\/i', $path) || substr($path, 0, 2) == '\\\\'); + } + +/** + * Returns true if given $path is an absolute path. + * + * @param string $path Path to check + * @return boolean true if path is absolute. + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#Folder::isAbsolute + */ + public static function isAbsolute($path) { + return !empty($path) && ($path[0] === '/' || preg_match('/^[A-Z]:\\\\/i', $path) || substr($path, 0, 2) == '\\\\'); + } + +/** + * Returns a correct set of slashes for given $path. (\\ for Windows paths and / for other paths.) + * + * @param string $path Path to check + * @return string Set of slashes ("\\" or "/") + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#Folder::normalizePath + */ + public static function normalizePath($path) { + return Folder::correctSlashFor($path); + } + +/** + * Returns a correct set of slashes for given $path. (\\ for Windows paths and / for other paths.) + * + * @param string $path Path to check + * @return string Set of slashes ("\\" or "/") + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#Folder::correctSlashFor + */ + public static function correctSlashFor($path) { + return (Folder::isWindowsPath($path)) ? '\\' : '/'; + } + +/** + * Returns $path with added terminating slash (corrected for Windows or other OS). + * + * @param string $path Path to check + * @return string Path with ending slash + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#Folder::slashTerm + */ + public static function slashTerm($path) { + if (Folder::isSlashTerm($path)) { + return $path; + } + return $path . Folder::correctSlashFor($path); + } + +/** + * Returns $path with $element added, with correct slash in-between. + * + * @param string $path Path + * @param string $element Element to and at end of path + * @return string Combined path + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#Folder::addPathElement + */ + public static function addPathElement($path, $element) { + return rtrim($path, DS) . DS . $element; + } + +/** + * Returns true if the File is in a given CakePath. + * + * @param string $path The path to check. + * @return boolean + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#Folder::inCakePath + */ + public function inCakePath($path = '') { + $dir = substr(Folder::slashTerm(ROOT), 0, -1); + $newdir = $dir . $path; + + return $this->inPath($newdir); + } + +/** + * Returns true if the File is in given path. + * + * @param string $path The path to check that the current pwd() resides with in. + * @param boolean $reverse Reverse the search, check that pwd() resides within $path. + * @return boolean + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#Folder::inPath + */ + public function inPath($path = '', $reverse = false) { + $dir = Folder::slashTerm($path); + $current = Folder::slashTerm($this->pwd()); + + if (!$reverse) { + $return = preg_match('/^(.*)' . preg_quote($dir, '/') . '(.*)/', $current); + } else { + $return = preg_match('/^(.*)' . preg_quote($current, '/') . '(.*)/', $dir); + } + return (bool)$return; + } + +/** + * Change the mode on a directory structure recursively. This includes changing the mode on files as well. + * + * @param string $path The path to chmod + * @param integer $mode octal value 0755 + * @param boolean $recursive chmod recursively, set to false to only change the current directory. + * @param array $exceptions array of files, directories to skip + * @return boolean Returns TRUE on success, FALSE on failure + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#Folder::chmod + */ + public function chmod($path, $mode = false, $recursive = true, $exceptions = array()) { + if (!$mode) { + $mode = $this->mode; + } + + if ($recursive === false && is_dir($path)) { + if (@chmod($path, intval($mode, 8))) { + $this->_messages[] = __d('cake_dev', '%s changed to %s', $path, $mode); + return true; + } + + $this->_errors[] = __d('cake_dev', '%s NOT changed to %s', $path, $mode); + return false; + } + + if (is_dir($path)) { + $paths = $this->tree($path); + + foreach ($paths as $type) { + foreach ($type as $key => $fullpath) { + $check = explode(DS, $fullpath); + $count = count($check); + + if (in_array($check[$count - 1], $exceptions)) { + continue; + } + + if (@chmod($fullpath, intval($mode, 8))) { + $this->_messages[] = __d('cake_dev', '%s changed to %s', $fullpath, $mode); + } else { + $this->_errors[] = __d('cake_dev', '%s NOT changed to %s', $fullpath, $mode); + } + } + } + + if (empty($this->_errors)) { + return true; + } + } + return false; + } + +/** + * Returns an array of nested directories and files in each directory + * + * @param string $path the directory path to build the tree from + * @param array|boolean $exceptions Either an array of files/folder to exclude + * or boolean true to not grab dot files/folders + * @param string $type either 'file' or 'dir'. null returns both files and directories + * @return mixed array of nested directories and files in each directory + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#Folder::tree + */ + public function tree($path = null, $exceptions = false, $type = null) { + if ($path == null) { + $path = $this->path; + } + $files = array(); + $directories = array($path); + + if (is_array($exceptions)) { + $exceptions = array_flip($exceptions); + } + $skipHidden = false; + if ($exceptions === true) { + $skipHidden = true; + } elseif (isset($exceptions['.'])) { + $skipHidden = true; + unset($exceptions['.']); + } + + try { + $directory = new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::KEY_AS_PATHNAME | RecursiveDirectoryIterator::CURRENT_AS_SELF); + $iterator = new RecursiveIteratorIterator($directory, RecursiveIteratorIterator::SELF_FIRST); + } catch (Exception $e) { + if ($type === null) { + return array(array(), array()); + } + return array(); + } + + foreach ($iterator as $itemPath => $fsIterator) { + if ($skipHidden) { + $subPathName = $fsIterator->getSubPathname(); + if ($subPathName{0} == '.' || strpos($subPathName, DS . '.') !== false) { + continue; + } + } + $item = $fsIterator->current(); + if (!empty($exceptions) && isset($exceptions[$item->getFilename()])) { + continue; + } + + if ($item->isFile()) { + $files[] = $itemPath; + } elseif ($item->isDir() && !$item->isDot()) { + $directories[] = $itemPath; + } + } + if ($type === null) { + return array($directories, $files); + } + if ($type === 'dir') { + return $directories; + } + return $files; + } + +/** + * Create a directory structure recursively. Can be used to create + * deep path structures like `/foo/bar/baz/shoe/horn` + * + * @param string $pathname The directory structure to create + * @param integer $mode octal value 0755 + * @return boolean Returns TRUE on success, FALSE on failure + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#Folder::create + */ + public function create($pathname, $mode = false) { + if (is_dir($pathname) || empty($pathname)) { + return true; + } + + if (!$mode) { + $mode = $this->mode; + } + + if (is_file($pathname)) { + $this->_errors[] = __d('cake_dev', '%s is a file', $pathname); + return false; + } + $pathname = rtrim($pathname, DS); + $nextPathname = substr($pathname, 0, strrpos($pathname, DS)); + + if ($this->create($nextPathname, $mode)) { + if (!file_exists($pathname)) { + $old = umask(0); + if (mkdir($pathname, $mode)) { + umask($old); + $this->_messages[] = __d('cake_dev', '%s created', $pathname); + return true; + } else { + umask($old); + $this->_errors[] = __d('cake_dev', '%s NOT created', $pathname); + return false; + } + } + } + return false; + } + +/** + * Returns the size in bytes of this Folder and its contents. + * + * @return integer size in bytes of current folder + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#Folder::dirsize + */ + public function dirsize() { + $size = 0; + $directory = Folder::slashTerm($this->path); + $stack = array($directory); + $count = count($stack); + for ($i = 0, $j = $count; $i < $j; ++$i) { + if (is_file($stack[$i])) { + $size += filesize($stack[$i]); + } elseif (is_dir($stack[$i])) { + $dir = dir($stack[$i]); + if ($dir) { + while (false !== ($entry = $dir->read())) { + if ($entry === '.' || $entry === '..') { + continue; + } + $add = $stack[$i] . $entry; + + if (is_dir($stack[$i] . $entry)) { + $add = Folder::slashTerm($add); + } + $stack[] = $add; + } + $dir->close(); + } + } + $j = count($stack); + } + return $size; + } + +/** + * Recursively Remove directories if the system allows. + * + * @param string $path Path of directory to delete + * @return boolean Success + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#Folder::delete + */ + public function delete($path = null) { + if (!$path) { + $path = $this->pwd(); + } + if (!$path) { + return null; + } + $path = Folder::slashTerm($path); + if (is_dir($path)) { + try { + $directory = new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::CURRENT_AS_SELF); + $iterator = new RecursiveIteratorIterator($directory, RecursiveIteratorIterator::CHILD_FIRST); + } catch (Exception $e) { + return false; + } + + foreach ($iterator as $item) { + $filePath = $item->getPathname(); + if ($item->isFile() || $item->isLink()) { + if (@unlink($filePath)) { + $this->_messages[] = __d('cake_dev', '%s removed', $filePath); + } else { + $this->_errors[] = __d('cake_dev', '%s NOT removed', $filePath); + } + } elseif ($item->isDir() && !$item->isDot()) { + if (@rmdir($filePath)) { + $this->_messages[] = __d('cake_dev', '%s removed', $filePath); + } else { + $this->_errors[] = __d('cake_dev', '%s NOT removed', $filePath); + return false; + } + } + } + + $path = rtrim($path, DS); + if (@rmdir($path)) { + $this->_messages[] = __d('cake_dev', '%s removed', $path); + } else { + $this->_errors[] = __d('cake_dev', '%s NOT removed', $path); + return false; + } + } + return true; + } + +/** + * Recursive directory copy. + * + * ### Options + * + * - `to` The directory to copy to. + * - `from` The directory to copy from, this will cause a cd() to occur, changing the results of pwd(). + * - `mode` The mode to copy the files/directories with. + * - `skip` Files/directories to skip. + * + * @param array|string $options Either an array of options (see above) or a string of the destination directory. + * @return boolean Success + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#Folder::copy + */ + public function copy($options = array()) { + if (!$this->pwd()) { + return false; + } + $to = null; + if (is_string($options)) { + $to = $options; + $options = array(); + } + $options = array_merge(array('to' => $to, 'from' => $this->path, 'mode' => $this->mode, 'skip' => array()), $options); + + $fromDir = $options['from']; + $toDir = $options['to']; + $mode = $options['mode']; + + if (!$this->cd($fromDir)) { + $this->_errors[] = __d('cake_dev', '%s not found', $fromDir); + return false; + } + + if (!is_dir($toDir)) { + $this->create($toDir, $mode); + } + + if (!is_writable($toDir)) { + $this->_errors[] = __d('cake_dev', '%s not writable', $toDir); + return false; + } + + $exceptions = array_merge(array('.', '..', '.svn'), $options['skip']); + if ($handle = @opendir($fromDir)) { + while (false !== ($item = readdir($handle))) { + if (!in_array($item, $exceptions)) { + $from = Folder::addPathElement($fromDir, $item); + $to = Folder::addPathElement($toDir, $item); + if (is_file($from)) { + if (copy($from, $to)) { + chmod($to, intval($mode, 8)); + touch($to, filemtime($from)); + $this->_messages[] = __d('cake_dev', '%s copied to %s', $from, $to); + } else { + $this->_errors[] = __d('cake_dev', '%s NOT copied to %s', $from, $to); + } + } + + if (is_dir($from) && !file_exists($to)) { + $old = umask(0); + if (mkdir($to, $mode)) { + umask($old); + $old = umask(0); + chmod($to, $mode); + umask($old); + $this->_messages[] = __d('cake_dev', '%s created', $to); + $options = array_merge($options, array('to' => $to, 'from' => $from)); + $this->copy($options); + } else { + $this->_errors[] = __d('cake_dev', '%s not created', $to); + } + } + } + } + closedir($handle); + } else { + return false; + } + + if (!empty($this->_errors)) { + return false; + } + return true; + } + +/** + * Recursive directory move. + * + * ### Options + * + * - `to` The directory to copy to. + * - `from` The directory to copy from, this will cause a cd() to occur, changing the results of pwd(). + * - `chmod` The mode to copy the files/directories with. + * - `skip` Files/directories to skip. + * + * @param array $options (to, from, chmod, skip) + * @return boolean Success + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#Folder::move + */ + public function move($options) { + $to = null; + if (is_string($options)) { + $to = $options; + $options = (array)$options; + } + $options = array_merge( + array('to' => $to, 'from' => $this->path, 'mode' => $this->mode, 'skip' => array()), + $options + ); + + if ($this->copy($options)) { + if ($this->delete($options['from'])) { + return (bool)$this->cd($options['to']); + } + } + return false; + } + +/** + * get messages from latest method + * + * @return array + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#Folder::messages + */ + public function messages() { + return $this->_messages; + } + +/** + * get error from latest method + * + * @return array + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#Folder::errors + */ + public function errors() { + return $this->_errors; + } + +/** + * Get the real path (taking ".." and such into account) + * + * @param string $path Path to resolve + * @return string The resolved path + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#Folder::realpath + */ + public function realpath($path) { + $path = str_replace('/', DS, trim($path)); + if (strpos($path, '..') === false) { + if (!Folder::isAbsolute($path)) { + $path = Folder::addPathElement($this->path, $path); + } + return $path; + } + $parts = explode(DS, $path); + $newparts = array(); + $newpath = ''; + if ($path[0] === DS) { + $newpath = DS; + } + + while (($part = array_shift($parts)) !== null) { + if ($part === '.' || $part === '') { + continue; + } + if ($part === '..') { + if (!empty($newparts)) { + array_pop($newparts); + continue; + } else { + return false; + } + } + $newparts[] = $part; + } + $newpath .= implode(DS, $newparts); + + return Folder::slashTerm($newpath); + } + +/** + * Returns true if given $path ends in a slash (i.e. is slash-terminated). + * + * @param string $path Path to check + * @return boolean true if path ends with slash, false otherwise + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#Folder::isSlashTerm + */ + public static function isSlashTerm($path) { + $lastChar = $path[strlen($path) - 1]; + return $lastChar === '/' || $lastChar === '\\'; + } + +} diff --git a/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/Hash.php b/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/Hash.php new file mode 100644 index 0000000..9514ccc --- /dev/null +++ b/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/Hash.php @@ -0,0 +1,974 @@ +<?php +/** + * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) + * Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * Redistributions of files must retain the above copyright notice. + * + * @copyright Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://cakephp.org CakePHP(tm) Project + * @package Cake.Utility + * @since CakePHP(tm) v 2.2.0 + * @license MIT License (http://www.opensource.org/licenses/mit-license.php) + */ + +App::uses('String', 'Utility'); + +/** + * Library of array functions for manipulating and extracting data + * from arrays or 'sets' of data. + * + * `Hash` provides an improved interface, more consistent and + * predictable set of features over `Set`. While it lacks the spotty + * support for pseudo Xpath, its more fully featured dot notation provides + * similar features in a more consistent implementation. + * + * @package Cake.Utility + */ +class Hash { + +/** + * Get a single value specified by $path out of $data. + * Does not support the full dot notation feature set, + * but is faster for simple read operations. + * + * @param array $data Array of data to operate on. + * @param string|array $path The path being searched for. Either a dot + * separated string, or an array of path segments. + * @return mixed The value fetched from the array, or null. + */ + public static function get(array $data, $path) { + if (empty($data) || empty($path)) { + return null; + } + if (is_string($path)) { + $parts = explode('.', $path); + } else { + $parts = $path; + } + foreach ($parts as $key) { + if (is_array($data) && isset($data[$key])) { + $data =& $data[$key]; + } else { + return null; + } + + } + return $data; + } + +/** + * Gets the values from an array matching the $path expression. + * The path expression is a dot separated expression, that can contain a set + * of patterns and expressions: + * + * - `{n}` Matches any numeric key, or integer. + * - `{s}` Matches any string key. + * - `Foo` Matches any key with the exact same value. + * + * There are a number of attribute operators: + * + * - `=`, `!=` Equality. + * - `>`, `<`, `>=`, `<=` Value comparison. + * - `=/.../` Regular expression pattern match. + * + * Given a set of User array data, from a `$User->find('all')` call: + * + * - `1.User.name` Get the name of the user at index 1. + * - `{n}.User.name` Get the name of every user in the set of users. + * - `{n}.User[id]` Get the name of every user with an id key. + * - `{n}.User[id>=2]` Get the name of every user with an id key greater than or equal to 2. + * - `{n}.User[username=/^paul/]` Get User elements with username matching `^paul`. + * + * @param array $data The data to extract from. + * @param string $path The path to extract. + * @return array An array of the extracted values. Returns an empty array + * if there are no matches. + */ + public static function extract(array $data, $path) { + if (empty($path)) { + return $data; + } + + // Simple paths. + if (!preg_match('/[{\[]/', $path)) { + return (array)self::get($data, $path); + } + + if (strpos('[', $path) === false) { + $tokens = explode('.', $path); + } else { + $tokens = String::tokenize($path, '.', '[', ']'); + } + + $_key = '__set_item__'; + + $context = array($_key => array($data)); + + foreach ($tokens as $token) { + $next = array(); + + $conditions = false; + $position = strpos($token, '['); + if ($position !== false) { + $conditions = substr($token, $position); + $token = substr($token, 0, $position); + } + + foreach ($context[$_key] as $item) { + foreach ($item as $k => $v) { + if (self::_matchToken($k, $token)) { + $next[] = $v; + } + } + } + + // Filter for attributes. + if ($conditions) { + $filter = array(); + foreach ($next as $item) { + if (self::_matches($item, $conditions)) { + $filter[] = $item; + } + } + $next = $filter; + } + $context = array($_key => $next); + + } + return $context[$_key]; + } + +/** + * Check a key against a token. + * + * @param string $key The key in the array being searched. + * @param string $token The token being matched. + * @return boolean + */ + protected static function _matchToken($key, $token) { + if ($token === '{n}') { + return is_numeric($key); + } + if ($token === '{s}') { + return is_string($key); + } + if (is_numeric($token)) { + return ($key == $token); + } + return ($key === $token); + } + +/** + * Checks whether or not $data matches the attribute patterns + * + * @param array $data Array of data to match. + * @param string $selector The patterns to match. + * @return boolean Fitness of expression. + */ + protected static function _matches(array $data, $selector) { + preg_match_all( + '/(\[ (?<attr>[^=><!]+?) (\s* (?<op>[><!]?[=]|[><]) \s* (?<val>[^\]]+) )? \])/x', + $selector, + $conditions, + PREG_SET_ORDER + ); + + foreach ($conditions as $cond) { + $attr = $cond['attr']; + $op = isset($cond['op']) ? $cond['op'] : null; + $val = isset($cond['val']) ? $cond['val'] : null; + + // Presence test. + if (empty($op) && empty($val) && !isset($data[$attr])) { + return false; + } + + // Empty attribute = fail. + if (!(isset($data[$attr]) || array_key_exists($attr, $data))) { + return false; + } + + $prop = isset($data[$attr]) ? $data[$attr] : null; + + // Pattern matches and other operators. + if ($op === '=' && $val && $val[0] === '/') { + if (!preg_match($val, $prop)) { + return false; + } + } elseif ( + ($op === '=' && $prop != $val) || + ($op === '!=' && $prop == $val) || + ($op === '>' && $prop <= $val) || + ($op === '<' && $prop >= $val) || + ($op === '>=' && $prop < $val) || + ($op === '<=' && $prop > $val) + ) { + return false; + } + + } + return true; + } + +/** + * Insert $values into an array with the given $path. You can use + * `{n}` and `{s}` elements to insert $data multiple times. + * + * @param array $data The data to insert into. + * @param string $path The path to insert at. + * @param array $values The values to insert. + * @return array The data with $values inserted. + */ + public static function insert(array $data, $path, $values = null) { + $tokens = explode('.', $path); + if (strpos($path, '{') === false) { + return self::_simpleOp('insert', $data, $tokens, $values); + } + + $token = array_shift($tokens); + $nextPath = implode('.', $tokens); + foreach ($data as $k => $v) { + if (self::_matchToken($k, $token)) { + $data[$k] = self::insert($v, $nextPath, $values); + } + } + return $data; + } + +/** + * Perform a simple insert/remove operation. + * + * @param string $op The operation to do. + * @param array $data The data to operate on. + * @param array $path The path to work on. + * @param mixed $values The values to insert when doing inserts. + * @return array $data. + */ + protected static function _simpleOp($op, $data, $path, $values = null) { + $_list =& $data; + + $count = count($path); + $last = $count - 1; + foreach ($path as $i => $key) { + if (is_numeric($key) && intval($key) > 0 || $key === '0') { + $key = intval($key); + } + if ($op === 'insert') { + if ($i === $last) { + $_list[$key] = $values; + return $data; + } + if (!isset($_list[$key])) { + $_list[$key] = array(); + } + $_list =& $_list[$key]; + if (!is_array($_list)) { + $_list = array(); + } + } elseif ($op === 'remove') { + if ($i === $last) { + unset($_list[$key]); + return $data; + } + if (!isset($_list[$key])) { + return $data; + } + $_list =& $_list[$key]; + } + } + } + +/** + * Remove data matching $path from the $data array. + * You can use `{n}` and `{s}` to remove multiple elements + * from $data. + * + * @param array $data The data to operate on + * @param string $path A path expression to use to remove. + * @return array The modified array. + */ + public static function remove(array $data, $path) { + $tokens = explode('.', $path); + if (strpos($path, '{') === false) { + return self::_simpleOp('remove', $data, $tokens); + } + + $token = array_shift($tokens); + $nextPath = implode('.', $tokens); + foreach ($data as $k => $v) { + $match = self::_matchToken($k, $token); + if ($match && is_array($v)) { + $data[$k] = self::remove($v, $nextPath); + } elseif ($match) { + unset($data[$k]); + } + } + return $data; + } + +/** + * Creates an associative array using `$keyPath` as the path to build its keys, and optionally + * `$valuePath` as path to get the values. If `$valuePath` is not specified, all values will be initialized + * to null (useful for Hash::merge). You can optionally group the values by what is obtained when + * following the path specified in `$groupPath`. + * + * @param array $data Array from where to extract keys and values + * @param string $keyPath A dot-separated string. + * @param string $valuePath A dot-separated string. + * @param string $groupPath A dot-separated string. + * @return array Combined array + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/hash.html#Hash::combine + */ + public static function combine(array $data, $keyPath, $valuePath = null, $groupPath = null) { + if (empty($data)) { + return array(); + } + + if (is_array($keyPath)) { + $format = array_shift($keyPath); + $keys = self::format($data, $keyPath, $format); + } else { + $keys = self::extract($data, $keyPath); + } + if (empty($keys)) { + return array(); + } + + if (!empty($valuePath) && is_array($valuePath)) { + $format = array_shift($valuePath); + $vals = self::format($data, $valuePath, $format); + } elseif (!empty($valuePath)) { + $vals = self::extract($data, $valuePath); + } + + $count = count($keys); + for ($i = 0; $i < $count; $i++) { + $vals[$i] = isset($vals[$i]) ? $vals[$i] : null; + } + + if ($groupPath !== null) { + $group = self::extract($data, $groupPath); + if (!empty($group)) { + $c = count($keys); + for ($i = 0; $i < $c; $i++) { + if (!isset($group[$i])) { + $group[$i] = 0; + } + if (!isset($out[$group[$i]])) { + $out[$group[$i]] = array(); + } + $out[$group[$i]][$keys[$i]] = $vals[$i]; + } + return $out; + } + } + if (empty($vals)) { + return array(); + } + return array_combine($keys, $vals); + } + +/** + * Returns a formated series of values extracted from `$data`, using + * `$format` as the format and `$paths` as the values to extract. + * + * Usage: + * + * {{{ + * $result = Hash::format($users, array('{n}.User.id', '{n}.User.name'), '%s : %s'); + * }}} + * + * The `$format` string can use any format options that `vsprintf()` and `sprintf()` do. + * + * @param array $data Source array from which to extract the data + * @param string $paths An array containing one or more Hash::extract()-style key paths + * @param string $format Format string into which values will be inserted, see sprintf() + * @return array An array of strings extracted from `$path` and formatted with `$format` + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/hash.html#Hash::format + * @see sprintf() + * @see Hash::extract() + */ + public static function format(array $data, array $paths, $format) { + $extracted = array(); + $count = count($paths); + + if (!$count) { + return; + } + + for ($i = 0; $i < $count; $i++) { + $extracted[] = self::extract($data, $paths[$i]); + } + $out = array(); + $data = $extracted; + $count = count($data[0]); + + $countTwo = count($data); + for ($j = 0; $j < $count; $j++) { + $args = array(); + for ($i = 0; $i < $countTwo; $i++) { + if (array_key_exists($j, $data[$i])) { + $args[] = $data[$i][$j]; + } + } + $out[] = vsprintf($format, $args); + } + return $out; + } + +/** + * Determines if one array contains the exact keys and values of another. + * + * @param array $data The data to search through. + * @param array $needle The values to file in $data + * @return boolean true if $data contains $needle, false otherwise + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/hash.html#Hash::contains + */ + public static function contains(array $data, array $needle) { + if (empty($data) || empty($needle)) { + return false; + } + $stack = array(); + + $i = 1; + while (!empty($needle)) { + $key = key($needle); + $val = $needle[$key]; + unset($needle[$key]); + + if (isset($data[$key]) && is_array($val)) { + $next = $data[$key]; + unset($data[$key]); + + if (!empty($val)) { + $stack[] = array($val, $next); + } + } elseif (!isset($data[$key]) || $data[$key] != $val) { + return false; + } + + if (empty($needle) && !empty($stack)) { + list($needle, $data) = array_pop($stack); + } + } + return true; + } + +/** + * Test whether or not a given path exists in $data. + * This method uses the same path syntax as Hash::extract() + * + * Checking for paths that could target more than one element will + * make sure that at least one matching element exists. + * + * @param array $data The data to check. + * @param string $path The path to check for. + * @return boolean Existence of path. + * @see Hash::extract() + */ + public static function check(array $data, $path) { + $results = self::extract($data, $path); + if (!is_array($results)) { + return false; + } + return count($results) > 0; + } + +/** + * Recursively filters a data set. + * + * @param array $data Either an array to filter, or value when in callback + * @param callable $callback A function to filter the data with. Defaults to + * `self::_filter()` Which strips out all non-zero empty values. + * @return array Filtered array + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/hash.html#Hash::filter + */ + public static function filter(array $data, $callback = array('self', '_filter')) { + foreach ($data as $k => $v) { + if (is_array($v)) { + $data[$k] = self::filter($v, $callback); + } + } + return array_filter($data, $callback); + } + +/** + * Callback function for filtering. + * + * @param array $var Array to filter. + * @return boolean + */ + protected static function _filter($var) { + if ($var === 0 || $var === '0' || !empty($var)) { + return true; + } + return false; + } + +/** + * Collapses a multi-dimensional array into a single dimension, using a delimited array path for + * each array element's key, i.e. array(array('Foo' => array('Bar' => 'Far'))) becomes + * array('0.Foo.Bar' => 'Far').) + * + * @param array $data Array to flatten + * @param string $separator String used to separate array key elements in a path, defaults to '.' + * @return array + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/hash.html#Hash::flatten + */ + public static function flatten(array $data, $separator = '.') { + $result = array(); + $stack = array(); + $path = null; + + reset($data); + while (!empty($data)) { + $key = key($data); + $element = $data[$key]; + unset($data[$key]); + + if (is_array($element)) { + if (!empty($data)) { + $stack[] = array($data, $path); + } + $data = $element; + $path .= $key . $separator; + } else { + $result[$path . $key] = $element; + } + + if (empty($data) && !empty($stack)) { + list($data, $path) = array_pop($stack); + } + } + return $result; + } + +/** + * Expand/unflattens an string to an array + * + * For example, unflattens an array that was collapsed with `Hash::flatten()` + * into a multi-dimensional array. So, `array('0.Foo.Bar' => 'Far')` becomes + * `array(array('Foo' => array('Bar' => 'Far')))`. + * + * @param array $data Flattened array + * @param string $separator The delimiter used + * @return array + */ + public static function expand($data, $separator = '.') { + $result = array(); + foreach ($data as $flat => $value) { + $keys = explode($separator, $flat); + $keys = array_reverse($keys); + $child = array( + $keys[0] => $value + ); + array_shift($keys); + foreach ($keys as $k) { + $child = array( + $k => $child + ); + } + $result = self::merge($result, $child); + } + return $result; + } + +/** + * This function can be thought of as a hybrid between PHP's `array_merge` and `array_merge_recursive`. + * + * The difference between this method and the built-in ones, is that if an array key contains another array, then + * Hash::merge() will behave in a recursive fashion (unlike `array_merge`). But it will not act recursively for + * keys that contain scalar values (unlike `array_merge_recursive`). + * + * Note: This function will work with an unlimited amount of arguments and typecasts non-array parameters into arrays. + * + * @param array $data Array to be merged + * @param mixed $merge Array to merge with. The argument and all trailing arguments will be array cast when merged + * @return array Merged array + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/hash.html#Hash::merge + */ + public static function merge(array $data, $merge) { + $args = func_get_args(); + $return = current($args); + + while (($arg = next($args)) !== false) { + foreach ((array)$arg as $key => $val) { + if (!empty($return[$key]) && is_array($return[$key]) && is_array($val)) { + $return[$key] = self::merge($return[$key], $val); + } elseif (is_int($key)) { + $return[] = $val; + } else { + $return[$key] = $val; + } + } + } + return $return; + } + +/** + * Checks to see if all the values in the array are numeric + * + * @param array $array The array to check. + * @return boolean true if values are numeric, false otherwise + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/hash.html#Hash::numeric + */ + public static function numeric(array $data) { + if (empty($data)) { + return false; + } + $values = array_values($data); + $str = implode('', $values); + return (bool)ctype_digit($str); + } + +/** + * Counts the dimensions of an array. + * Only considers the dimension of the first element in the array. + * + * If you have an un-even or hetrogenous array, consider using Hash::maxDimensions() + * to get the dimensions of the array. + * + * @param array $array Array to count dimensions on + * @return integer The number of dimensions in $data + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/hash.html#Hash::dimensions + */ + public static function dimensions(array $data) { + if (empty($data)) { + return 0; + } + reset($data); + $depth = 1; + while ($elem = array_shift($data)) { + if (is_array($elem)) { + $depth += 1; + $data =& $elem; + } else { + break; + } + } + return $depth; + } + +/** + * Counts the dimensions of *all* array elements. Useful for finding the maximum + * number of dimensions in a mixed array. + * + * @param array $data Array to count dimensions on + * @return integer The maximum number of dimensions in $data + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/hash.html#Hash::maxDimensions + */ + public static function maxDimensions(array $data) { + $depth = array(); + if (is_array($data) && reset($data) !== false) { + foreach ($data as $value) { + $depth[] = self::dimensions((array)$value) + 1; + } + } + return max($depth); + } + +/** + * Map a callback across all elements in a set. + * Can be provided a path to only modify slices of the set. + * + * @param array $data The data to map over, and extract data out of. + * @param string $path The path to extract for mapping over. + * @param callable $function The function to call on each extracted value. + * @return array An array of the modified values. + */ + public static function map(array $data, $path, $function) { + $values = (array)self::extract($data, $path); + return array_map($function, $values); + } + +/** + * Reduce a set of extracted values using `$function`. + * + * @param array $data The data to reduce. + * @param string $path The path to extract from $data. + * @return mixed The reduced value. + */ + public static function reduce(array $data, $path, $function) { + $values = (array)self::extract($data, $path); + return array_reduce($values, $function); + } + +/** + * Apply a callback to a set of extracted values using `$function`. + * The function will get the extracted values as the first argument. + * + * @param array $data The data to reduce. + * @param string $path The path to extract from $data. + * @return mixed The results of the applied method. + */ + public static function apply(array $data, $path, $function) { + $values = (array)self::extract($data, $path); + return call_user_func($function, $values); + } + +/** + * Sorts an array by any value, determined by a Set-compatible path + * + * ### Sort directions + * + * - `asc` Sort ascending. + * - `desc` Sort descending. + * + * ## Sort types + * + * - `numeric` Sort by numeric value. + * - `regular` Sort by numeric value. + * - `string` Sort by numeric value. + * - `natural` Sort by natural order. Requires PHP 5.4 or greater. + * + * @param array $data An array of data to sort + * @param string $path A Set-compatible path to the array value + * @param string $dir See directions above. + * @param string $type See direction types above. Defaults to 'regular'. + * @return array Sorted array of data + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/hash.html#Hash::sort + */ + public static function sort(array $data, $path, $dir, $type = 'regular') { + $originalKeys = array_keys($data); + $numeric = is_numeric(implode('', $originalKeys)); + if ($numeric) { + $data = array_values($data); + } + $sortValues = self::extract($data, $path); + $sortCount = count($sortValues); + $dataCount = count($data); + + // Make sortValues match the data length, as some keys could be missing + // the sorted value path. + if ($sortCount < $dataCount) { + $sortValues = array_pad($sortValues, $dataCount, null); + } + $result = self::_squash($sortValues); + $keys = self::extract($result, '{n}.id'); + $values = self::extract($result, '{n}.value'); + + $dir = strtolower($dir); + $type = strtolower($type); + if ($type == 'natural' && version_compare(PHP_VERSION, '5.4.0', '<')) { + $type == 'regular'; + } + if ($dir === 'asc') { + $dir = SORT_ASC; + } else { + $dir = SORT_DESC; + } + if ($type === 'numeric') { + $type = SORT_NUMERIC; + } elseif ($type === 'string') { + $type = SORT_STRING; + } elseif ($type === 'natural') { + $type = SORT_NATURAL; + } else { + $type = SORT_REGULAR; + } + array_multisort($values, $dir, $type, $keys, $dir, $type); + $sorted = array(); + $keys = array_unique($keys); + + foreach ($keys as $k) { + if ($numeric) { + $sorted[] = $data[$k]; + continue; + } + if (isset($originalKeys[$k])) { + $sorted[$originalKeys[$k]] = $data[$originalKeys[$k]]; + } else { + $sorted[$k] = $data[$k]; + } + } + return $sorted; + } + +/** + * Helper method for sort() + * Sqaushes an array to a single hash so it can be sorted. + * + * @param array $data The data to squash. + * @param string $key The key for the data. + * @return array + */ + protected static function _squash($data, $key = null) { + $stack = array(); + foreach ($data as $k => $r) { + $id = $k; + if (!is_null($key)) { + $id = $key; + } + if (is_array($r) && !empty($r)) { + $stack = array_merge($stack, self::_squash($r, $id)); + } else { + $stack[] = array('id' => $id, 'value' => $r); + } + } + return $stack; + } + +/** + * Computes the difference between two complex arrays. + * This method differs from the built-in array_diff() in that it will preserve keys + * and work on multi-dimensional arrays. + * + * @param array $data First value + * @param array $compare Second value + * @return array Returns the key => value pairs that are not common in $data and $compare + * The expression for this function is ($data - $compare) + ($compare - ($data - $compare)) + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/hash.html#Hash::diff + */ + public static function diff(array $data, $compare) { + if (empty($data)) { + return (array)$compare; + } + if (empty($compare)) { + return (array)$data; + } + $intersection = array_intersect_key($data, $compare); + while (($key = key($intersection)) !== null) { + if ($data[$key] == $compare[$key]) { + unset($data[$key]); + unset($compare[$key]); + } + next($intersection); + } + return $data + $compare; + } + +/** + * Merges the difference between $data and $push onto $data. + * + * @param array $data The data to append onto. + * @param array $compare The data to compare and append onto. + * @return array The merged array. + */ + public static function mergeDiff(array $data, $compare) { + if (empty($data) && !empty($compare)) { + return $compare; + } + if (empty($compare)) { + return $data; + } + foreach ($compare as $key => $value) { + if (!array_key_exists($key, $data)) { + $data[$key] = $value; + } elseif (is_array($value)) { + $data[$key] = self::mergeDiff($data[$key], $compare[$key]); + } + } + return $data; + } + +/** + * Normalizes an array, and converts it to a standard format. + * + * @param array $data List to normalize + * @param boolean $assoc If true, $data will be converted to an associative array. + * @return array + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/hash.html#Hash::normalize + */ + public static function normalize(array $data, $assoc = true) { + $keys = array_keys($data); + $count = count($keys); + $numeric = true; + + if (!$assoc) { + for ($i = 0; $i < $count; $i++) { + if (!is_int($keys[$i])) { + $numeric = false; + break; + } + } + } + if (!$numeric || $assoc) { + $newList = array(); + for ($i = 0; $i < $count; $i++) { + if (is_int($keys[$i])) { + $newList[$data[$keys[$i]]] = null; + } else { + $newList[$keys[$i]] = $data[$keys[$i]]; + } + } + $data = $newList; + } + return $data; + } + +/** + * Takes in a flat array and returns a nested array + * + * ### Options: + * + * - `children` The key name to use in the resultset for children. + * - `idPath` The path to a key that identifies each entry. Should be + * compatible with Hash::extract(). Defaults to `{n}.$alias.id` + * - `parentPath` The path to a key that identifies the parent of each entry. + * Should be compatible with Hash::extract(). Defaults to `{n}.$alias.parent_id` + * - `root` The id of the desired top-most result. + * + * @param array $data The data to nest. + * @param array $options Options are: + * @return array of results, nested + * @see Hash::extract() + */ + public static function nest(array $data, $options = array()) { + if (!$data) { + return $data; + } + + $alias = key(current($data)); + $options += array( + 'idPath' => "{n}.$alias.id", + 'parentPath' => "{n}.$alias.parent_id", + 'children' => 'children', + 'root' => null + ); + + $return = $idMap = array(); + $ids = self::extract($data, $options['idPath']); + + $idKeys = explode('.', $options['idPath']); + array_shift($idKeys); + + $parentKeys = explode('.', $options['parentPath']); + array_shift($parentKeys); + + foreach ($data as $result) { + $result[$options['children']] = array(); + + $id = self::get($result, $idKeys); + $parentId = self::get($result, $parentKeys); + + if (isset($idMap[$id][$options['children']])) { + $idMap[$id] = array_merge($result, (array)$idMap[$id]); + } else { + $idMap[$id] = array_merge($result, array($options['children'] => array())); + } + if (!$parentId || !in_array($parentId, $ids)) { + $return[] =& $idMap[$id]; + } else { + $idMap[$parentId][$options['children']][] =& $idMap[$id]; + } + } + + if ($options['root']) { + $root = $options['root']; + } else { + $root = self::get($return[0], $parentKeys); + } + + foreach ($return as $i => $result) { + $id = self::get($result, $idKeys); + $parentId = self::get($result, $parentKeys); + if ($id !== $root && $parentId != $root) { + unset($return[$i]); + } + } + return array_values($return); + } + +} diff --git a/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/Inflector.php b/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/Inflector.php new file mode 100644 index 0000000..31829d6 --- /dev/null +++ b/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/Inflector.php @@ -0,0 +1,551 @@ +<?php +/** + * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) + * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * Redistributions of files must retain the above copyright notice. + * + * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://cakephp.org CakePHP(tm) Project + * @package Cake.Utility + * @since CakePHP(tm) v 0.2.9 + * @license MIT License (http://www.opensource.org/licenses/mit-license.php) + */ + +/** + * Pluralize and singularize English words. + * + * Inflector pluralizes and singularizes English nouns. + * Used by Cake's naming conventions throughout the framework. + * + * @package Cake.Utility + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/inflector.html + */ +class Inflector { + +/** + * Plural inflector rules + * + * @var array + */ + protected 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)$/i' => '\1s', + '/(?:([^f])fe|([lr])f)$/i' => '\1\2ves', + '/sis$/i' => 'ses', + '/([ti])um$/i' => '\1a', + '/(p)erson$/i' => '\1eople', + '/(m)an$/i' => '\1en', + '/(c)hild$/i' => '\1hildren', + '/(buffal|tomat)o$/i' => '\1\2oes', + '/(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|vir)us$/i' => '\1i', + '/us$/i' => 'uses', + '/(alias)$/i' => '\1es', + '/(ax|cris|test)is$/i' => '\1es', + '/s$/' => 's', + '/^$/' => '', + '/$/' => 's', + ), + 'uninflected' => array( + '.*[nrlm]ese', '.*deer', '.*fish', '.*measles', '.*ois', '.*pox', '.*sheep', 'people' + ), + 'irregular' => array( + 'atlas' => 'atlases', + 'beef' => 'beefs', + 'brother' => 'brothers', + 'cafe' => 'cafes', + 'child' => 'children', + 'corpus' => 'corpuses', + 'cow' => 'cows', + 'ganglion' => 'ganglions', + 'genie' => 'genies', + 'genus' => 'genera', + 'graffito' => 'graffiti', + 'hoof' => 'hoofs', + 'loaf' => 'loaves', + 'man' => 'men', + 'money' => 'monies', + 'mongoose' => 'mongooses', + 'move' => 'moves', + 'mythos' => 'mythoi', + 'niche' => 'niches', + 'numen' => 'numina', + 'occiput' => 'occiputs', + 'octopus' => 'octopuses', + 'opus' => 'opuses', + 'ox' => 'oxen', + 'penis' => 'penises', + 'person' => 'people', + 'sex' => 'sexes', + 'soliloquy' => 'soliloquies', + 'testis' => 'testes', + 'trilby' => 'trilbys', + 'turf' => 'turfs' + ) + ); + +/** + * Singular inflector rules + * + * @var array + */ + protected 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', + '/(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|viri?)i$/i' => '\1us', + '/([ftw]ax)es/i' => '\1', + '/(cris|ax|test)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', + '/([^fo])ves$/i' => '\1fe', + '/(^analy)ses$/i' => '\1sis', + '/(analy|diagno|^ba|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i' => '\1\2sis', + '/([ti])a$/i' => '\1um', + '/(p)eople$/i' => '\1\2erson', + '/(m)en$/i' => '\1an', + '/(c)hildren$/i' => '\1\2hild', + '/(n)ews$/i' => '\1\2ews', + '/eaus$/' => 'eau', + '/^(.*us)$/' => '\\1', + '/s$/i' => '' + ), + 'uninflected' => array( + '.*[nrlm]ese', '.*deer', '.*fish', '.*measles', '.*ois', '.*pox', '.*sheep', '.*ss' + ), + 'irregular' => array( + 'foes' => 'foe', + 'waves' => 'wave', + 'curves' => 'curve' + ) + ); + +/** + * Words that should not be inflected + * + * @var array + */ + protected static $_uninflected = array( + 'Amoyese', 'bison', 'Borghese', 'bream', 'breeches', 'britches', 'buffalo', 'cantus', + 'carp', 'chassis', 'clippers', 'cod', 'coitus', 'Congoese', 'contretemps', 'corps', + 'debris', 'diabetes', 'djinn', 'eland', 'elk', 'equipment', 'Faroese', 'flounder', + 'Foochowese', 'gallows', 'Genevese', 'Genoese', 'Gilbertese', 'graffiti', + 'headquarters', 'herpes', 'hijinks', 'Hottentotese', 'information', 'innings', + 'jackanapes', 'Kiplingese', 'Kongoese', 'Lucchese', 'mackerel', 'Maltese', '.*?media', + 'mews', 'moose', 'mumps', 'Nankingese', 'news', 'nexus', 'Niasese', + 'Pekingese', 'Piedmontese', 'pincers', 'Pistoiese', 'pliers', 'Portuguese', + 'proceedings', 'rabies', 'rice', 'rhinoceros', 'salmon', 'Sarawakese', 'scissors', + 'sea[- ]bass', 'series', 'Shavese', 'shears', 'siemens', 'species', 'swine', 'testes', + 'trousers', 'trout', 'tuna', 'Vermontese', 'Wenchowese', 'whiting', 'wildebeest', + 'Yengeese' + ); + +/** + * Default map of accented and special characters to ASCII characters + * + * @var array + */ + protected static $_transliteration = array( + '/ä|æ|ǽ/' => 'ae', + '/ö|œ/' => 'oe', + '/ü/' => 'ue', + '/Ä/' => 'Ae', + '/Ü/' => 'Ue', + '/Ö/' => 'Oe', + '/À|Á|Â|Ã|Ä|Å|Ǻ|Ā|Ă|Ą|Ǎ/' => 'A', + '/à|á|â|ã|å|ǻ|ā|ă|ą|ǎ|ª/' => 'a', + '/Ç|Ć|Ĉ|Ċ|Č/' => 'C', + '/ç|ć|ĉ|ċ|č/' => 'c', + '/Ð|Ď|Đ/' => 'D', + '/ð|ď|đ/' => 'd', + '/È|É|Ê|Ë|Ē|Ĕ|Ė|Ę|Ě/' => 'E', + '/è|é|ê|ë|ē|ĕ|ė|ę|ě/' => 'e', + '/Ĝ|Ğ|Ġ|Ģ/' => 'G', + '/ĝ|ğ|ġ|ģ/' => 'g', + '/Ĥ|Ħ/' => 'H', + '/ĥ|ħ/' => 'h', + '/Ì|Í|Î|Ï|Ĩ|Ī|Ĭ|Ǐ|Į|İ/' => 'I', + '/ì|í|î|ï|ĩ|ī|ĭ|ǐ|į|ı/' => 'i', + '/Ĵ/' => 'J', + '/ĵ/' => 'j', + '/Ķ/' => 'K', + '/ķ/' => 'k', + '/Ĺ|Ļ|Ľ|Ŀ|Ł/' => 'L', + '/ĺ|ļ|ľ|ŀ|ł/' => 'l', + '/Ñ|Ń|Ņ|Ň/' => 'N', + '/ñ|ń|ņ|ň|ʼn/' => 'n', + '/Ò|Ó|Ô|Õ|Ō|Ŏ|Ǒ|Ő|Ơ|Ø|Ǿ/' => 'O', + '/ò|ó|ô|õ|ō|ŏ|ǒ|ő|ơ|ø|ǿ|º/' => 'o', + '/Ŕ|Ŗ|Ř/' => 'R', + '/ŕ|ŗ|ř/' => 'r', + '/Ś|Ŝ|Ş|Š/' => 'S', + '/ś|ŝ|ş|š|ſ/' => 's', + '/Ţ|Ť|Ŧ/' => 'T', + '/ţ|ť|ŧ/' => 't', + '/Ù|Ú|Û|Ũ|Ū|Ŭ|Ů|Ű|Ų|Ư|Ǔ|Ǖ|Ǘ|Ǚ|Ǜ/' => 'U', + '/ù|ú|û|ũ|ū|ŭ|ů|ű|ų|ư|ǔ|ǖ|ǘ|ǚ|ǜ/' => 'u', + '/Ý|Ÿ|Ŷ/' => 'Y', + '/ý|ÿ|ŷ/' => 'y', + '/Ŵ/' => 'W', + '/ŵ/' => 'w', + '/Ź|Ż|Ž/' => 'Z', + '/ź|ż|ž/' => 'z', + '/Æ|Ǽ/' => 'AE', + '/ß/' => 'ss', + '/IJ/' => 'IJ', + '/ij/' => 'ij', + '/Œ/' => 'OE', + '/ƒ/' => 'f' + ); + +/** + * Method cache array. + * + * @var array + */ + protected static $_cache = array(); + +/** + * The initial state of Inflector so reset() works. + * + * @var array + */ + protected static $_initialState = array(); + +/** + * Cache inflected values, and return if already available + * + * @param string $type Inflection type + * @param string $key Original value + * @param string $value Inflected value + * @return string Inflected value, from cache + */ + protected static function _cache($type, $key, $value = false) { + $key = '_' . $key; + $type = '_' . $type; + if ($value !== false) { + self::$_cache[$type][$key] = $value; + return $value; + } + if (!isset(self::$_cache[$type][$key])) { + return false; + } + return self::$_cache[$type][$key]; + } + +/** + * Clears Inflectors inflected value caches. And resets the inflection + * rules to the initial values. + * + * @return void + */ + public static function reset() { + 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', 'singular' or 'transliteration' $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') + * )); + * Inflector::rules('transliteration', array('/å/' => 'aa')); + * }}} + * + * @param string $type The type of inflection, either 'plural', 'singular' or 'transliteration' + * @param array $rules 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($type, $rules, $reset = false) { + $var = '_' . $type; + + switch ($type) { + case 'transliteration': + if ($reset) { + self::$_transliteration = $rules; + } else { + self::$_transliteration = $rules + self::$_transliteration; + } + break; + + default: + foreach ($rules as $rule => $pattern) { + if (is_array($pattern)) { + if ($reset) { + self::${$var}[$rule] = $pattern; + } else { + if ($rule === 'uninflected') { + self::${$var}[$rule] = array_merge($pattern, self::${$var}[$rule]); + } else { + self::${$var}[$rule] = $pattern + self::${$var}[$rule]; + } + } + unset($rules[$rule], self::${$var}['cache' . ucfirst($rule)]); + if (isset(self::${$var}['merged'][$rule])) { + unset(self::${$var}['merged'][$rule]); + } + if ($type === 'plural') { + self::$_cache['pluralize'] = self::$_cache['tableize'] = array(); + } elseif ($type === 'singular') { + self::$_cache['singularize'] = array(); + } + } + } + self::${$var}['rules'] = $rules + self::${$var}['rules']; + break; + } + } + +/** + * Return $word in plural form. + * + * @param string $word Word in singular + * @return string Word in plural + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/inflector.html#Inflector::pluralize + */ + public static function pluralize($word) { + 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] . substr($word, 0, 1) . 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]; + } + } + } + +/** + * Return $word in singular form. + * + * @param string $word Word in plural + * @return string Word in singular + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/inflector.html#Inflector::singularize + */ + public static function singularize($word) { + 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'] = '(?:' . join('|', self::$_singular['merged']['uninflected']) . ')'; + self::$_singular['cacheIrregular'] = '(?:' . join('|', array_keys(self::$_singular['merged']['irregular'])) . ')'; + } + + if (preg_match('/(.*)\\b(' . self::$_singular['cacheIrregular'] . ')$/i', $word, $regs)) { + self::$_cache['singularize'][$word] = $regs[1] . substr($word, 0, 1) . 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; + } + +/** + * Returns the given lower_case_and_underscored_word as a CamelCased word. + * + * @param string $lowerCaseAndUnderscoredWord Word to camelize + * @return string Camelized word. LikeThis. + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/inflector.html#Inflector::camelize + */ + public static function camelize($lowerCaseAndUnderscoredWord) { + if (!($result = self::_cache(__FUNCTION__, $lowerCaseAndUnderscoredWord))) { + $result = str_replace(' ', '', Inflector::humanize($lowerCaseAndUnderscoredWord)); + self::_cache(__FUNCTION__, $lowerCaseAndUnderscoredWord, $result); + } + return $result; + } + +/** + * Returns the given camelCasedWord as an underscored_word. + * + * @param string $camelCasedWord Camel-cased word to be "underscorized" + * @return string Underscore-syntaxed version of the $camelCasedWord + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/inflector.html#Inflector::underscore + */ + public static function underscore($camelCasedWord) { + if (!($result = self::_cache(__FUNCTION__, $camelCasedWord))) { + $result = strtolower(preg_replace('/(?<=\\w)([A-Z])/', '_\\1', $camelCasedWord)); + self::_cache(__FUNCTION__, $camelCasedWord, $result); + } + return $result; + } + +/** + * Returns the given underscored_word_group as a Human Readable Word Group. + * (Underscores are replaced by spaces and capitalized following words.) + * + * @param string $lowerCaseAndUnderscoredWord String to be made more readable + * @return string Human-readable string + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/inflector.html#Inflector::humanize + */ + public static function humanize($lowerCaseAndUnderscoredWord) { + if (!($result = self::_cache(__FUNCTION__, $lowerCaseAndUnderscoredWord))) { + $result = ucwords(str_replace('_', ' ', $lowerCaseAndUnderscoredWord)); + self::_cache(__FUNCTION__, $lowerCaseAndUnderscoredWord, $result); + } + return $result; + } + +/** + * Returns corresponding table name for given model $className. ("people" for the model class "Person"). + * + * @param string $className Name of class to get database table name for + * @return string Name of the database table for given class + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/inflector.html#Inflector::tableize + */ + public static function tableize($className) { + if (!($result = self::_cache(__FUNCTION__, $className))) { + $result = Inflector::pluralize(Inflector::underscore($className)); + self::_cache(__FUNCTION__, $className, $result); + } + return $result; + } + +/** + * Returns Cake model class name ("Person" for the database table "people".) for given database table. + * + * @param string $tableName Name of database table to get class name for + * @return string Class name + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/inflector.html#Inflector::classify + */ + public static function classify($tableName) { + if (!($result = self::_cache(__FUNCTION__, $tableName))) { + $result = Inflector::camelize(Inflector::singularize($tableName)); + self::_cache(__FUNCTION__, $tableName, $result); + } + return $result; + } + +/** + * Returns camelBacked version of an underscored string. + * + * @param string $string + * @return string in variable form + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/inflector.html#Inflector::variable + */ + public static function variable($string) { + if (!($result = self::_cache(__FUNCTION__, $string))) { + $camelized = Inflector::camelize(Inflector::underscore($string)); + $replace = strtolower(substr($camelized, 0, 1)); + $result = preg_replace('/\\w/', $replace, $camelized, 1); + self::_cache(__FUNCTION__, $string, $result); + } + return $result; + } + +/** + * Returns a string with all spaces converted to underscores (by default), accented + * characters converted to non-accented characters, and non word characters removed. + * + * @param string $string the string you want to slug + * @param string $replacement will replace keys in map + * @return string + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/inflector.html#Inflector::slug + */ + public static function slug($string, $replacement = '_') { + $quotedReplacement = preg_quote($replacement, '/'); + + $merge = array( + '/[^\s\p{Ll}\p{Lm}\p{Lo}\p{Lt}\p{Lu}\p{Nd}]/mu' => ' ', + '/\\s+/' => $replacement, + sprintf('/^[%s]+|[%s]+$/', $quotedReplacement, $quotedReplacement) => '', + ); + + $map = self::$_transliteration + $merge; + return preg_replace(array_keys($map), array_values($map), $string); + } + +} + +// Store the initial state +Inflector::reset(); diff --git a/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/ObjectCollection.php b/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/ObjectCollection.php new file mode 100644 index 0000000..96ec3d5 --- /dev/null +++ b/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/ObjectCollection.php @@ -0,0 +1,326 @@ +<?php +/** + * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) + * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * Redistributions of files must retain the above copyright notice. + * + * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://cakephp.org CakePHP(tm) Project + * @license MIT License (http://www.opensource.org/licenses/mit-license.php) + */ + +/** + * Deals with Collections of objects. Keeping registries of those objects, + * loading and constructing new objects and triggering callbacks. Each subclass needs + * to implement its own load() functionality. + * + * All core subclasses of ObjectCollection by convention loaded objects are stored + * in `$this->_loaded`. Enabled objects are stored in `$this->_enabled`. In addition + * the all support an `enabled` option that controls the enabled/disabled state of the object + * when loaded. + * + * @package Cake.Utility + * @since CakePHP(tm) v 2.0 + */ +abstract class ObjectCollection { + +/** + * List of the currently-enabled objects + * + * @var array + */ + protected $_enabled = array(); + +/** + * A hash of loaded objects, indexed by name + * + * @var array + */ + protected $_loaded = array(); + +/** + * Default object priority. A non zero integer. + * + * @var int + */ + public $defaultPriority = 10; + +/** + * Loads a new object onto the collection. Can throw a variety of exceptions + * + * Implementations of this class support a `$options['enabled']` flag which enables/disables + * a loaded object. + * + * @param string $name Name of object to load. + * @param array $options Array of configuration options for the object to be constructed. + * @return object the constructed object + */ + abstract public function load($name, $options = array()); + +/** + * Trigger a callback method on every object in the collection. + * Used to trigger methods on objects in the collection. Will fire the methods in the + * order they were attached. + * + * ### Options + * + * - `breakOn` Set to the value or values you want the callback propagation to stop on. + * Can either be a scalar value, or an array of values to break on. Defaults to `false`. + * + * - `break` Set to true to enabled breaking. When a trigger is broken, the last returned value + * will be returned. If used in combination with `collectReturn` the collected results will be returned. + * Defaults to `false`. + * + * - `collectReturn` Set to true to collect the return of each object into an array. + * This array of return values will be returned from the trigger() call. Defaults to `false`. + * + * - `modParams` Allows each object the callback gets called on to modify the parameters to the next object. + * Setting modParams to an integer value will allow you to modify the parameter with that index. + * Any non-null value will modify the parameter index indicated. + * Defaults to false. + * + * + * @param string $callback|CakeEvent Method to fire on all the objects. Its assumed all the objects implement + * the method you are calling. If an instance of CakeEvent is provided, then then Event name will parsed to + * get the callback name. This is done by getting the last word after any dot in the event name + * (eg. `Model.afterSave` event will trigger the `afterSave` callback) + * @param array $params Array of parameters for the triggered callback. + * @param array $options Array of options. + * @return mixed Either the last result or all results if collectReturn is on. + * @throws CakeException when modParams is used with an index that does not exist. + */ + public function trigger($callback, $params = array(), $options = array()) { + if (empty($this->_enabled)) { + return true; + } + if ($callback instanceof CakeEvent) { + $event = $callback; + if (is_array($event->data)) { + $params =& $event->data; + } + if (empty($event->omitSubject)) { + $subject = $event->subject(); + } + //TODO: Temporary BC check, while we move all the triggers system into the CakeEventManager + foreach (array('break', 'breakOn', 'collectReturn', 'modParams') as $opt) { + if (isset($event->{$opt})) { + $options[$opt] = $event->{$opt}; + } + } + $parts = explode('.', $event->name()); + $callback = array_pop($parts); + } + $options = array_merge( + array( + 'break' => false, + 'breakOn' => false, + 'collectReturn' => false, + 'modParams' => false + ), + $options + ); + $collected = array(); + $list = array_keys($this->_enabled); + if ($options['modParams'] !== false && !isset($params[$options['modParams']])) { + throw new CakeException(__d('cake_dev', 'Cannot use modParams with indexes that do not exist.')); + } + foreach ($list as $name) { + $result = call_user_func_array(array($this->_loaded[$name], $callback), compact('subject') + $params); + if ($options['collectReturn'] === true) { + $collected[] = $result; + } + if ( + $options['break'] && ($result === $options['breakOn'] || + (is_array($options['breakOn']) && in_array($result, $options['breakOn'], true))) + ) { + return $result; + } elseif ($options['modParams'] !== false && !in_array($result, array(true, false, null), true)) { + $params[$options['modParams']] = $result; + } + } + if ($options['modParams'] !== false) { + return $params[$options['modParams']]; + } + return $options['collectReturn'] ? $collected : $result; + } + +/** + * Provide public read access to the loaded objects + * + * @param string $name Name of property to read + * @return mixed + */ + public function __get($name) { + if (isset($this->_loaded[$name])) { + return $this->_loaded[$name]; + } + return null; + } + +/** + * Provide isset access to _loaded + * + * @param string $name Name of object being checked. + * @return boolean + */ + public function __isset($name) { + return isset($this->_loaded[$name]); + } + +/** + * Enables callbacks on an object or array of objects + * + * @param string|array $name CamelCased name of the object(s) to enable (string or array) + * @param boolean Prioritize enabled list after enabling object(s) + * @return void + */ + public function enable($name, $prioritize = true) { + $enabled = false; + foreach ((array)$name as $object) { + if (isset($this->_loaded[$object]) && !isset($this->_enabled[$object])) { + $priority = isset($this->_loaded[$object]->settings['priority']) ? $this->_loaded[$object]->settings['priority'] : $this->defaultPriority; + $this->_enabled[$object] = array($priority); + $enabled = true; + } + } + if ($prioritize && $enabled) { + $this->prioritize(); + } + } + +/** + * Prioritize list of enabled object + * + * @return array Prioritized list of object + */ + public function prioritize() { + $i = 1; + foreach ($this->_enabled as $name => $priority) { + $priority[1] = $i++; + $this->_enabled[$name] = $priority; + } + asort($this->_enabled); + return $this->_enabled; + } + +/** + * Set priority for an object or array of objects + * + * @param string|array $name CamelCased name of the object(s) to enable (string or array) + * If string the second param $priority is used else it should be an associative array + * with keys as object names and values as priorities to set. + * @param integer|null Integer priority to set or null for default + * @return void + */ + public function setPriority($name, $priority = null) { + if (is_string($name)) { + $name = array($name => $priority); + } + foreach ($name as $obj => $prio) { + if (isset($this->_loaded[$obj])) { + if (is_null($prio)) { + $prio = $this->defaultPriority; + } + $this->_loaded[$obj]->settings['priority'] = $prio; + if (isset($this->_enabled[$obj])) { + $this->_enabled[$obj] = array($prio); + } + } + } + $this->prioritize(); + } + +/** + * Disables callbacks on a object or array of objects. Public object methods are still + * callable as normal. + * + * @param string|array $name CamelCased name of the objects(s) to disable (string or array) + * @return void + */ + public function disable($name) { + foreach ((array)$name as $object) { + unset($this->_enabled[$object]); + } + } + +/** + * Gets the list of currently-enabled objects, or, the current status of a single objects + * + * @param string $name Optional. The name of the object to check the status of. If omitted, + * returns an array of currently-enabled object + * @return mixed If $name is specified, returns the boolean status of the corresponding object. + * Otherwise, returns an array of all enabled objects. + */ + public function enabled($name = null) { + if (!empty($name)) { + return isset($this->_enabled[$name]); + } + return array_keys($this->_enabled); + } + +/** + * Gets the list of attached objects, or, whether the given object is attached + * + * @param string $name Optional. The name of the behavior to check the status of. If omitted, + * returns an array of currently-attached behaviors + * @return mixed If $name is specified, returns the boolean status of the corresponding behavior. + * Otherwise, returns an array of all attached behaviors. + */ + public function attached($name = null) { + if (!empty($name)) { + return isset($this->_loaded[$name]); + } + return array_keys($this->_loaded); + } + +/** + * Name of the object to remove from the collection + * + * @param string $name Name of the object to delete. + * @return void + */ + public function unload($name) { + list($plugin, $name) = pluginSplit($name); + unset($this->_loaded[$name]); + unset($this->_enabled[$name]); + } + +/** + * Adds or overwrites an instantiated object to the collection + * + * @param string $name Name of the object + * @param Object $object The object to use + * @return array Loaded objects + */ + public function set($name = null, $object = null) { + if (!empty($name) && !empty($object)) { + list($plugin, $name) = pluginSplit($name); + $this->_loaded[$name] = $object; + } + return $this->_loaded; + } + +/** + * Normalizes an object array, creates an array that makes lazy loading + * easier + * + * @param array $objects Array of child objects to normalize. + * @return array Array of normalized objects. + */ + public static function normalizeObjectArray($objects) { + $normal = array(); + foreach ($objects as $i => $objectName) { + $options = array(); + if (!is_int($i)) { + $options = (array)$objectName; + $objectName = $i; + } + list($plugin, $name) = pluginSplit($objectName); + $normal[$name] = array('class' => $objectName, 'settings' => $options); + } + return $normal; + } + +} diff --git a/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/Sanitize.php b/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/Sanitize.php new file mode 100644 index 0000000..dfb55f3 --- /dev/null +++ b/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/Sanitize.php @@ -0,0 +1,264 @@ +<?php +/** + * Washes strings from unwanted noise. + * + * Helpful methods to make unsafe strings usable. + * + * PHP 5 + * + * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) + * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * Redistributions of files must retain the above copyright notice. + * + * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://cakephp.org CakePHP(tm) Project + * @package Cake.Utility + * @since CakePHP(tm) v 0.10.0.1076 + * @license MIT License (http://www.opensource.org/licenses/mit-license.php) + */ + +App::import('Model', 'ConnectionManager'); + +/** + * Data Sanitization. + * + * Removal of alphanumeric characters, SQL-safe slash-added strings, HTML-friendly strings, + * and all of the above on arrays. + * + * @package Cake.Utility + */ +class Sanitize { + +/** + * Removes any non-alphanumeric characters. + * + * @param string $string String to sanitize + * @param array $allowed An array of additional characters that are not to be removed. + * @return string Sanitized string + */ + public static function paranoid($string, $allowed = array()) { + $allow = null; + if (!empty($allowed)) { + foreach ($allowed as $value) { + $allow .= "\\$value"; + } + } + + if (is_array($string)) { + $cleaned = array(); + foreach ($string as $key => $clean) { + $cleaned[$key] = preg_replace("/[^{$allow}a-zA-Z0-9]/", '', $clean); + } + } else { + $cleaned = preg_replace("/[^{$allow}a-zA-Z0-9]/", '', $string); + } + return $cleaned; + } + +/** + * Makes a string SQL-safe. + * + * @param string $string String to sanitize + * @param string $connection Database connection being used + * @return string SQL safe string + */ + public static function escape($string, $connection = 'default') { + $db = ConnectionManager::getDataSource($connection); + if (is_numeric($string) || $string === null || is_bool($string)) { + return $string; + } + $string = $db->value($string, 'string'); + if ($string[0] === 'N') { + $string = substr($string, 2); + } else { + $string = substr($string, 1); + } + + $string = substr($string, 0, -1); + return $string; + } + +/** + * Returns given string safe for display as HTML. Renders entities. + * + * strip_tags() does not validating HTML syntax or structure, so it might strip whole passages + * with broken HTML. + * + * ### Options: + * + * - remove (boolean) if true strips all HTML tags before encoding + * - charset (string) the charset used to encode the string + * - quotes (int) see http://php.net/manual/en/function.htmlentities.php + * - double (boolean) doube encode html entities + * + * @param string $string String from where to strip tags + * @param array $options Array of options to use. + * @return string Sanitized string + */ + public static function html($string, $options = array()) { + static $defaultCharset = false; + if ($defaultCharset === false) { + $defaultCharset = Configure::read('App.encoding'); + if ($defaultCharset === null) { + $defaultCharset = 'UTF-8'; + } + } + $default = array( + 'remove' => false, + 'charset' => $defaultCharset, + 'quotes' => ENT_QUOTES, + 'double' => true + ); + + $options = array_merge($default, $options); + + if ($options['remove']) { + $string = strip_tags($string); + } + + return htmlentities($string, $options['quotes'], $options['charset'], $options['double']); + } + +/** + * Strips extra whitespace from output + * + * @param string $str String to sanitize + * @return string whitespace sanitized string + */ + public static function stripWhitespace($str) { + $r = preg_replace('/[\n\r\t]+/', '', $str); + return preg_replace('/\s{2,}/u', ' ', $r); + } + +/** + * Strips image tags from output + * + * @param string $str String to sanitize + * @return string Sting with images stripped. + */ + public static function stripImages($str) { + $str = preg_replace('/(<a[^>]*>)(<img[^>]+alt=")([^"]*)("[^>]*>)(<\/a>)/i', '$1$3$5<br />', $str); + $str = preg_replace('/(<img[^>]+alt=")([^"]*)("[^>]*>)/i', '$2<br />', $str); + $str = preg_replace('/<img[^>]*>/i', '', $str); + return $str; + } + +/** + * Strips scripts and stylesheets from output + * + * @param string $str String to sanitize + * @return string String with <script>, <style>, <link>, <img> elements removed. + */ + public static function stripScripts($str) { + return preg_replace('/(<link[^>]+rel="[^"]*stylesheet"[^>]*>|<img[^>]*>|style="[^"]*")|<script[^>]*>.*?<\/script>|<style[^>]*>.*?<\/style>|<!--.*?-->/is', '', $str); + } + +/** + * Strips extra whitespace, images, scripts and stylesheets from output + * + * @param string $str String to sanitize + * @return string sanitized string + */ + public static function stripAll($str) { + $str = Sanitize::stripWhitespace($str); + $str = Sanitize::stripImages($str); + $str = Sanitize::stripScripts($str); + return $str; + } + +/** + * Strips the specified tags from output. First parameter is string from + * where to remove tags. All subsequent parameters are tags. + * + * Ex.`$clean = Sanitize::stripTags($dirty, 'b', 'p', 'div');` + * + * Will remove all `<b>`, `<p>`, and `<div>` tags from the $dirty string. + * + * @param string $str,... String to sanitize + * @return string sanitized String + */ + public static function stripTags($str) { + $params = func_get_args(); + + for ($i = 1, $count = count($params); $i < $count; $i++) { + $str = preg_replace('/<' . $params[$i] . '\b[^>]*>/i', '', $str); + $str = preg_replace('/<\/' . $params[$i] . '[^>]*>/i', '', $str); + } + return $str; + } + +/** + * Sanitizes given array or value for safe input. Use the options to specify + * the connection to use, and what filters should be applied (with a boolean + * value). Valid filters: + * + * - odd_spaces - removes any non space whitespace characters + * - encode - Encode any html entities. Encode must be true for the `remove_html` to work. + * - dollar - Escape `$` with `\$` + * - carriage - Remove `\r` + * - unicode - + * - escape - Should the string be SQL escaped. + * - backslash - + * - remove_html - Strip HTML with strip_tags. `encode` must be true for this option to work. + * + * @param string|array $data Data to sanitize + * @param string|array $options If string, DB connection being used, otherwise set of options + * @return mixed Sanitized data + */ + public static function clean($data, $options = array()) { + if (empty($data)) { + return $data; + } + + if (is_string($options)) { + $options = array('connection' => $options); + } elseif (!is_array($options)) { + $options = array(); + } + + $options = array_merge(array( + 'connection' => 'default', + 'odd_spaces' => true, + 'remove_html' => false, + 'encode' => true, + 'dollar' => true, + 'carriage' => true, + 'unicode' => true, + 'escape' => true, + 'backslash' => true + ), $options); + + if (is_array($data)) { + foreach ($data as $key => $val) { + $data[$key] = Sanitize::clean($val, $options); + } + return $data; + } else { + if ($options['odd_spaces']) { + $data = str_replace(chr(0xCA), '', $data); + } + if ($options['encode']) { + $data = Sanitize::html($data, array('remove' => $options['remove_html'])); + } + if ($options['dollar']) { + $data = str_replace("\\\$", "$", $data); + } + if ($options['carriage']) { + $data = str_replace("\r", "", $data); + } + if ($options['unicode']) { + $data = preg_replace("/&#([0-9]+);/s", "&#\\1;", $data); + } + if ($options['escape']) { + $data = Sanitize::escape($data, $options['connection']); + } + if ($options['backslash']) { + $data = preg_replace("/\\\(?!&#|\?#)/", "\\", $data); + } + return $data; + } + } + +} diff --git a/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/Security.php b/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/Security.php new file mode 100644 index 0000000..6438338 --- /dev/null +++ b/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/Security.php @@ -0,0 +1,192 @@ +<?php +/** + * Core Security + * + * PHP 5 + * + * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) + * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * Redistributions of files must retain the above copyright notice. + * + * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://cakephp.org CakePHP(tm) Project + * @package Cake.Utility + * @since CakePHP(tm) v .0.10.0.1233 + * @license MIT License (http://www.opensource.org/licenses/mit-license.php) + */ + +App::uses('String', 'Utility'); + +/** + * Security Library contains utility methods related to security + * + * @package Cake.Utility + */ +class Security { + +/** + * Default hash method + * + * @var string + */ + public static $hashType = null; + +/** + * Get allowed minutes of inactivity based on security level. + * + * @return integer Allowed inactivity in minutes + */ + public static function inactiveMins() { + switch (Configure::read('Security.level')) { + case 'high': + return 10; + break; + case 'medium': + return 100; + break; + case 'low': + default: + return 300; + break; + } + } + +/** + * Generate authorization hash. + * + * @return string Hash + */ + public static function generateAuthKey() { + return Security::hash(String::uuid()); + } + +/** + * Validate authorization hash. + * + * @param string $authKey Authorization hash + * @return boolean Success + * @todo Complete implementation + */ + public static function validateAuthKey($authKey) { + return true; + } + +/** + * Create a hash from string using given method. + * Fallback on next available method. + * + * @param string $string String to hash + * @param string $type Method to use (sha1/sha256/md5) + * @param boolean $salt If true, automatically appends the application's salt + * value to $string (Security.salt) + * @return string Hash + */ + public static function hash($string, $type = null, $salt = false) { + if ($salt) { + if (is_string($salt)) { + $string = $salt . $string; + } else { + $string = Configure::read('Security.salt') . $string; + } + } + + if (empty($type)) { + $type = self::$hashType; + } + $type = strtolower($type); + + if ($type == 'sha1' || $type == null) { + if (function_exists('sha1')) { + $return = sha1($string); + return $return; + } + $type = 'sha256'; + } + + if ($type == 'sha256' && function_exists('mhash')) { + return bin2hex(mhash(MHASH_SHA256, $string)); + } + + if (function_exists('hash')) { + return hash($type, $string); + } + return md5($string); + } + +/** + * Sets the default hash method for the Security object. This affects all objects using + * Security::hash(). + * + * @param string $hash Method to use (sha1/sha256/md5) + * @return void + * @see Security::hash() + */ + public static function setHash($hash) { + self::$hashType = $hash; + } + +/** + * Encrypts/Decrypts a text using the given key. + * + * @param string $text Encrypted string to decrypt, normal string to encrypt + * @param string $key Key to use + * @return string Encrypted/Decrypted string + */ + public static function cipher($text, $key) { + if (empty($key)) { + trigger_error(__d('cake_dev', 'You cannot use an empty key for Security::cipher()'), E_USER_WARNING); + return ''; + } + + srand(Configure::read('Security.cipherSeed')); + $out = ''; + $keyLength = strlen($key); + for ($i = 0, $textLength = strlen($text); $i < $textLength; $i++) { + $j = ord(substr($key, $i % $keyLength, 1)); + while ($j--) { + rand(0, 255); + } + $mask = rand(0, 255); + $out .= chr(ord(substr($text, $i, 1)) ^ $mask); + } + srand(); + return $out; + } + +/** + * Encrypts/Decrypts a text using the given key using rijndael method. + * + * @param string $text Encrypted string to decrypt, normal string to encrypt + * @param string $key Key to use + * @param string $operation Operation to perform, encrypt or decrypt + * @return string Encrypted/Descrypted string + */ + public static function rijndael($text, $key, $operation) { + if (empty($key)) { + trigger_error(__d('cake_dev', 'You cannot use an empty key for Security::rijndael()'), E_USER_WARNING); + return ''; + } + if (empty($operation) || !in_array($operation, array('encrypt', 'decrypt'))) { + trigger_error(__d('cake_dev', 'You must specify the operation for Security::rijndael(), either encrypt or decrypt'), E_USER_WARNING); + return ''; + } + if (strlen($key) < 32) { + trigger_error(__d('cake_dev', 'You must use a key larger than 32 bytes for Security::rijndael()'), E_USER_WARNING); + return ''; + } + $algorithm = 'rijndael-256'; + $mode = 'cbc'; + $cryptKey = substr($key, 0, 32); + $iv = substr($key, strlen($key) - 32, 32); + $out = ''; + if ($operation === 'encrypt') { + $out .= mcrypt_encrypt($algorithm, $cryptKey, $text, $mode, $iv); + } elseif ($operation === 'decrypt') { + $out .= rtrim(mcrypt_decrypt($algorithm, $cryptKey, $text, $mode, $iv), "\0"); + } + return $out; + } + +} diff --git a/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/Set.php b/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/Set.php new file mode 100644 index 0000000..3bfa008 --- /dev/null +++ b/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/Set.php @@ -0,0 +1,1108 @@ +<?php +/** + * Library of array functions for Cake. + * + * PHP 5 + * + * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) + * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * Redistributions of files must retain the above copyright notice. + * + * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://cakephp.org CakePHP(tm) Project + * @package Cake.Utility + * @since CakePHP(tm) v 1.2.0 + * @license MIT License (http://www.opensource.org/licenses/mit-license.php) + */ + +App::uses('String', 'Utility'); +App::uses('Hash', 'Utility'); + +/** + * Class used for manipulation of arrays. + * + * @package Cake.Utility + */ +class Set { + +/** + * This function can be thought of as a hybrid between PHP's array_merge and array_merge_recursive. The difference + * to the two is that if an array key contains another array then the function behaves recursive (unlike array_merge) + * but does not do if for keys containing strings (unlike array_merge_recursive). + * + * Since this method emulates `array_merge`, it will re-order numeric keys. When combined with out of + * order numeric keys containing arrays, results can be lossy. + * + * Note: This function will work with an unlimited amount of arguments and typecasts non-array + * parameters into arrays. + * + * @param array $data Array to be merged + * @param array $merge Array to merge with + * @return array Merged array + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/set.html#Set::merge + */ + public static function merge($data, $merge = null) { + $args = func_get_args(); + if (empty($args[1])) { + return (array)$args[0]; + } + if (!is_array($args[0])) { + $args[0] = (array)$args[0]; + } + return call_user_func_array('Hash::merge', $args); + } + +/** + * Filters empty elements out of a route array, excluding '0'. + * + * @param array $var Either an array to filter, or value when in callback + * @return mixed Either filtered array, or true/false when in callback + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/set.html#Set::filter + */ + public static function filter(array $var) { + return Hash::filter($var); + } + +/** + * Pushes the differences in $array2 onto the end of $array + * + * @param array $array Original array + * @param array $array2 Differences to push + * @return array Combined array + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/set.html#Set::pushDiff + */ + public static function pushDiff($array, $array2) { + if (empty($array) && !empty($array2)) { + return $array2; + } + if (!empty($array) && !empty($array2)) { + foreach ($array2 as $key => $value) { + if (!array_key_exists($key, $array)) { + $array[$key] = $value; + } else { + if (is_array($value)) { + $array[$key] = Set::pushDiff($array[$key], $array2[$key]); + } + } + } + } + return $array; + } + +/** + * Maps the contents of the Set object to an object hierarchy. + * Maintains numeric keys as arrays of objects + * + * @param string $class A class name of the type of object to map to + * @param string $tmp A temporary class name used as $class if $class is an array + * @return object Hierarchical object + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/set.html#Set::map + */ + public static function map($class = 'stdClass', $tmp = 'stdClass') { + if (is_array($class)) { + $val = $class; + $class = $tmp; + } + + if (empty($val)) { + return null; + } + return Set::_map($val, $class); + } + +/** + * Maps the given value as an object. If $value is an object, + * it returns $value. Otherwise it maps $value as an object of + * type $class, and if primary assign _name_ $key on first array. + * If $value is not empty, it will be used to set properties of + * returned object (recursively). If $key is numeric will maintain array + * structure + * + * @param array $array Array to map + * @param string $class Class name + * @param boolean $primary whether to assign first array key as the _name_ + * @return mixed Mapped object + */ + protected static function _map(&$array, $class, $primary = false) { + if ($class === true) { + $out = new stdClass; + } else { + $out = new $class; + } + if (is_array($array)) { + $keys = array_keys($array); + foreach ($array as $key => $value) { + if ($keys[0] === $key && $class !== true) { + $primary = true; + } + if (is_numeric($key)) { + if (is_object($out)) { + $out = get_object_vars($out); + } + $out[$key] = Set::_map($value, $class); + if (is_object($out[$key])) { + if ($primary !== true && is_array($value) && Set::countDim($value, true) === 2) { + if (!isset($out[$key]->_name_)) { + $out[$key]->_name_ = $primary; + } + } + } + } elseif (is_array($value)) { + if ($primary === true) { + // @codingStandardsIgnoreStart Legacy junk + if (!isset($out->_name_)) { + $out->_name_ = $key; + } + // @codingStandardsIgnoreEnd + $primary = false; + foreach ($value as $key2 => $value2) { + $out->{$key2} = Set::_map($value2, true); + } + } else { + if (!is_numeric($key)) { + $out->{$key} = Set::_map($value, true, $key); + if (is_object($out->{$key}) && !is_numeric($key)) { + if (!isset($out->{$key}->_name_)) { + $out->{$key}->_name_ = $key; + } + } + } else { + $out->{$key} = Set::_map($value, true); + } + } + } else { + $out->{$key} = $value; + } + } + } else { + $out = $array; + } + return $out; + } + +/** + * Checks to see if all the values in the array are numeric + * + * @param array $array The array to check. If null, the value of the current Set object + * @return boolean true if values are numeric, false otherwise + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/set.html#Set::numeric + */ + public static function numeric($array = null) { + return Hash::numeric($array); + } + +/** + * Return a value from an array list if the key exists. + * + * If a comma separated $list is passed arrays are numeric with the key of the first being 0 + * $list = 'no, yes' would translate to $list = array(0 => 'no', 1 => 'yes'); + * + * If an array is used, keys can be strings example: array('no' => 0, 'yes' => 1); + * + * $list defaults to 0 = no 1 = yes if param is not passed + * + * @param array $select Key in $list to return + * @param array|string $list can be an array or a comma-separated list. + * @return string the value of the array key or null if no match + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/set.html#Set::enum + */ + public static function enum($select, $list = null) { + if (empty($list)) { + $list = array('no', 'yes'); + } + + $return = null; + $list = Set::normalize($list, false); + + if (array_key_exists($select, $list)) { + $return = $list[$select]; + } + return $return; + } + +/** + * Returns a series of values extracted from an array, formatted in a format string. + * + * @param array $data Source array from which to extract the data + * @param string $format Format string into which values will be inserted, see sprintf() + * @param array $keys An array containing one or more Set::extract()-style key paths + * @return array An array of strings extracted from $keys and formatted with $format + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/set.html#Set::format + */ + public static function format($data, $format, $keys) { + $extracted = array(); + $count = count($keys); + + if (!$count) { + return; + } + + for ($i = 0; $i < $count; $i++) { + $extracted[] = Set::extract($data, $keys[$i]); + } + $out = array(); + $data = $extracted; + $count = count($data[0]); + + if (preg_match_all('/\{([0-9]+)\}/msi', $format, $keys2) && isset($keys2[1])) { + $keys = $keys2[1]; + $format = preg_split('/\{([0-9]+)\}/msi', $format); + $count2 = count($format); + + for ($j = 0; $j < $count; $j++) { + $formatted = ''; + for ($i = 0; $i <= $count2; $i++) { + if (isset($format[$i])) { + $formatted .= $format[$i]; + } + if (isset($keys[$i]) && isset($data[$keys[$i]][$j])) { + $formatted .= $data[$keys[$i]][$j]; + } + } + $out[] = $formatted; + } + } else { + $count2 = count($data); + for ($j = 0; $j < $count; $j++) { + $args = array(); + for ($i = 0; $i < $count2; $i++) { + if (array_key_exists($j, $data[$i])) { + $args[] = $data[$i][$j]; + } + } + $out[] = vsprintf($format, $args); + } + } + return $out; + } + +/** + * Implements partial support for XPath 2.0. If $path does not contain a '/' the call + * is delegated to Set::classicExtract(). Also the $path and $data arguments are + * reversible. + * + * #### Currently implemented selectors: + * + * - /User/id (similar to the classic {n}.User.id) + * - /User[2]/name (selects the name of the second User) + * - /User[id>2] (selects all Users with an id > 2) + * - /User[id>2][<5] (selects all Users with an id > 2 but < 5) + * - /Post/Comment[author_name=john]/../name (Selects the name of all Posts that have at least one Comment written by john) + * - /Posts[name] (Selects all Posts that have a 'name' key) + * - /Comment/.[1] (Selects the contents of the first comment) + * - /Comment/.[:last] (Selects the last comment) + * - /Comment/.[:first] (Selects the first comment) + * - /Comment[text=/cakephp/i] (Selects the all comments that have a text matching the regex /cakephp/i) + * - /Comment/@* (Selects the all key names of all comments) + * + * #### Other limitations: + * + * - Only absolute paths starting with a single '/' are supported right now + * + * **Warning**: Even so it has plenty of unit tests the XPath support has not gone through a lot of + * real-world testing. Please report Bugs as you find them. Suggestions for additional features to + * implement are also very welcome! + * + * @param string $path An absolute XPath 2.0 path + * @param array $data An array of data to extract from + * @param array $options Currently only supports 'flatten' which can be disabled for higher XPath-ness + * @return array An array of matched items + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/set.html#Set::extract + */ + public static function extract($path, $data = null, $options = array()) { + if (is_string($data)) { + $tmp = $data; + $data = $path; + $path = $tmp; + } + if (strpos($path, '/') === false) { + return Set::classicExtract($data, $path); + } + if (empty($data)) { + return array(); + } + if ($path === '/') { + return $data; + } + $contexts = $data; + $options = array_merge(array('flatten' => true), $options); + if (!isset($contexts[0])) { + $current = current($data); + if ((is_array($current) && count($data) < 1) || !is_array($current) || !Set::numeric(array_keys($data))) { + $contexts = array($data); + } + } + $tokens = array_slice(preg_split('/(?<!=|\\\\)\/(?![a-z-\s]*\])/', $path), 1); + + do { + $token = array_shift($tokens); + $conditions = false; + if (preg_match_all('/\[([^=]+=\/[^\/]+\/|[^\]]+)\]/', $token, $m)) { + $conditions = $m[1]; + $token = substr($token, 0, strpos($token, '[')); + } + $matches = array(); + foreach ($contexts as $key => $context) { + if (!isset($context['trace'])) { + $context = array('trace' => array(null), 'item' => $context, 'key' => $key); + } + if ($token === '..') { + if (count($context['trace']) == 1) { + $context['trace'][] = $context['key']; + } + $parent = implode('/', $context['trace']) . '/.'; + $context['item'] = Set::extract($parent, $data); + $context['key'] = array_pop($context['trace']); + if (isset($context['trace'][1]) && $context['trace'][1] > 0) { + $context['item'] = $context['item'][0]; + } elseif (!empty($context['item'][$key])) { + $context['item'] = $context['item'][$key]; + } else { + $context['item'] = array_shift($context['item']); + } + $matches[] = $context; + continue; + } + if ($token === '@*' && is_array($context['item'])) { + $matches[] = array( + 'trace' => array_merge($context['trace'], (array)$key), + 'key' => $key, + 'item' => array_keys($context['item']), + ); + } elseif (is_array($context['item']) + && array_key_exists($token, $context['item']) + && !(strval($key) === strval($token) && count($tokens) == 1 && $tokens[0] === '.')) { + $items = $context['item'][$token]; + if (!is_array($items)) { + $items = array($items); + } elseif (!isset($items[0])) { + $current = current($items); + $currentKey = key($items); + if (!is_array($current) || (is_array($current) && count($items) <= 1 && !is_numeric($currentKey))) { + $items = array($items); + } + } + + foreach ($items as $key => $item) { + $ctext = array($context['key']); + if (!is_numeric($key)) { + $ctext[] = $token; + $tok = array_shift($tokens); + if (isset($items[$tok])) { + $ctext[] = $tok; + $item = $items[$tok]; + $matches[] = array( + 'trace' => array_merge($context['trace'], $ctext), + 'key' => $tok, + 'item' => $item, + ); + break; + } elseif ($tok !== null) { + array_unshift($tokens, $tok); + } + } else { + $key = $token; + } + + $matches[] = array( + 'trace' => array_merge($context['trace'], $ctext), + 'key' => $key, + 'item' => $item, + ); + } + } elseif ($key === $token || (ctype_digit($token) && $key == $token) || $token === '.') { + $context['trace'][] = $key; + $matches[] = array( + 'trace' => $context['trace'], + 'key' => $key, + 'item' => $context['item'], + ); + } + } + if ($conditions) { + foreach ($conditions as $condition) { + $filtered = array(); + $length = count($matches); + foreach ($matches as $i => $match) { + if (Set::matches(array($condition), $match['item'], $i + 1, $length)) { + $filtered[$i] = $match; + } + } + $matches = $filtered; + } + } + $contexts = $matches; + + if (empty($tokens)) { + break; + } + } while (1); + + $r = array(); + + foreach ($matches as $match) { + if ((!$options['flatten'] || is_array($match['item'])) && !is_int($match['key'])) { + $r[] = array($match['key'] => $match['item']); + } else { + $r[] = $match['item']; + } + } + return $r; + } + +/** + * This function can be used to see if a single item or a given xpath match certain conditions. + * + * @param string|array $conditions An array of condition strings or an XPath expression + * @param array $data An array of data to execute the match on + * @param integer $i Optional: The 'nth'-number of the item being matched. + * @param integer $length + * @return boolean + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/set.html#Set::matches + */ + public static function matches($conditions, $data = array(), $i = null, $length = null) { + if (empty($conditions)) { + return true; + } + if (is_string($conditions)) { + return !!Set::extract($conditions, $data); + } + foreach ($conditions as $condition) { + if ($condition === ':last') { + if ($i != $length) { + return false; + } + continue; + } elseif ($condition === ':first') { + if ($i != 1) { + return false; + } + continue; + } + if (!preg_match('/(.+?)([><!]?[=]|[><])(.*)/', $condition, $match)) { + if (ctype_digit($condition)) { + if ($i != $condition) { + return false; + } + } elseif (preg_match_all('/(?:^[0-9]+|(?<=,)[0-9]+)/', $condition, $matches)) { + return in_array($i, $matches[0]); + } elseif (!array_key_exists($condition, $data)) { + return false; + } + continue; + } + list(, $key, $op, $expected) = $match; + if (!(isset($data[$key]) || array_key_exists($key, $data))) { + return false; + } + + $val = $data[$key]; + + if ($op === '=' && $expected && $expected{0} === '/') { + return preg_match($expected, $val); + } + if ($op === '=' && $val != $expected) { + return false; + } + if ($op === '!=' && $val == $expected) { + return false; + } + if ($op === '>' && $val <= $expected) { + return false; + } + if ($op === '<' && $val >= $expected) { + return false; + } + if ($op === '<=' && $val > $expected) { + return false; + } + if ($op === '>=' && $val < $expected) { + return false; + } + } + return true; + } + +/** + * Gets a value from an array or object that is contained in a given path using an array path syntax, i.e.: + * "{n}.Person.{[a-z]+}" - Where "{n}" represents a numeric key, "Person" represents a string literal, + * and "{[a-z]+}" (i.e. any string literal enclosed in brackets besides {n} and {s}) is interpreted as + * a regular expression. + * + * @param array $data Array from where to extract + * @param string|array $path As an array, or as a dot-separated string. + * @return array Extracted data + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/set.html#Set::classicExtract + */ + public static function classicExtract($data, $path = null) { + if (empty($path)) { + return $data; + } + if (is_object($data)) { + if (!($data instanceof ArrayAccess || $data instanceof Traversable)) { + $data = get_object_vars($data); + } + } + if (empty($data)) { + return null; + } + if (is_string($path) && strpos($path, '{') !== false) { + $path = String::tokenize($path, '.', '{', '}'); + } elseif (is_string($path)) { + $path = explode('.', $path); + } + $tmp = array(); + + if (empty($path)) { + return null; + } + + foreach ($path as $i => $key) { + if (is_numeric($key) && intval($key) > 0 || $key === '0') { + if (isset($data[$key])) { + $data = $data[$key]; + } else { + return null; + } + } elseif ($key === '{n}') { + foreach ($data as $j => $val) { + if (is_int($j)) { + $tmpPath = array_slice($path, $i + 1); + if (empty($tmpPath)) { + $tmp[] = $val; + } else { + $tmp[] = Set::classicExtract($val, $tmpPath); + } + } + } + return $tmp; + } elseif ($key === '{s}') { + foreach ($data as $j => $val) { + if (is_string($j)) { + $tmpPath = array_slice($path, $i + 1); + if (empty($tmpPath)) { + $tmp[] = $val; + } else { + $tmp[] = Set::classicExtract($val, $tmpPath); + } + } + } + return $tmp; + } elseif (false !== strpos($key, '{') && false !== strpos($key, '}')) { + $pattern = substr($key, 1, -1); + + foreach ($data as $j => $val) { + if (preg_match('/^' . $pattern . '/s', $j) !== 0) { + $tmpPath = array_slice($path, $i + 1); + if (empty($tmpPath)) { + $tmp[$j] = $val; + } else { + $tmp[$j] = Set::classicExtract($val, $tmpPath); + } + } + } + return $tmp; + } else { + if (isset($data[$key])) { + $data = $data[$key]; + } else { + return null; + } + } + } + return $data; + } + +/** + * Inserts $data into an array as defined by $path. + * + * @param array $list Where to insert into + * @param string $path A dot-separated string. + * @param array $data Data to insert + * @return array + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/set.html#Set::insert + */ + public static function insert($list, $path, $data = null) { + return Hash::insert($list, $path, $data); + } + +/** + * Removes an element from a Set or array as defined by $path. + * + * @param array $list From where to remove + * @param string $path A dot-separated string. + * @return array Array with $path removed from its value + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/set.html#Set::remove + */ + public static function remove($list, $path = null) { + return Hash::remove($list, $path); + } + +/** + * Checks if a particular path is set in an array + * + * @param string|array $data Data to check on + * @param string|array $path A dot-separated string. + * @return boolean true if path is found, false otherwise + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/set.html#Set::check + */ + public static function check($data, $path = null) { + if (empty($path)) { + return $data; + } + if (!is_array($path)) { + $path = explode('.', $path); + } + + foreach ($path as $i => $key) { + if (is_numeric($key) && intval($key) > 0 || $key === '0') { + $key = intval($key); + } + if ($i === count($path) - 1) { + return (is_array($data) && array_key_exists($key, $data)); + } + + if (!is_array($data) || !array_key_exists($key, $data)) { + return false; + } + $data =& $data[$key]; + } + return true; + } + +/** + * Computes the difference between a Set and an array, two Sets, or two arrays + * + * @param mixed $val1 First value + * @param mixed $val2 Second value + * @return array Returns the key => value pairs that are not common in $val1 and $val2 + * The expression for this function is($val1 - $val2) + ($val2 - ($val1 - $val2)) + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/set.html#Set::diff + */ + public static function diff($val1, $val2 = null) { + if (empty($val1)) { + return (array)$val2; + } + if (empty($val2)) { + return (array)$val1; + } + $intersection = array_intersect_key($val1, $val2); + while (($key = key($intersection)) !== null) { + if ($val1[$key] == $val2[$key]) { + unset($val1[$key]); + unset($val2[$key]); + } + next($intersection); + } + + return $val1 + $val2; + } + +/** + * Determines if one Set or array contains the exact keys and values of another. + * + * @param array $val1 First value + * @param array $val2 Second value + * @return boolean true if $val1 contains $val2, false otherwise + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/set.html#Set::contains + */ + public static function contains($val1, $val2 = null) { + if (empty($val1) || empty($val2)) { + return false; + } + + foreach ($val2 as $key => $val) { + if (is_numeric($key)) { + Set::contains($val, $val1); + } else { + if (!isset($val1[$key]) || $val1[$key] != $val) { + return false; + } + } + } + return true; + } + +/** + * Counts the dimensions of an array. If $all is set to false (which is the default) it will + * only consider the dimension of the first element in the array. + * + * @param array $array Array to count dimensions on + * @param boolean $all Set to true to count the dimension considering all elements in array + * @param integer $count Start the dimension count at this number + * @return integer The number of dimensions in $array + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/set.html#Set::countDim + */ + public static function countDim($array = null, $all = false, $count = 0) { + if ($all) { + $depth = array($count); + if (is_array($array) && reset($array) !== false) { + foreach ($array as $value) { + $depth[] = Set::countDim($value, true, $count + 1); + } + } + $return = max($depth); + } else { + if (is_array(reset($array))) { + $return = Set::countDim(reset($array)) + 1; + } else { + $return = 1; + } + } + return $return; + } + +/** + * Normalizes a string or array list. + * + * @param mixed $list List to normalize + * @param boolean $assoc If true, $list will be converted to an associative array + * @param string $sep If $list is a string, it will be split into an array with $sep + * @param boolean $trim If true, separated strings will be trimmed + * @return array + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/set.html#Set::normalize + */ + public static function normalize($list, $assoc = true, $sep = ',', $trim = true) { + if (is_string($list)) { + $list = explode($sep, $list); + if ($trim) { + foreach ($list as $key => $value) { + $list[$key] = trim($value); + } + } + if ($assoc) { + return Hash::normalize($list); + } + } elseif (is_array($list)) { + $list = Hash::normalize($list, $assoc); + } + return $list; + } + +/** + * Creates an associative array using a $path1 as the path to build its keys, and optionally + * $path2 as path to get the values. If $path2 is not specified, all values will be initialized + * to null (useful for Set::merge). You can optionally group the values by what is obtained when + * following the path specified in $groupPath. + * + * @param array|object $data Array or object from where to extract keys and values + * @param string|array $path1 As an array, or as a dot-separated string. + * @param string|array $path2 As an array, or as a dot-separated string. + * @param string $groupPath As an array, or as a dot-separated string. + * @return array Combined array + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/set.html#Set::combine + */ + public static function combine($data, $path1 = null, $path2 = null, $groupPath = null) { + if (empty($data)) { + return array(); + } + + if (is_object($data)) { + if (!($data instanceof ArrayAccess || $data instanceof Traversable)) { + $data = get_object_vars($data); + } + } + + if (is_array($path1)) { + $format = array_shift($path1); + $keys = Set::format($data, $format, $path1); + } else { + $keys = Set::extract($data, $path1); + } + if (empty($keys)) { + return array(); + } + + if (!empty($path2) && is_array($path2)) { + $format = array_shift($path2); + $vals = Set::format($data, $format, $path2); + } elseif (!empty($path2)) { + $vals = Set::extract($data, $path2); + } else { + $count = count($keys); + for ($i = 0; $i < $count; $i++) { + $vals[$i] = null; + } + } + + if ($groupPath != null) { + $group = Set::extract($data, $groupPath); + if (!empty($group)) { + $c = count($keys); + for ($i = 0; $i < $c; $i++) { + if (!isset($group[$i])) { + $group[$i] = 0; + } + if (!isset($out[$group[$i]])) { + $out[$group[$i]] = array(); + } + $out[$group[$i]][$keys[$i]] = $vals[$i]; + } + return $out; + } + } + if (empty($vals)) { + return array(); + } + return array_combine($keys, $vals); + } + +/** + * Converts an object into an array. + * @param object $object Object to reverse + * @return array Array representation of given object + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/set.html#Set::reverse + */ + public static function reverse($object) { + $out = array(); + if ($object instanceof SimpleXMLElement) { + return Xml::toArray($object); + } elseif (is_object($object)) { + $keys = get_object_vars($object); + if (isset($keys['_name_'])) { + $identity = $keys['_name_']; + unset($keys['_name_']); + } + $new = array(); + foreach ($keys as $key => $value) { + if (is_array($value)) { + $new[$key] = (array)Set::reverse($value); + } else { + // @codingStandardsIgnoreStart Legacy junk + if (isset($value->_name_)) { + $new = array_merge($new, Set::reverse($value)); + } else { + $new[$key] = Set::reverse($value); + } + // @codingStandardsIgnoreEnd + } + } + if (isset($identity)) { + $out[$identity] = $new; + } else { + $out = $new; + } + } elseif (is_array($object)) { + foreach ($object as $key => $value) { + $out[$key] = Set::reverse($value); + } + } else { + $out = $object; + } + return $out; + } + +/** + * Collapses a multi-dimensional array into a single dimension, using a delimited array path for + * each array element's key, i.e. array(array('Foo' => array('Bar' => 'Far'))) becomes + * array('0.Foo.Bar' => 'Far'). + * + * @param array $data Array to flatten + * @param string $separator String used to separate array key elements in a path, defaults to '.' + * @return array + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/set.html#Set::flatten + */ + public static function flatten($data, $separator = '.') { + return Hash::flatten($data, $separator); + } + +/** + * Expand/unflattens an string to an array + * + * For example, unflattens an array that was collapsed with `Set::flatten()` + * into a multi-dimensional array. So, `array('0.Foo.Bar' => 'Far')` becomes + * `array(array('Foo' => array('Bar' => 'Far')))`. + * + * @param array $data Flattened array + * @param string $separator The delimiter used + * @return array + */ + public static function expand($data, $separator = '.') { + return Hash::expand($data, $separator); + } + +/** + * Flattens an array for sorting + * + * @param array $results + * @param string $key + * @return array + */ + protected static function _flatten($results, $key = null) { + $stack = array(); + foreach ($results as $k => $r) { + $id = $k; + if (!is_null($key)) { + $id = $key; + } + if (is_array($r) && !empty($r)) { + $stack = array_merge($stack, Set::_flatten($r, $id)); + } else { + $stack[] = array('id' => $id, 'value' => $r); + } + } + return $stack; + } + +/** + * Sorts an array by any value, determined by a Set-compatible path + * + * @param array $data An array of data to sort + * @param string $path A Set-compatible path to the array value + * @param string $dir Direction of sorting - either ascending (ASC), or descending (DESC) + * @return array Sorted array of data + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/set.html#Set::sort + */ + public static function sort($data, $path, $dir) { + $originalKeys = array_keys($data); + $numeric = false; + if (is_numeric(implode('', $originalKeys))) { + $data = array_values($data); + $numeric = true; + } + $result = Set::_flatten(Set::extract($data, $path)); + list($keys, $values) = array(Set::extract($result, '{n}.id'), Set::extract($result, '{n}.value')); + + $dir = strtolower($dir); + if ($dir === 'asc') { + $dir = SORT_ASC; + } elseif ($dir === 'desc') { + $dir = SORT_DESC; + } + array_multisort($values, $dir, $keys, $dir); + $sorted = array(); + $keys = array_unique($keys); + + foreach ($keys as $k) { + if ($numeric) { + $sorted[] = $data[$k]; + } else { + if (isset($originalKeys[$k])) { + $sorted[$originalKeys[$k]] = $data[$originalKeys[$k]]; + } else { + $sorted[$k] = $data[$k]; + } + } + } + return $sorted; + } + +/** + * Allows the application of a callback method to elements of an + * array extracted by a Set::extract() compatible path. + * + * @param mixed $path Set-compatible path to the array value + * @param array $data An array of data to extract from & then process with the $callback. + * @param mixed $callback Callback method to be applied to extracted data. + * See http://ca2.php.net/manual/en/language.pseudo-types.php#language.types.callback for examples + * of callback formats. + * @param array $options Options are: + * - type : can be pass, map, or reduce. Map will handoff the given callback + * to array_map, reduce will handoff to array_reduce, and pass will + * use call_user_func_array(). + * @return mixed Result of the callback when applied to extracted data + * @link http://book.cakephp.org/2.0/en/core-utility-libraries/set.html#Set::apply + */ + public static function apply($path, $data, $callback, $options = array()) { + $defaults = array('type' => 'pass'); + $options = array_merge($defaults, $options); + $extracted = Set::extract($path, $data); + + if ($options['type'] === 'map') { + return array_map($callback, $extracted); + } elseif ($options['type'] === 'reduce') { + return array_reduce($extracted, $callback); + } elseif ($options['type'] === 'pass') { + return call_user_func_array($callback, array($extracted)); + } + return null; + } + +/** + * Takes in a flat array and returns a nested array + * + * @param mixed $data + * @param array $options Options are: + * children - the key name to use in the resultset for children + * idPath - the path to a key that identifies each entry + * parentPath - the path to a key that identifies the parent of each entry + * root - the id of the desired top-most result + * @return array of results, nested + * @link + */ + public static function nest($data, $options = array()) { + if (!$data) { + return $data; + } + + $alias = key(current($data)); + $options += array( + 'idPath' => "/$alias/id", + 'parentPath' => "/$alias/parent_id", + 'children' => 'children', + 'root' => null + ); + + $return = $idMap = array(); + $ids = Set::extract($data, $options['idPath']); + $idKeys = explode('/', trim($options['idPath'], '/')); + $parentKeys = explode('/', trim($options['parentPath'], '/')); + + foreach ($data as $result) { + $result[$options['children']] = array(); + + $id = Set::get($result, $idKeys); + $parentId = Set::get($result, $parentKeys); + + if (isset($idMap[$id][$options['children']])) { + $idMap[$id] = array_merge($result, (array)$idMap[$id]); + } else { + $idMap[$id] = array_merge($result, array($options['children'] => array())); + } + if (!$parentId || !in_array($parentId, $ids)) { + $return[] =& $idMap[$id]; + } else { + $idMap[$parentId][$options['children']][] =& $idMap[$id]; + } + } + + if ($options['root']) { + $root = $options['root']; + } else { + $root = Set::get($return[0], $parentKeys); + } + + foreach ($return as $i => $result) { + $id = Set::get($result, $idKeys); + $parentId = Set::get($result, $parentKeys); + if ($id !== $root && $parentId != $root) { + unset($return[$i]); + } + } + + return array_values($return); + } + +/** + * Return the value at the specified position + * + * @param array $input an array + * @param string|array $path string or array of array keys + * @return the value at the specified position or null if it doesn't exist + */ + public static function get($input, $path = null) { + if (is_string($path)) { + if (strpos($path, '/') !== false) { + $keys = explode('/', trim($path, '/')); + } else { + $keys = explode('.', trim($path, '.')); + } + } else { + $keys = $path; + } + return Hash::get($input, $keys); + } + +} diff --git a/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/String.php b/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/String.php new file mode 100644 index 0000000..01f9acb --- /dev/null +++ b/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/String.php @@ -0,0 +1,605 @@ +<?php +/** + * String handling methods. + * + * PHP 5 + * + * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) + * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * Redistributions of files must retain the above copyright notice. + * + * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://cakephp.org CakePHP(tm) Project + * @package Cake.Utility + * @since CakePHP(tm) v 1.2.0.5551 + * @license MIT License (http://www.opensource.org/licenses/mit-license.php) + */ + +/** + * String handling methods. + * + * + * @package Cake.Utility + */ +class String { + +/** + * Generate a random UUID + * + * @see http://www.ietf.org/rfc/rfc4122.txt + * @return RFC 4122 UUID + */ + public static function uuid() { + $node = env('SERVER_ADDR'); + + if (strpos($node, ':') !== false) { + if (substr_count($node, '::')) { + $node = str_replace( + '::', str_repeat(':0000', 8 - substr_count($node, ':')) . ':', $node + ); + } + $node = explode(':', $node); + $ipSix = ''; + + foreach ($node as $id) { + $ipSix .= str_pad(base_convert($id, 16, 2), 16, 0, STR_PAD_LEFT); + } + $node = base_convert($ipSix, 2, 10); + + if (strlen($node) < 38) { + $node = null; + } else { + $node = crc32($node); + } + } elseif (empty($node)) { + $host = env('HOSTNAME'); + + if (empty($host)) { + $host = env('HOST'); + } + + if (!empty($host)) { + $ip = gethostbyname($host); + + if ($ip === $host) { + $node = crc32($host); + } else { + $node = ip2long($ip); + } + } + } elseif ($node !== '127.0.0.1') { + $node = ip2long($node); + } else { + $node = null; + } + + if (empty($node)) { + $node = crc32(Configure::read('Security.salt')); + } + + if (function_exists('hphp_get_thread_id')) { + $pid = hphp_get_thread_id(); + } elseif (function_exists('zend_thread_id')) { + $pid = zend_thread_id(); + } else { + $pid = getmypid(); + } + + if (!$pid || $pid > 65535) { + $pid = mt_rand(0, 0xfff) | 0x4000; + } + + list($timeMid, $timeLow) = explode(' ', microtime()); + $uuid = sprintf( + "%08x-%04x-%04x-%02x%02x-%04x%08x", (int)$timeLow, (int)substr($timeMid, 2) & 0xffff, + mt_rand(0, 0xfff) | 0x4000, mt_rand(0, 0x3f) | 0x80, mt_rand(0, 0xff), $pid, $node + ); + + return $uuid; + } + +/** + * Tokenizes a string using $separator, ignoring any instance of $separator that appears between + * $leftBound and $rightBound + * + * @param string $data The data to tokenize + * @param string $separator The token to split the data on. + * @param string $leftBound The left boundary to ignore separators in. + * @param string $rightBound The right boundary to ignore separators in. + * @return array Array of tokens in $data. + */ + public static function tokenize($data, $separator = ',', $leftBound = '(', $rightBound = ')') { + if (empty($data) || is_array($data)) { + return $data; + } + + $depth = 0; + $offset = 0; + $buffer = ''; + $results = array(); + $length = strlen($data); + $open = false; + + while ($offset <= $length) { + $tmpOffset = -1; + $offsets = array( + strpos($data, $separator, $offset), + strpos($data, $leftBound, $offset), + strpos($data, $rightBound, $offset) + ); + for ($i = 0; $i < 3; $i++) { + if ($offsets[$i] !== false && ($offsets[$i] < $tmpOffset || $tmpOffset == -1)) { + $tmpOffset = $offsets[$i]; + } + } + if ($tmpOffset !== -1) { + $buffer .= substr($data, $offset, ($tmpOffset - $offset)); + if ($data{$tmpOffset} == $separator && $depth == 0) { + $results[] = $buffer; + $buffer = ''; + } else { + $buffer .= $data{$tmpOffset}; + } + if ($leftBound != $rightBound) { + if ($data{$tmpOffset} == $leftBound) { + $depth++; + } + if ($data{$tmpOffset} == $rightBound) { + $depth--; + } + } else { + if ($data{$tmpOffset} == $leftBound) { + if (!$open) { + $depth++; + $open = true; + } else { + $depth--; + $open = false; + } + } + } + $offset = ++$tmpOffset; + } else { + $results[] = $buffer . substr($data, $offset); + $offset = $length + 1; + } + } + if (empty($results) && !empty($buffer)) { + $results[] = $buffer; + } + + if (!empty($results)) { + $data = array_map('trim', $results); + } else { + $data = array(); + } + return $data; + } + +/** + * Replaces variable placeholders inside a $str with any given $data. Each key in the $data array + * corresponds to a variable placeholder name in $str. + * Example: `String::insert(':name is :age years old.', array('name' => 'Bob', '65'));` + * Returns: Bob is 65 years old. + * + * Available $options are: + * + * - before: The character or string in front of the name of the variable placeholder (Defaults to `:`) + * - after: The character or string after the name of the variable placeholder (Defaults to null) + * - escape: The character or string used to escape the before character / string (Defaults to `\`) + * - format: A regex to use for matching variable placeholders. Default is: `/(?<!\\)\:%s/` + * (Overwrites before, after, breaks escape / clean) + * - clean: A boolean or array with instructions for String::cleanInsert + * + * @param string $str A string containing variable placeholders + * @param string $data A key => val array where each key stands for a placeholder variable name + * to be replaced with val + * @param string $options An array of options, see description above + * @return string + */ + public static function insert($str, $data, $options = array()) { + $defaults = array( + 'before' => ':', 'after' => null, 'escape' => '\\', 'format' => null, 'clean' => false + ); + $options += $defaults; + $format = $options['format']; + $data = (array)$data; + if (empty($data)) { + return ($options['clean']) ? String::cleanInsert($str, $options) : $str; + } + + if (!isset($format)) { + $format = sprintf( + '/(?<!%s)%s%%s%s/', + preg_quote($options['escape'], '/'), + str_replace('%', '%%', preg_quote($options['before'], '/')), + str_replace('%', '%%', preg_quote($options['after'], '/')) + ); + } + + if (strpos($str, '?') !== false && is_numeric(key($data))) { + $offset = 0; + while (($pos = strpos($str, '?', $offset)) !== false) { + $val = array_shift($data); + $offset = $pos + strlen($val); + $str = substr_replace($str, $val, $pos, 1); + } + return ($options['clean']) ? String::cleanInsert($str, $options) : $str; + } else { + asort($data); + + $hashKeys = array(); + foreach ($data as $key => $value) { + $hashKeys[] = crc32($key); + } + + $tempData = array_combine(array_keys($data), array_values($hashKeys)); + krsort($tempData); + foreach ($tempData as $key => $hashVal) { + $key = sprintf($format, preg_quote($key, '/')); + $str = preg_replace($key, $hashVal, $str); + } + $dataReplacements = array_combine($hashKeys, array_values($data)); + foreach ($dataReplacements as $tmpHash => $tmpValue) { + $tmpValue = (is_array($tmpValue)) ? '' : $tmpValue; + $str = str_replace($tmpHash, $tmpValue, $str); + } + } + + if (!isset($options['format']) && isset($options['before'])) { + $str = str_replace($options['escape'] . $options['before'], $options['before'], $str); + } + return ($options['clean']) ? String::cleanInsert($str, $options) : $str; + } + +/** + * Cleans up a String::insert() formatted string with given $options depending on the 'clean' key in + * $options. The default method used is text but html is also available. The goal of this function + * is to replace all whitespace and unneeded markup around placeholders that did not get replaced + * by String::insert(). + * + * @param string $str + * @param string $options + * @return string + * @see String::insert() + */ + public static function cleanInsert($str, $options) { + $clean = $options['clean']; + if (!$clean) { + return $str; + } + if ($clean === true) { + $clean = array('method' => 'text'); + } + if (!is_array($clean)) { + $clean = array('method' => $options['clean']); + } + switch ($clean['method']) { + case 'html': + $clean = array_merge(array( + 'word' => '[\w,.]+', + 'andText' => true, + 'replacement' => '', + ), $clean); + $kleenex = sprintf( + '/[\s]*[a-z]+=(")(%s%s%s[\s]*)+\\1/i', + preg_quote($options['before'], '/'), + $clean['word'], + preg_quote($options['after'], '/') + ); + $str = preg_replace($kleenex, $clean['replacement'], $str); + if ($clean['andText']) { + $options['clean'] = array('method' => 'text'); + $str = String::cleanInsert($str, $options); + } + break; + case 'text': + $clean = array_merge(array( + 'word' => '[\w,.]+', + 'gap' => '[\s]*(?:(?:and|or)[\s]*)?', + 'replacement' => '', + ), $clean); + + $kleenex = sprintf( + '/(%s%s%s%s|%s%s%s%s)/', + preg_quote($options['before'], '/'), + $clean['word'], + preg_quote($options['after'], '/'), + $clean['gap'], + $clean['gap'], + preg_quote($options['before'], '/'), + $clean['word'], + preg_quote($options['after'], '/') + ); + $str = preg_replace($kleenex, $clean['replacement'], $str); + break; + } + return $str; + } + +/** + * Wraps text to a specific width, can optionally wrap at word breaks. + * + * ### Options + * + * - `width` The width to wrap to. Defaults to 72 + * - `wordWrap` Only wrap on words breaks (spaces) Defaults to true. + * - `indent` String to indent with. Defaults to null. + * - `indentAt` 0 based index to start indenting at. Defaults to 0. + * + * @param string $text Text the text to format. + * @param array|integer $options Array of options to use, or an integer to wrap the text to. + * @return string Formatted text. + */ + public static function wrap($text, $options = array()) { + if (is_numeric($options)) { + $options = array('width' => $options); + } + $options += array('width' => 72, 'wordWrap' => true, 'indent' => null, 'indentAt' => 0); + if ($options['wordWrap']) { + $wrapped = wordwrap($text, $options['width'], "\n"); + } else { + $wrapped = trim(chunk_split($text, $options['width'] - 1, "\n")); + } + if (!empty($options['indent'])) { + $chunks = explode("\n", $wrapped); + for ($i = $options['indentAt'], $len = count($chunks); $i < $len; $i++) { + $chunks[$i] = $options['indent'] . $chunks[$i]; + } + $wrapped = implode("\n", $chunks); + } + return $wrapped; + } + +/** + * Highlights a given phrase in a text. You can specify any expression in highlighter that + * may include the \1 expression to include the $phrase found. + * + * ### Options: + * + * - `format` The piece of html with that the phrase will be highlighted + * - `html` If true, will ignore any HTML tags, ensuring that only the correct text is highlighted + * - `regex` a custom regex rule that is ued to match words, default is '|$tag|iu' + * + * @param string $text Text to search the phrase in + * @param string $phrase The phrase that will be searched + * @param array $options An array of html attributes and options. + * @return string The highlighted text + * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/text.html#TextHelper::highlight + */ + public static function highlight($text, $phrase, $options = array()) { + if (empty($phrase)) { + return $text; + } + + $default = array( + 'format' => '<span class="highlight">\1</span>', + 'html' => false, + 'regex' => "|%s|iu" + ); + $options = array_merge($default, $options); + extract($options); + + if (is_array($phrase)) { + $replace = array(); + $with = array(); + + foreach ($phrase as $key => $segment) { + $segment = '(' . preg_quote($segment, '|') . ')'; + if ($html) { + $segment = "(?![^<]+>)$segment(?![^<]+>)"; + } + + $with[] = (is_array($format)) ? $format[$key] : $format; + $replace[] = sprintf($options['regex'], $segment); + } + + return preg_replace($replace, $with, $text); + } else { + $phrase = '(' . preg_quote($phrase, '|') . ')'; + if ($html) { + $phrase = "(?![^<]+>)$phrase(?![^<]+>)"; + } + + return preg_replace(sprintf($options['regex'], $phrase), $format, $text); + } + } + +/** + * Strips given text of all links (<a href=....) + * + * @param string $text Text + * @return string The text without links + * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/text.html#TextHelper::stripLinks + */ + public static function stripLinks($text) { + return preg_replace('|<a\s+[^>]+>|im', '', preg_replace('|<\/a>|im', '', $text)); + } + +/** + * Truncates text. + * + * Cuts a string to the length of $length and replaces the last characters + * with the ending if the text is longer than length. + * + * ### Options: + * + * - `ending` Will be used as Ending and appended to the trimmed string + * - `exact` If false, $text will not be cut mid-word + * - `html` If true, HTML tags would be handled correctly + * + * @param string $text String to truncate. + * @param integer $length Length of returned string, including ellipsis. + * @param array $options An array of html attributes and options. + * @return string Trimmed string. + * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/text.html#TextHelper::truncate + */ + public static function truncate($text, $length = 100, $options = array()) { + $default = array( + 'ending' => '...', 'exact' => true, 'html' => false + ); + $options = array_merge($default, $options); + extract($options); + + if (!function_exists('mb_strlen')) { + class_exists('Multibyte'); + } + + if ($html) { + if (mb_strlen(preg_replace('/<.*?>/', '', $text)) <= $length) { + return $text; + } + $totalLength = mb_strlen(strip_tags($ending)); + $openTags = array(); + $truncate = ''; + + preg_match_all('/(<\/?([\w+]+)[^>]*>)?([^<>]*)/', $text, $tags, PREG_SET_ORDER); + foreach ($tags as $tag) { + if (!preg_match('/img|br|input|hr|area|base|basefont|col|frame|isindex|link|meta|param/s', $tag[2])) { + if (preg_match('/<[\w]+[^>]*>/s', $tag[0])) { + array_unshift($openTags, $tag[2]); + } elseif (preg_match('/<\/([\w]+)[^>]*>/s', $tag[0], $closeTag)) { + $pos = array_search($closeTag[1], $openTags); + if ($pos !== false) { + array_splice($openTags, $pos, 1); + } + } + } + $truncate .= $tag[1]; + + $contentLength = mb_strlen(preg_replace('/&[0-9a-z]{2,8};|&#[0-9]{1,7};|&#x[0-9a-f]{1,6};/i', ' ', $tag[3])); + if ($contentLength + $totalLength > $length) { + $left = $length - $totalLength; + $entitiesLength = 0; + if (preg_match_all('/&[0-9a-z]{2,8};|&#[0-9]{1,7};|&#x[0-9a-f]{1,6};/i', $tag[3], $entities, PREG_OFFSET_CAPTURE)) { + foreach ($entities[0] as $entity) { + if ($entity[1] + 1 - $entitiesLength <= $left) { + $left--; + $entitiesLength += mb_strlen($entity[0]); + } else { + break; + } + } + } + + $truncate .= mb_substr($tag[3], 0 , $left + $entitiesLength); + break; + } else { + $truncate .= $tag[3]; + $totalLength += $contentLength; + } + if ($totalLength >= $length) { + break; + } + } + } else { + if (mb_strlen($text) <= $length) { + return $text; + } else { + $truncate = mb_substr($text, 0, $length - mb_strlen($ending)); + } + } + if (!$exact) { + $spacepos = mb_strrpos($truncate, ' '); + if ($html) { + $truncateCheck = mb_substr($truncate, 0, $spacepos); + $lastOpenTag = mb_strrpos($truncateCheck, '<'); + $lastCloseTag = mb_strrpos($truncateCheck, '>'); + if ($lastOpenTag > $lastCloseTag) { + preg_match_all('/<[\w]+[^>]*>/s', $truncate, $lastTagMatches); + $lastTag = array_pop($lastTagMatches[0]); + $spacepos = mb_strrpos($truncate, $lastTag) + mb_strlen($lastTag); + } + $bits = mb_substr($truncate, $spacepos); + preg_match_all('/<\/([a-z]+)>/', $bits, $droppedTags, PREG_SET_ORDER); + if (!empty($droppedTags)) { + if (!empty($openTags)) { + foreach ($droppedTags as $closingTag) { + if (!in_array($closingTag[1], $openTags)) { + array_unshift($openTags, $closingTag[1]); + } + } + } else { + foreach ($droppedTags as $closingTag) { + array_push($openTags, $closingTag[1]); + } + } + } + } + $truncate = mb_substr($truncate, 0, $spacepos); + } + $truncate .= $ending; + + if ($html) { + foreach ($openTags as $tag) { + $truncate .= '</' . $tag . '>'; + } + } + + return $truncate; + } + +/** + * Extracts an excerpt from the text surrounding the phrase with a number of characters on each side + * determined by radius. + * + * @param string $text String to search the phrase in + * @param string $phrase Phrase that will be searched for + * @param integer $radius The amount of characters that will be returned on each side of the founded phrase + * @param string $ending Ending that will be appended + * @return string Modified string + * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/text.html#TextHelper::excerpt + */ + public static function excerpt($text, $phrase, $radius = 100, $ending = '...') { + if (empty($text) || empty($phrase)) { + return self::truncate($text, $radius * 2, array('ending' => $ending)); + } + + $append = $prepend = $ending; + + $phraseLen = mb_strlen($phrase); + $textLen = mb_strlen($text); + + $pos = mb_strpos(mb_strtolower($text), mb_strtolower($phrase)); + if ($pos === false) { + return mb_substr($text, 0, $radius) . $ending; + } + + $startPos = $pos - $radius; + if ($startPos <= 0) { + $startPos = 0; + $prepend = ''; + } + + $endPos = $pos + $phraseLen + $radius; + if ($endPos >= $textLen) { + $endPos = $textLen; + $append = ''; + } + + $excerpt = mb_substr($text, $startPos, $endPos - $startPos); + $excerpt = $prepend . $excerpt . $append; + + return $excerpt; + } + +/** + * Creates a comma separated list where the last two items are joined with 'and', forming natural English + * + * @param array $list The list to be joined + * @param string $and The word used to join the last and second last items together with. Defaults to 'and' + * @param string $separator The separator used to join all the other items together. Defaults to ', ' + * @return string The glued together string. + * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/text.html#TextHelper::toList + */ + public static function toList($list, $and = 'and', $separator = ', ') { + if (count($list) > 1) { + return implode($separator, array_slice($list, null, -1)) . ' ' . $and . ' ' . array_pop($list); + } else { + return array_pop($list); + } + } + +} diff --git a/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/Validation.php b/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/Validation.php new file mode 100644 index 0000000..d709732 --- /dev/null +++ b/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/Validation.php @@ -0,0 +1,937 @@ +<?php +/** + * Validation Class. Used for validation of model data + * + * PHP Version 5.x + * + * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) + * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * Redistributions of files must retain the above copyright notice. + * + * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://cakephp.org CakePHP(tm) Project + * @package Cake.Utility + * @since CakePHP(tm) v 1.2.0.3830 + * @license MIT License (http://www.opensource.org/licenses/mit-license.php) + */ + +App::uses('Multibyte', 'I18n'); +App::uses('File', 'Utility'); +// Load multibyte if the extension is missing. +if (!function_exists('mb_strlen')) { + class_exists('Multibyte'); +} + +/** + * Offers different validation methods. + * + * @package Cake.Utility + * @since CakePHP v 1.2.0.3830 + */ +class Validation { + +/** + * Some complex patterns needed in multiple places + * + * @var array + */ + protected static $_pattern = array( + 'hostname' => '(?:[a-z0-9][-a-z0-9]*\.)*(?:[a-z0-9][-a-z0-9]{0,62})\.(?:(?:[a-z]{2}\.)?[a-z]{2,4}|museum|travel)' + ); + +/** + * Holds an array of errors messages set in this class. + * These are used for debugging purposes + * + * @var array + */ + public static $errors = array(); + +/** + * Checks that a string contains something other than whitespace + * + * Returns true if string contains something other than whitespace + * + * $check can be passed as an array: + * array('check' => 'valueToCheck'); + * + * @param string|array $check Value to check + * @return boolean Success + */ + public static function notEmpty($check) { + if (is_array($check)) { + extract(self::_defaults($check)); + } + + if (empty($check) && $check != '0') { + return false; + } + return self::_check($check, '/[^\s]+/m'); + } + +/** + * Checks that a string contains only integer or letters + * + * Returns true if string contains only integer or letters + * + * $check can be passed as an array: + * array('check' => 'valueToCheck'); + * + * @param string|array $check Value to check + * @return boolean Success + */ + public static function alphaNumeric($check) { + if (is_array($check)) { + extract(self::_defaults($check)); + } + + if (empty($check) && $check != '0') { + return false; + } + return self::_check($check, '/^[\p{Ll}\p{Lm}\p{Lo}\p{Lt}\p{Lu}\p{Nd}]+$/mu'); + } + +/** + * Checks that a string length is within s specified range. + * Spaces are included in the character count. + * Returns true is string matches value min, max, or between min and max, + * + * @param string $check Value to check for length + * @param integer $min Minimum value in range (inclusive) + * @param integer $max Maximum value in range (inclusive) + * @return boolean Success + */ + public static function between($check, $min, $max) { + $length = mb_strlen($check); + return ($length >= $min && $length <= $max); + } + +/** + * Returns true if field is left blank -OR- only whitespace characters are present in it's value + * Whitespace characters include Space, Tab, Carriage Return, Newline + * + * $check can be passed as an array: + * array('check' => 'valueToCheck'); + * + * @param string|array $check Value to check + * @return boolean Success + */ + public static function blank($check) { + if (is_array($check)) { + extract(self::_defaults($check)); + } + return !self::_check($check, '/[^\\s]/'); + } + +/** + * Validation of credit card numbers. + * Returns true if $check is in the proper credit card format. + * + * @param string|array $check credit card number to validate + * @param string|array $type 'all' may be passed as a sting, defaults to fast which checks format of most major credit cards + * if an array is used only the values of the array are checked. + * Example: array('amex', 'bankcard', 'maestro') + * @param boolean $deep set to true this will check the Luhn algorithm of the credit card. + * @param string $regex A custom regex can also be passed, this will be used instead of the defined regex values + * @return boolean Success + * @see Validation::luhn() + */ + public static function cc($check, $type = 'fast', $deep = false, $regex = null) { + if (is_array($check)) { + extract(self::_defaults($check)); + } + + $check = str_replace(array('-', ' '), '', $check); + if (mb_strlen($check) < 13) { + return false; + } + + if (!is_null($regex)) { + if (self::_check($check, $regex)) { + return self::luhn($check, $deep); + } + } + $cards = array( + 'all' => array( + 'amex' => '/^3[4|7]\\d{13}$/', + 'bankcard' => '/^56(10\\d\\d|022[1-5])\\d{10}$/', + 'diners' => '/^(?:3(0[0-5]|[68]\\d)\\d{11})|(?:5[1-5]\\d{14})$/', + 'disc' => '/^(?:6011|650\\d)\\d{12}$/', + 'electron' => '/^(?:417500|4917\\d{2}|4913\\d{2})\\d{10}$/', + 'enroute' => '/^2(?:014|149)\\d{11}$/', + 'jcb' => '/^(3\\d{4}|2100|1800)\\d{11}$/', + 'maestro' => '/^(?:5020|6\\d{3})\\d{12}$/', + 'mc' => '/^5[1-5]\\d{14}$/', + 'solo' => '/^(6334[5-9][0-9]|6767[0-9]{2})\\d{10}(\\d{2,3})?$/', + 'switch' => '/^(?:49(03(0[2-9]|3[5-9])|11(0[1-2]|7[4-9]|8[1-2])|36[0-9]{2})\\d{10}(\\d{2,3})?)|(?:564182\\d{10}(\\d{2,3})?)|(6(3(33[0-4][0-9])|759[0-9]{2})\\d{10}(\\d{2,3})?)$/', + 'visa' => '/^4\\d{12}(\\d{3})?$/', + 'voyager' => '/^8699[0-9]{11}$/' + ), + 'fast' => '/^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6011[0-9]{12}|3(?:0[0-5]|[68][0-9])[0-9]{11}|3[47][0-9]{13})$/' + ); + + if (is_array($type)) { + foreach ($type as $value) { + $regex = $cards['all'][strtolower($value)]; + + if (self::_check($check, $regex)) { + return self::luhn($check, $deep); + } + } + } elseif ($type == 'all') { + foreach ($cards['all'] as $value) { + $regex = $value; + + if (self::_check($check, $regex)) { + return self::luhn($check, $deep); + } + } + } else { + $regex = $cards['fast']; + + if (self::_check($check, $regex)) { + return self::luhn($check, $deep); + } + } + return false; + } + +/** + * Used to compare 2 numeric values. + * + * @param string|array $check1 if string is passed for a string must also be passed for $check2 + * used as an array it must be passed as array('check1' => value, 'operator' => 'value', 'check2' -> value) + * @param string $operator Can be either a word or operand + * is greater >, is less <, greater or equal >= + * less or equal <=, is less <, equal to ==, not equal != + * @param integer $check2 only needed if $check1 is a string + * @return boolean Success + */ + public static function comparison($check1, $operator = null, $check2 = null) { + if (is_array($check1)) { + extract($check1, EXTR_OVERWRITE); + } + $operator = str_replace(array(' ', "\t", "\n", "\r", "\0", "\x0B"), '', strtolower($operator)); + + switch ($operator) { + case 'isgreater': + case '>': + if ($check1 > $check2) { + return true; + } + break; + case 'isless': + case '<': + if ($check1 < $check2) { + return true; + } + break; + case 'greaterorequal': + case '>=': + if ($check1 >= $check2) { + return true; + } + break; + case 'lessorequal': + case '<=': + if ($check1 <= $check2) { + return true; + } + break; + case 'equalto': + case '==': + if ($check1 == $check2) { + return true; + } + break; + case 'notequal': + case '!=': + if ($check1 != $check2) { + return true; + } + break; + default: + self::$errors[] = __d('cake_dev', 'You must define the $operator parameter for Validation::comparison()'); + break; + } + return false; + } + +/** + * Used when a custom regular expression is needed. + * + * @param string|array $check When used as a string, $regex must also be a valid regular expression. + * As and array: array('check' => value, 'regex' => 'valid regular expression') + * @param string $regex If $check is passed as a string, $regex must also be set to valid regular expression + * @return boolean Success + */ + public static function custom($check, $regex = null) { + if (is_array($check)) { + extract(self::_defaults($check)); + } + if ($regex === null) { + self::$errors[] = __d('cake_dev', 'You must define a regular expression for Validation::custom()'); + return false; + } + return self::_check($check, $regex); + } + +/** + * Date validation, determines if the string passed is a valid date. + * keys that expect full month, day and year will validate leap years + * + * @param string $check a valid date string + * @param string|array $format Use a string or an array of the keys below. Arrays should be passed as array('dmy', 'mdy', etc) + * Keys: dmy 27-12-2006 or 27-12-06 separators can be a space, period, dash, forward slash + * mdy 12-27-2006 or 12-27-06 separators can be a space, period, dash, forward slash + * ymd 2006-12-27 or 06-12-27 separators can be a space, period, dash, forward slash + * dMy 27 December 2006 or 27 Dec 2006 + * Mdy December 27, 2006 or Dec 27, 2006 comma is optional + * My December 2006 or Dec 2006 + * my 12/2006 separators can be a space, period, dash, forward slash + * @param string $regex If a custom regular expression is used this is the only validation that will occur. + * @return boolean Success + */ + public static function date($check, $format = 'ymd', $regex = null) { + if (!is_null($regex)) { + return self::_check($check, $regex); + } + + $regex['dmy'] = '%^(?:(?:31(\\/|-|\\.|\\x20)(?:0?[13578]|1[02]))\\1|(?:(?:29|30)(\\/|-|\\.|\\x20)(?:0?[1,3-9]|1[0-2])\\2))(?:(?:1[6-9]|[2-9]\\d)?\\d{2})$|^(?:29(\\/|-|\\.|\\x20)0?2\\3(?:(?:(?:1[6-9]|[2-9]\\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:0?[1-9]|1\\d|2[0-8])(\\/|-|\\.|\\x20)(?:(?:0?[1-9])|(?:1[0-2]))\\4(?:(?:1[6-9]|[2-9]\\d)?\\d{2})$%'; + $regex['mdy'] = '%^(?:(?:(?:0?[13578]|1[02])(\\/|-|\\.|\\x20)31)\\1|(?:(?:0?[13-9]|1[0-2])(\\/|-|\\.|\\x20)(?:29|30)\\2))(?:(?:1[6-9]|[2-9]\\d)?\\d{2})$|^(?:0?2(\\/|-|\\.|\\x20)29\\3(?:(?:(?:1[6-9]|[2-9]\\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:(?:0?[1-9])|(?:1[0-2]))(\\/|-|\\.|\\x20)(?:0?[1-9]|1\\d|2[0-8])\\4(?:(?:1[6-9]|[2-9]\\d)?\\d{2})$%'; + $regex['ymd'] = '%^(?:(?:(?:(?:(?:1[6-9]|[2-9]\\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00)))(\\/|-|\\.|\\x20)(?:0?2\\1(?:29)))|(?:(?:(?:1[6-9]|[2-9]\\d)?\\d{2})(\\/|-|\\.|\\x20)(?:(?:(?:0?[13578]|1[02])\\2(?:31))|(?:(?:0?[1,3-9]|1[0-2])\\2(29|30))|(?:(?:0?[1-9])|(?:1[0-2]))\\2(?:0?[1-9]|1\\d|2[0-8]))))$%'; + $regex['dMy'] = '/^((31(?!\\ (Feb(ruary)?|Apr(il)?|June?|(Sep(?=\\b|t)t?|Nov)(ember)?)))|((30|29)(?!\\ Feb(ruary)?))|(29(?=\\ Feb(ruary)?\\ (((1[6-9]|[2-9]\\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00)))))|(0?[1-9])|1\\d|2[0-8])\\ (Jan(uary)?|Feb(ruary)?|Ma(r(ch)?|y)|Apr(il)?|Ju((ly?)|(ne?))|Aug(ust)?|Oct(ober)?|(Sep(?=\\b|t)t?|Nov|Dec)(ember)?)\\ ((1[6-9]|[2-9]\\d)\\d{2})$/'; + $regex['Mdy'] = '/^(?:(((Jan(uary)?|Ma(r(ch)?|y)|Jul(y)?|Aug(ust)?|Oct(ober)?|Dec(ember)?)\\ 31)|((Jan(uary)?|Ma(r(ch)?|y)|Apr(il)?|Ju((ly?)|(ne?))|Aug(ust)?|Oct(ober)?|(Sep)(tember)?|(Nov|Dec)(ember)?)\\ (0?[1-9]|([12]\\d)|30))|(Feb(ruary)?\\ (0?[1-9]|1\\d|2[0-8]|(29(?=,?\\ ((1[6-9]|[2-9]\\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00)))))))\\,?\\ ((1[6-9]|[2-9]\\d)\\d{2}))$/'; + $regex['My'] = '%^(Jan(uary)?|Feb(ruary)?|Ma(r(ch)?|y)|Apr(il)?|Ju((ly?)|(ne?))|Aug(ust)?|Oct(ober)?|(Sep(?=\\b|t)t?|Nov|Dec)(ember)?)[ /]((1[6-9]|[2-9]\\d)\\d{2})$%'; + $regex['my'] = '%^(((0[123456789]|10|11|12)([- /.])(([1][9][0-9][0-9])|([2][0-9][0-9][0-9]))))$%'; + + $format = (is_array($format)) ? array_values($format) : array($format); + foreach ($format as $key) { + if (self::_check($check, $regex[$key]) === true) { + return true; + } + } + return false; + } + +/** + * Validates a datetime value + * All values matching the "date" core validation rule, and the "time" one will be valid + * + * @param array $check Value to check + * @param string|array $dateFormat Format of the date part + * Use a string or an array of the keys below. Arrays should be passed as array('dmy', 'mdy', etc) + * ## Keys: + * + * - dmy 27-12-2006 or 27-12-06 separators can be a space, period, dash, forward slash + * - mdy 12-27-2006 or 12-27-06 separators can be a space, period, dash, forward slash + * - ymd 2006-12-27 or 06-12-27 separators can be a space, period, dash, forward slash + * - dMy 27 December 2006 or 27 Dec 2006 + * - Mdy December 27, 2006 or Dec 27, 2006 comma is optional + * - My December 2006 or Dec 2006 + * - my 12/2006 separators can be a space, period, dash, forward slash + * @param string $regex Regex for the date part. If a custom regular expression is used this is the only validation that will occur. + * @return boolean True if the value is valid, false otherwise + * @see Validation::date + * @see Validation::time + */ + public static function datetime($check, $dateFormat = 'ymd', $regex = null) { + $valid = false; + $parts = explode(' ', $check); + if (!empty($parts) && count($parts) > 1) { + $time = array_pop($parts); + $date = implode(' ', $parts); + $valid = self::date($date, $dateFormat, $regex) && self::time($time); + } + return $valid; + } + +/** + * Time validation, determines if the string passed is a valid time. + * Validates time as 24hr (HH:MM) or am/pm ([H]H:MM[a|p]m) + * Does not allow/validate seconds. + * + * @param string $check a valid time string + * @return boolean Success + */ + public static function time($check) { + return self::_check($check, '%^((0?[1-9]|1[012])(:[0-5]\d){0,2} ?([AP]M|[ap]m))$|^([01]\d|2[0-3])(:[0-5]\d){0,2}$%'); + } + +/** + * Boolean validation, determines if value passed is a boolean integer or true/false. + * + * @param string $check a valid boolean + * @return boolean Success + */ + public static function boolean($check) { + $booleanList = array(0, 1, '0', '1', true, false); + return in_array($check, $booleanList, true); + } + +/** + * Checks that a value is a valid decimal. If $places is null, the $check is allowed to be a scientific float + * If no decimal point is found a false will be returned. Both the sign and exponent are optional. + * + * @param integer $check The value the test for decimal + * @param integer $places if set $check value must have exactly $places after the decimal point + * @param string $regex If a custom regular expression is used this is the only validation that will occur. + * @return boolean Success + */ + public static function decimal($check, $places = null, $regex = null) { + if (is_null($regex)) { + if (is_null($places)) { + $regex = '/^[-+]?[0-9]*(\\.{1}[0-9]+(?:[eE][-+]?[0-9]+)?)?$/'; + } else { + $regex = '/^[-+]?[0-9]*(\\.{1}[0-9]{' . $places . '})?$/'; + } + } + return self::_check($check, $regex); + } + +/** + * Validates for an email address. + * + * Only uses getmxrr() checking for deep validation if PHP 5.3.0+ is used, or + * any PHP version on a non-windows distribution + * + * @param string $check Value to check + * @param boolean $deep Perform a deeper validation (if true), by also checking availability of host + * @param string $regex Regex to use (if none it will use built in regex) + * @return boolean Success + */ + public static function email($check, $deep = false, $regex = null) { + if (is_array($check)) { + extract(self::_defaults($check)); + } + + if (is_null($regex)) { + $regex = '/^[a-z0-9!#$%&\'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&\'*+\/=?^_`{|}~-]+)*@' . self::$_pattern['hostname'] . '$/i'; + } + $return = self::_check($check, $regex); + if ($deep === false || $deep === null) { + return $return; + } + + if ($return === true && preg_match('/@(' . self::$_pattern['hostname'] . ')$/i', $check, $regs)) { + if (function_exists('getmxrr') && getmxrr($regs[1], $mxhosts)) { + return true; + } + if (function_exists('checkdnsrr') && checkdnsrr($regs[1], 'MX')) { + return true; + } + return is_array(gethostbynamel($regs[1])); + } + return false; + } + +/** + * Check that value is exactly $comparedTo. + * + * @param mixed $check Value to check + * @param mixed $comparedTo Value to compare + * @return boolean Success + */ + public static function equalTo($check, $comparedTo) { + return ($check === $comparedTo); + } + +/** + * Check that value has a valid file extension. + * + * @param string|array $check Value to check + * @param array $extensions file extensions to allow. By default extensions are 'gif', 'jpeg', 'png', 'jpg' + * @return boolean Success + */ + public static function extension($check, $extensions = array('gif', 'jpeg', 'png', 'jpg')) { + if (is_array($check)) { + return self::extension(array_shift($check), $extensions); + } + $extension = strtolower(pathinfo($check, PATHINFO_EXTENSION)); + foreach ($extensions as $value) { + if ($extension === strtolower($value)) { + return true; + } + } + return false; + } + +/** + * Validation of an IP address. + * + * @param string $check The string to test. + * @param string $type The IP Protocol version to validate against + * @return boolean Success + */ + public static function ip($check, $type = 'both') { + $type = strtolower($type); + $flags = 0; + if ($type === 'ipv4') { + $flags = FILTER_FLAG_IPV4; + } + if ($type === 'ipv6') { + $flags = FILTER_FLAG_IPV6; + } + return (boolean)filter_var($check, FILTER_VALIDATE_IP, array('flags' => $flags)); + } + +/** + * Checks whether the length of a string is greater or equal to a minimal length. + * + * @param string $check The string to test + * @param integer $min The minimal string length + * @return boolean Success + */ + public static function minLength($check, $min) { + return mb_strlen($check) >= $min; + } + +/** + * Checks whether the length of a string is smaller or equal to a maximal length.. + * + * @param string $check The string to test + * @param integer $max The maximal string length + * @return boolean Success + */ + public static function maxLength($check, $max) { + return mb_strlen($check) <= $max; + } + +/** + * Checks that a value is a monetary amount. + * + * @param string $check Value to check + * @param string $symbolPosition Where symbol is located (left/right) + * @return boolean Success + */ + public static function money($check, $symbolPosition = 'left') { + $money = '(?!0,?\d)(?:\d{1,3}(?:([, .])\d{3})?(?:\1\d{3})*|(?:\d+))((?!\1)[,.]\d{2})?'; + if ($symbolPosition == 'right') { + $regex = '/^' . $money . '(?<!\x{00a2})\p{Sc}?$/u'; + } else { + $regex = '/^(?!\x{00a2})\p{Sc}?' . $money . '$/u'; + } + return self::_check($check, $regex); + } + +/** + * Validate a multiple select. + * + * Valid Options + * + * - in => provide a list of choices that selections must be made from + * - max => maximum number of non-zero choices that can be made + * - min => minimum number of non-zero choices that can be made + * + * @param array $check Value to check + * @param array $options Options for the check. + * @param boolean $strict Defaults to true, set to false to disable strict type check + * @return boolean Success + */ + public static function multiple($check, $options = array(), $strict = true) { + $defaults = array('in' => null, 'max' => null, 'min' => null); + $options = array_merge($defaults, $options); + $check = array_filter((array)$check); + if (empty($check)) { + return false; + } + if ($options['max'] && count($check) > $options['max']) { + return false; + } + if ($options['min'] && count($check) < $options['min']) { + return false; + } + if ($options['in'] && is_array($options['in'])) { + foreach ($check as $val) { + if (!in_array($val, $options['in'], $strict)) { + return false; + } + } + } + return true; + } + +/** + * Checks if a value is numeric. + * + * @param string $check Value to check + * @return boolean Success + */ + public static function numeric($check) { + return is_numeric($check); + } + +/** + * Checks if a value is a natural number. + * + * @param string $check Value to check + * @param boolean $allowZero Set true to allow zero, defaults to false + * @return boolean Success + * @see http://en.wikipedia.org/wiki/Natural_number + */ + public static function naturalNumber($check, $allowZero = false) { + $regex = $allowZero ? '/^(?:0|[1-9][0-9]*)$/' : '/^[1-9][0-9]*$/'; + return self::_check($check, $regex); + } + +/** + * Check that a value is a valid phone number. + * + * @param string|array $check Value to check (string or array) + * @param string $regex Regular expression to use + * @param string $country Country code (defaults to 'all') + * @return boolean Success + */ + public static function phone($check, $regex = null, $country = 'all') { + if (is_array($check)) { + extract(self::_defaults($check)); + } + + if (is_null($regex)) { + switch ($country) { + case 'us': + case 'all': + case 'can': + // includes all NANPA members. + // see http://en.wikipedia.org/wiki/North_American_Numbering_Plan#List_of_NANPA_countries_and_territories + $regex = '/^(?:\+?1)?[-. ]?\\(?[2-9][0-8][0-9]\\)?[-. ]?[2-9][0-9]{2}[-. ]?[0-9]{4}$/'; + break; + } + } + if (empty($regex)) { + return self::_pass('phone', $check, $country); + } + return self::_check($check, $regex); + } + +/** + * Checks that a given value is a valid postal code. + * + * @param string|array $check Value to check + * @param string $regex Regular expression to use + * @param string $country Country to use for formatting + * @return boolean Success + */ + public static function postal($check, $regex = null, $country = 'us') { + if (is_array($check)) { + extract(self::_defaults($check)); + } + + if (is_null($regex)) { + switch ($country) { + case 'uk': + $regex = '/\\A\\b[A-Z]{1,2}[0-9][A-Z0-9]? [0-9][ABD-HJLNP-UW-Z]{2}\\b\\z/i'; + break; + case 'ca': + $regex = '/\\A\\b[ABCEGHJKLMNPRSTVXY][0-9][A-Z] [0-9][A-Z][0-9]\\b\\z/i'; + break; + case 'it': + case 'de': + $regex = '/^[0-9]{5}$/i'; + break; + case 'be': + $regex = '/^[1-9]{1}[0-9]{3}$/i'; + break; + case 'us': + $regex = '/\\A\\b[0-9]{5}(?:-[0-9]{4})?\\b\\z/i'; + break; + } + } + if (empty($regex)) { + return self::_pass('postal', $check, $country); + } + return self::_check($check, $regex); + } + +/** + * Validate that a number is in specified range. + * if $lower and $upper are not set, will return true if + * $check is a legal finite on this platform + * + * @param string $check Value to check + * @param integer $lower Lower limit + * @param integer $upper Upper limit + * @return boolean Success + */ + public static function range($check, $lower = null, $upper = null) { + if (!is_numeric($check)) { + return false; + } + if (isset($lower) && isset($upper)) { + return ($check > $lower && $check < $upper); + } + return is_finite($check); + } + +/** + * Checks that a value is a valid Social Security Number. + * + * @param string|array $check Value to check + * @param string $regex Regular expression to use + * @param string $country Country + * @return boolean Success + */ + public static function ssn($check, $regex = null, $country = null) { + if (is_array($check)) { + extract(self::_defaults($check)); + } + + if (is_null($regex)) { + switch ($country) { + case 'dk': + $regex = '/\\A\\b[0-9]{6}-[0-9]{4}\\b\\z/i'; + break; + case 'nl': + $regex = '/\\A\\b[0-9]{9}\\b\\z/i'; + break; + case 'us': + $regex = '/\\A\\b[0-9]{3}-[0-9]{2}-[0-9]{4}\\b\\z/i'; + break; + } + } + if (empty($regex)) { + return self::_pass('ssn', $check, $country); + } + return self::_check($check, $regex); + } + +/** + * Checks that a value is a valid URL according to http://www.w3.org/Addressing/URL/url-spec.txt + * + * The regex checks for the following component parts: + * + * - a valid, optional, scheme + * - a valid ip address OR + * a valid domain name as defined by section 2.3.1 of http://www.ietf.org/rfc/rfc1035.txt + * with an optional port number + * - an optional valid path + * - an optional query string (get parameters) + * - an optional fragment (anchor tag) + * + * @param string $check Value to check + * @param boolean $strict Require URL to be prefixed by a valid scheme (one of http(s)/ftp(s)/file/news/gopher) + * @return boolean Success + */ + public static function url($check, $strict = false) { + self::_populateIp(); + $validChars = '([' . preg_quote('!"$&\'()*+,-.@_:;=~[]') . '\/0-9a-z\p{L}\p{N}]|(%[0-9a-f]{2}))'; + $regex = '/^(?:(?:https?|ftps?|sftp|file|news|gopher):\/\/)' . (!empty($strict) ? '' : '?') . + '(?:' . self::$_pattern['IPv4'] . '|\[' . self::$_pattern['IPv6'] . '\]|' . self::$_pattern['hostname'] . ')(?::[1-9][0-9]{0,4})?' . + '(?:\/?|\/' . $validChars . '*)?' . + '(?:\?' . $validChars . '*)?' . + '(?:#' . $validChars . '*)?$/iu'; + return self::_check($check, $regex); + } + +/** + * Checks if a value is in a given list. + * + * @param string $check Value to check + * @param array $list List to check against + * @param boolean $strict Defaults to true, set to false to disable strict type check + * @return boolean Success + */ + public static function inList($check, $list, $strict = true) { + return in_array($check, $list, $strict); + } + +/** + * Runs an user-defined validation. + * + * @param string|array $check value that will be validated in user-defined methods. + * @param object $object class that holds validation method + * @param string $method class method name for validation to run + * @param array $args arguments to send to method + * @return mixed user-defined class class method returns + */ + public static function userDefined($check, $object, $method, $args = null) { + return call_user_func_array(array($object, $method), array($check, $args)); + } + +/** + * Checks that a value is a valid uuid - http://tools.ietf.org/html/rfc4122 + * + * @param string $check Value to check + * @return boolean Success + */ + public static function uuid($check) { + $regex = '/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i'; + return self::_check($check, $regex); + } + +/** + * Attempts to pass unhandled Validation locales to a class starting with $classPrefix + * and ending with Validation. For example $classPrefix = 'nl', the class would be + * `NlValidation`. + * + * @param string $method The method to call on the other class. + * @param mixed $check The value to check or an array of parameters for the method to be called. + * @param string $classPrefix The prefix for the class to do the validation. + * @return mixed Return of Passed method, false on failure + */ + protected static function _pass($method, $check, $classPrefix) { + $className = ucwords($classPrefix) . 'Validation'; + if (!class_exists($className)) { + trigger_error(__d('cake_dev', 'Could not find %s class, unable to complete validation.', $className), E_USER_WARNING); + return false; + } + if (!method_exists($className, $method)) { + trigger_error(__d('cake_dev', 'Method %s does not exist on %s unable to complete validation.', $method, $className), E_USER_WARNING); + return false; + } + $check = (array)$check; + return call_user_func_array(array($className, $method), $check); + } + +/** + * Runs a regular expression match. + * + * @param string $check Value to check against the $regex expression + * @param string $regex Regular expression + * @return boolean Success of match + */ + protected static function _check($check, $regex) { + if (preg_match($regex, $check)) { + self::$errors[] = false; + return true; + } else { + self::$errors[] = true; + return false; + } + } + +/** + * Get the values to use when value sent to validation method is + * an array. + * + * @param array $params Parameters sent to validation method + * @return void + */ + protected static function _defaults($params) { + self::_reset(); + $defaults = array( + 'check' => null, + 'regex' => null, + 'country' => null, + 'deep' => false, + 'type' => null + ); + $params = array_merge($defaults, $params); + if ($params['country'] !== null) { + $params['country'] = mb_strtolower($params['country']); + } + return $params; + } + +/** + * Luhn algorithm + * + * @param string|array $check + * @param boolean $deep + * @return boolean Success + * @see http://en.wikipedia.org/wiki/Luhn_algorithm + */ + public static function luhn($check, $deep = false) { + if (is_array($check)) { + extract(self::_defaults($check)); + } + if ($deep !== true) { + return true; + } + if ($check == 0) { + return false; + } + $sum = 0; + $length = strlen($check); + + for ($position = 1 - ($length % 2); $position < $length; $position += 2) { + $sum += $check[$position]; + } + + for ($position = ($length % 2); $position < $length; $position += 2) { + $number = $check[$position] * 2; + $sum += ($number < 10) ? $number : $number - 9; + } + + return ($sum % 10 == 0); + } + +/** + * Checks the mime type of a file + * + * @param string|array $check + * @param array $mimeTypes to check for + * @return boolean Success + * @throws CakeException when mime type can not be determined. + */ + public static function mimeType($check, $mimeTypes = array()) { + if (is_array($check) && isset($check['tmp_name'])) { + $check = $check['tmp_name']; + } + + $File = new File($check); + $mime = $File->mime(); + + if ($mime === false) { + throw new CakeException(__d('cake_dev', 'Can not determine the mimetype.')); + } + return in_array($mime, $mimeTypes); + } + +/** + * Checking for upload errors + * + * @param string|array $check + * @retrun boolean + * @see http://www.php.net/manual/en/features.file-upload.errors.php + */ + public static function uploadError($check) { + if (is_array($check) && isset($check['error'])) { + $check = $check['error']; + } + + return $check === UPLOAD_ERR_OK; + } + +/** + * Lazily populate the IP address patterns used for validations + * + * @return void + */ + protected static function _populateIp() { + if (!isset(self::$_pattern['IPv6'])) { + $pattern = '((([0-9A-Fa-f]{1,4}:){7}(([0-9A-Fa-f]{1,4})|:))|(([0-9A-Fa-f]{1,4}:){6}'; + $pattern .= '(:|((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})'; + $pattern .= '|(:[0-9A-Fa-f]{1,4})))|(([0-9A-Fa-f]{1,4}:){5}((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})'; + $pattern .= '(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:)'; + $pattern .= '{4}(:[0-9A-Fa-f]{1,4}){0,1}((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2}))'; + $pattern .= '{3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:){3}(:[0-9A-Fa-f]{1,4}){0,2}'; + $pattern .= '((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|'; + $pattern .= '((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:){2}(:[0-9A-Fa-f]{1,4}){0,3}'; + $pattern .= '((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2}))'; + $pattern .= '{3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:)(:[0-9A-Fa-f]{1,4})'; + $pattern .= '{0,4}((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)'; + $pattern .= '|((:[0-9A-Fa-f]{1,4}){1,2})))|(:(:[0-9A-Fa-f]{1,4}){0,5}((:((25[0-5]|2[0-4]'; + $pattern .= '\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4})'; + $pattern .= '{1,2})))|(((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})))(%.+)?'; + + self::$_pattern['IPv6'] = $pattern; + } + if (!isset(self::$_pattern['IPv4'])) { + $pattern = '(?:(?:25[0-5]|2[0-4][0-9]|(?:(?:1[0-9])?|[1-9]?)[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|(?:(?:1[0-9])?|[1-9]?)[0-9])'; + self::$_pattern['IPv4'] = $pattern; + } + } + +/** + * Reset internal variables for another validation run. + * + * @return void + */ + protected static function _reset() { + self::$errors = array(); + } + +} diff --git a/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/Xml.php b/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/Xml.php new file mode 100644 index 0000000..f8662b2 --- /dev/null +++ b/poc/poc02-compiling-cake/src/vendor/cakephp-2.2.1-0-gcc44130/lib/Cake/Utility/Xml.php @@ -0,0 +1,370 @@ +<?php +/** + * XML handling for Cake. + * + * The methods in these classes enable the datasources that use XML to work. + * + * PHP 5 + * + * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) + * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * Redistributions of files must retain the above copyright notice. + * + * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://cakephp.org CakePHP(tm) Project + * @package Cake.Utility + * @since CakePHP v .0.10.3.1400 + * @license MIT License (http://www.opensource.org/licenses/mit-license.php) + */ + +/** + * XML handling for Cake. + * + * The methods in these classes enable the datasources that use XML to work. + * + * @package Cake.Utility + */ +class Xml { + +/** + * Initialize SimpleXMLElement or DOMDocument from a given XML string, file path, URL or array. + * + * ### Usage: + * + * Building XML from a string: + * + * `$xml = Xml::build('<example>text</example>');` + * + * Building XML from string (output DOMDocument): + * + * `$xml = Xml::build('<example>text</example>', array('return' => 'domdocument'));` + * + * Building XML from a file path: + * + * `$xml = Xml::build('/path/to/an/xml/file.xml');` + * + * Building from a remote URL: + * + * `$xml = Xml::build('http://example.com/example.xml');` + * + * Building from an array: + * + * {{{ + * $value = array( + * 'tags' => array( + * 'tag' => array( + * array( + * 'id' => '1', + * 'name' => 'defect' + * ), + * array( + * 'id' => '2', + * 'name' => 'enhancement' + * ) + * ) + * ) + * ); + * $xml = Xml::build($value); + * }}} + * + * When building XML from an array ensure that there is only one top level element. + * + * ### Options + * + * - `return` Can be 'simplexml' to return object of SimpleXMLElement or 'domdocument' to return DOMDocument. + * - `loadEntities` Defaults to false. Set to true to enable loading of `<!ENTITY` definitions. This + * is disabled by default for security reasons. + * - If using array as input, you can pass `options` from Xml::fromArray. + * + * @param string|array $input XML string, a path to a file, an URL or an array + * @param array $options The options to use + * @return SimpleXMLElement|DOMDocument SimpleXMLElement or DOMDocument + * @throws XmlException + */ + public static function build($input, $options = array()) { + if (!is_array($options)) { + $options = array('return' => (string)$options); + } + $defaults = array( + 'return' => 'simplexml', + 'loadEntities' => false, + ); + $options = array_merge($defaults, $options); + + if (is_array($input) || is_object($input)) { + return self::fromArray((array)$input, $options); + } elseif (strpos($input, '<') !== false) { + return self::_loadXml($input, $options); + } elseif (file_exists($input) || strpos($input, 'http://') === 0 || strpos($input, 'https://') === 0) { + $input = file_get_contents($input); + return self::_loadXml($input, $options); + } elseif (!is_string($input)) { + throw new XmlException(__d('cake_dev', 'Invalid input.')); + } + throw new XmlException(__d('cake_dev', 'XML cannot be read.')); + } + +/** + * Parse the input data and create either a SimpleXmlElement object or a DOMDocument. + * + * @param string $input The input to load. + * @param array $options The options to use. See Xml::build() + * @return SimpleXmlElement|DOMDocument. + */ + protected static function _loadXml($input, $options) { + $hasDisable = function_exists('libxml_disable_entity_loader'); + $internalErrors = libxml_use_internal_errors(true); + if ($hasDisable && !$options['loadEntities']) { + libxml_disable_entity_loader(true); + } + if ($options['return'] === 'simplexml' || $options['return'] === 'simplexmlelement') { + $xml = new SimpleXMLElement($input, LIBXML_NOCDATA); + } else { + $xml = new DOMDocument(); + $xml->loadXML($input); + } + if ($hasDisable && !$options['loadEntities']) { + libxml_disable_entity_loader(false); + } + libxml_use_internal_errors($internalErrors); + return $xml; + } + +/** + * Transform an array into a SimpleXMLElement + * + * ### Options + * + * - `format` If create childs ('tags') or attributes ('attribute'). + * - `version` Version of XML document. Default is 1.0. + * - `encoding` Encoding of XML document. If null remove from XML header. Default is the some of application. + * - `return` If return object of SimpleXMLElement ('simplexml') or DOMDocument ('domdocument'). Default is SimpleXMLElement. + * + * Using the following data: + * + * {{{ + * $value = array( + * 'root' => array( + * 'tag' => array( + * 'id' => 1, + * 'value' => 'defect', + * '@' => 'description' + * ) + * ) + * ); + * }}} + * + * Calling `Xml::fromArray($value, 'tags');` Will generate: + * + * `<root><tag><id>1</id><value>defect</value>description</tag></root>` + * + * And calling `Xml::fromArray($value, 'attribute');` Will generate: + * + * `<root><tag id="1" value="defect">description</tag></root>` + * + * @param array $input Array with data + * @param array $options The options to use + * @return SimpleXMLElement|DOMDocument SimpleXMLElement or DOMDocument + * @throws XmlException + */ + public static function fromArray($input, $options = array()) { + if (!is_array($input) || count($input) !== 1) { + throw new XmlException(__d('cake_dev', 'Invalid input.')); + } + $key = key($input); + if (is_integer($key)) { + throw new XmlException(__d('cake_dev', 'The key of input must be alphanumeric')); + } + + if (!is_array($options)) { + $options = array('format' => (string)$options); + } + $defaults = array( + 'format' => 'tags', + 'version' => '1.0', + 'encoding' => Configure::read('App.encoding'), + 'return' => 'simplexml' + ); + $options = array_merge($defaults, $options); + + $dom = new DOMDocument($options['version'], $options['encoding']); + self::_fromArray($dom, $dom, $input, $options['format']); + + $options['return'] = strtolower($options['return']); + if ($options['return'] === 'simplexml' || $options['return'] === 'simplexmlelement') { + return new SimpleXMLElement($dom->saveXML()); + } + return $dom; + } + +/** + * Recursive method to create childs from array + * + * @param DOMDocument $dom Handler to DOMDocument + * @param DOMElement $node Handler to DOMElement (child) + * @param array $data Array of data to append to the $node. + * @param string $format Either 'attribute' or 'tags'. This determines where nested keys go. + * @return void + * @throws XmlException + */ + protected static function _fromArray($dom, $node, &$data, $format) { + if (empty($data) || !is_array($data)) { + return; + } + foreach ($data as $key => $value) { + if (is_string($key)) { + if (!is_array($value)) { + if (is_bool($value)) { + $value = (int)$value; + } elseif ($value === null) { + $value = ''; + } + $isNamespace = strpos($key, 'xmlns:'); + if ($isNamespace !== false) { + $node->setAttributeNS('http://www.w3.org/2000/xmlns/', $key, $value); + continue; + } + if ($key[0] !== '@' && $format === 'tags') { + $child = null; + if (!is_numeric($value)) { + // Escape special characters + // http://www.w3.org/TR/REC-xml/#syntax + // https://bugs.php.net/bug.php?id=36795 + $child = $dom->createElement($key, ''); + $child->appendChild(new DOMText($value)); + } else { + $child = $dom->createElement($key, $value); + } + $node->appendChild($child); + } else { + if ($key[0] === '@') { + $key = substr($key, 1); + } + $attribute = $dom->createAttribute($key); + $attribute->appendChild($dom->createTextNode($value)); + $node->appendChild($attribute); + } + } else { + if ($key[0] === '@') { + throw new XmlException(__d('cake_dev', 'Invalid array')); + } + if (is_numeric(implode('', array_keys($value)))) { // List + foreach ($value as $item) { + $itemData = compact('dom', 'node', 'key', 'format'); + $itemData['value'] = $item; + self::_createChild($itemData); + } + } else { // Struct + self::_createChild(compact('dom', 'node', 'key', 'value', 'format')); + } + } + } else { + throw new XmlException(__d('cake_dev', 'Invalid array')); + } + } + } + +/** + * Helper to _fromArray(). It will create childs of arrays + * + * @param array $data Array with informations to create childs + * @return void + */ + protected static function _createChild($data) { + extract($data); + $childNS = $childValue = null; + if (is_array($value)) { + if (isset($value['@'])) { + $childValue = (string)$value['@']; + unset($value['@']); + } + if (isset($value['xmlns:'])) { + $childNS = $value['xmlns:']; + unset($value['xmlns:']); + } + } elseif (!empty($value) || $value === 0) { + $childValue = (string)$value; + } + + if ($childValue) { + $child = $dom->createElement($key, $childValue); + } else { + $child = $dom->createElement($key); + } + if ($childNS) { + $child->setAttribute('xmlns', $childNS); + } + + self::_fromArray($dom, $child, $value, $format); + $node->appendChild($child); + } + +/** + * Returns this XML structure as a array. + * + * @param SimpleXMLElement|DOMDocument|DOMNode $obj SimpleXMLElement, DOMDocument or DOMNode instance + * @return array Array representation of the XML structure. + * @throws XmlException + */ + public static function toArray($obj) { + if ($obj instanceof DOMNode) { + $obj = simplexml_import_dom($obj); + } + if (!($obj instanceof SimpleXMLElement)) { + throw new XmlException(__d('cake_dev', 'The input is not instance of SimpleXMLElement, DOMDocument or DOMNode.')); + } + $result = array(); + $namespaces = array_merge(array('' => ''), $obj->getNamespaces(true)); + self::_toArray($obj, $result, '', array_keys($namespaces)); + return $result; + } + +/** + * Recursive method to toArray + * + * @param SimpleXMLElement $xml SimpleXMLElement object + * @param array $parentData Parent array with data + * @param string $ns Namespace of current child + * @param array $namespaces List of namespaces in XML + * @return void + */ + protected static function _toArray($xml, &$parentData, $ns, $namespaces) { + $data = array(); + + foreach ($namespaces as $namespace) { + foreach ($xml->attributes($namespace, true) as $key => $value) { + if (!empty($namespace)) { + $key = $namespace . ':' . $key; + } + $data['@' . $key] = (string)$value; + } + + foreach ($xml->children($namespace, true) as $child) { + self::_toArray($child, $data, $namespace, $namespaces); + } + } + + $asString = trim((string)$xml); + if (empty($data)) { + $data = $asString; + } elseif (!empty($asString)) { + $data['@'] = $asString; + } + + if (!empty($ns)) { + $ns .= ':'; + } + $name = $ns . $xml->getName(); + if (isset($parentData[$name])) { + if (!is_array($parentData[$name]) || !isset($parentData[$name][0])) { + $parentData[$name] = array($parentData[$name]); + } + $parentData[$name][] = $data; + } else { + $parentData[$name] = $data; + } + } + +} |