diff --git a/k2shop/usr/k2shop/libs/browser/Browser.php b/k2shop/usr/k2shop/libs/browser/Browser.php
new file mode 100644
index 0000000..2acf548
--- /dev/null
+++ b/k2shop/usr/k2shop/libs/browser/Browser.php
@@ -0,0 +1,1732 @@
+getBrowser() == Browser::BROWSER_FIREFOX && $browser->getVersion() >= 2 ) {
+ * echo 'You have FireFox version 2 or greater';
+ * }
+ *
+ * User Agents Sampled from: http://www.useragentstring.com/
+ *
+ * This implementation is based on the original work from Gary White
+ * http://apptools.com/phptools/browser/
+ *
+ */
+class Browser
+{
+ private $_agent = '';
+ private $_browser_name = '';
+ private $_version = '';
+ private $_platform = '';
+ private $_os = '';
+ private $_is_aol = false;
+ private $_is_mobile = false;
+ private $_is_tablet = false;
+ private $_is_robot = false;
+ private $_is_facebook = false;
+ private $_aol_version = '';
+
+ const BROWSER_UNKNOWN = 'unknown';
+ const VERSION_UNKNOWN = 'unknown';
+
+ const BROWSER_OPERA = 'Opera'; // http://www.opera.com/
+ const BROWSER_OPERA_MINI = 'Opera Mini'; // http://www.opera.com/mini/
+ const BROWSER_WEBTV = 'WebTV'; // http://www.webtv.net/pc/
+ const BROWSER_EDGE = 'Edge'; // https://www.microsoft.com/edge
+ const BROWSER_IE = 'Internet Explorer'; // http://www.microsoft.com/ie/
+ const BROWSER_POCKET_IE = 'Pocket Internet Explorer'; // http://en.wikipedia.org/wiki/Internet_Explorer_Mobile
+ const BROWSER_KONQUEROR = 'Konqueror'; // http://www.konqueror.org/
+ const BROWSER_ICAB = 'iCab'; // http://www.icab.de/
+ const BROWSER_OMNIWEB = 'OmniWeb'; // http://www.omnigroup.com/applications/omniweb/
+ const BROWSER_FIREBIRD = 'Firebird'; // http://www.ibphoenix.com/
+ const BROWSER_FIREFOX = 'Firefox'; // http://www.mozilla.com/en-US/firefox/firefox.html
+ const BROWSER_ICEWEASEL = 'Iceweasel'; // http://www.geticeweasel.org/
+ const BROWSER_SHIRETOKO = 'Shiretoko'; // http://wiki.mozilla.org/Projects/shiretoko
+ const BROWSER_MOZILLA = 'Mozilla'; // http://www.mozilla.com/en-US/
+ const BROWSER_AMAYA = 'Amaya'; // http://www.w3.org/Amaya/
+ const BROWSER_LYNX = 'Lynx'; // http://en.wikipedia.org/wiki/Lynx
+ const BROWSER_SAFARI = 'Safari'; // http://apple.com
+ const BROWSER_IPHONE = 'iPhone'; // http://apple.com
+ const BROWSER_IPOD = 'iPod'; // http://apple.com
+ const BROWSER_IPAD = 'iPad'; // http://apple.com
+ const BROWSER_CHROME = 'Chrome'; // http://www.google.com/chrome
+ const BROWSER_ANDROID = 'Android'; // http://www.android.com/
+ const BROWSER_GOOGLEBOT = 'GoogleBot'; // http://en.wikipedia.org/wiki/Googlebot
+
+ const BROWSER_YANDEXBOT = 'YandexBot'; // http://yandex.com/bots
+ const BROWSER_YANDEXIMAGERESIZER_BOT = 'YandexImageResizer'; // http://yandex.com/bots
+ const BROWSER_YANDEXIMAGES_BOT = 'YandexImages'; // http://yandex.com/bots
+ const BROWSER_YANDEXVIDEO_BOT = 'YandexVideo'; // http://yandex.com/bots
+ const BROWSER_YANDEXMEDIA_BOT = 'YandexMedia'; // http://yandex.com/bots
+ const BROWSER_YANDEXBLOGS_BOT = 'YandexBlogs'; // http://yandex.com/bots
+ const BROWSER_YANDEXFAVICONS_BOT = 'YandexFavicons'; // http://yandex.com/bots
+ const BROWSER_YANDEXWEBMASTER_BOT = 'YandexWebmaster'; // http://yandex.com/bots
+ const BROWSER_YANDEXDIRECT_BOT = 'YandexDirect'; // http://yandex.com/bots
+ const BROWSER_YANDEXMETRIKA_BOT = 'YandexMetrika'; // http://yandex.com/bots
+ const BROWSER_YANDEXNEWS_BOT = 'YandexNews'; // http://yandex.com/bots
+ const BROWSER_YANDEXCATALOG_BOT = 'YandexCatalog'; // http://yandex.com/bots
+
+ const BROWSER_SLURP = 'Yahoo! Slurp'; // http://en.wikipedia.org/wiki/Yahoo!_Slurp
+ const BROWSER_W3CVALIDATOR = 'W3C Validator'; // http://validator.w3.org/
+ const BROWSER_BLACKBERRY = 'BlackBerry'; // http://www.blackberry.com/
+ const BROWSER_ICECAT = 'IceCat'; // http://en.wikipedia.org/wiki/GNU_IceCat
+ const BROWSER_NOKIA_S60 = 'Nokia S60 OSS Browser'; // http://en.wikipedia.org/wiki/Web_Browser_for_S60
+ const BROWSER_NOKIA = 'Nokia Browser'; // * all other WAP-based browsers on the Nokia Platform
+ const BROWSER_MSN = 'MSN Browser'; // http://explorer.msn.com/
+ const BROWSER_MSNBOT = 'MSN Bot'; // http://search.msn.com/msnbot.htm
+ const BROWSER_BINGBOT = 'Bing Bot'; // http://en.wikipedia.org/wiki/Bingbot
+ const BROWSER_VIVALDI = 'Vivalidi'; // https://vivaldi.com/
+ const BROWSER_YANDEX = 'Yandex'; // https://browser.yandex.ua/
+
+ const BROWSER_NETSCAPE_NAVIGATOR = 'Netscape Navigator'; // http://browser.netscape.com/ (DEPRECATED)
+ const BROWSER_GALEON = 'Galeon'; // http://galeon.sourceforge.net/ (DEPRECATED)
+ const BROWSER_NETPOSITIVE = 'NetPositive'; // http://en.wikipedia.org/wiki/NetPositive (DEPRECATED)
+ const BROWSER_PHOENIX = 'Phoenix'; // http://en.wikipedia.org/wiki/History_of_Mozilla_Firefox (DEPRECATED)
+ const BROWSER_PLAYSTATION = "PlayStation";
+ const BROWSER_SAMSUNG = "SamsungBrowser";
+ const BROWSER_SILK = "Silk";
+ const BROWSER_I_FRAME = "Iframely";
+ const BROWSER_COCOA = "CocoaRestClient";
+
+ const PLATFORM_UNKNOWN = 'unknown';
+ const PLATFORM_WINDOWS = 'Windows';
+ const PLATFORM_WINDOWS_CE = 'Windows CE';
+ const PLATFORM_APPLE = 'Apple';
+ const PLATFORM_LINUX = 'Linux';
+ const PLATFORM_OS2 = 'OS/2';
+ const PLATFORM_BEOS = 'BeOS';
+ const PLATFORM_IPHONE = 'iPhone';
+ const PLATFORM_IPOD = 'iPod';
+ const PLATFORM_IPAD = 'iPad';
+ const PLATFORM_BLACKBERRY = 'BlackBerry';
+ const PLATFORM_NOKIA = 'Nokia';
+ const PLATFORM_FREEBSD = 'FreeBSD';
+ const PLATFORM_OPENBSD = 'OpenBSD';
+ const PLATFORM_NETBSD = 'NetBSD';
+ const PLATFORM_SUNOS = 'SunOS';
+ const PLATFORM_OPENSOLARIS = 'OpenSolaris';
+ const PLATFORM_ANDROID = 'Android';
+ const PLATFORM_PLAYSTATION = "Sony PlayStation";
+ const PLATFORM_ROKU = "Roku";
+ const PLATFORM_APPLE_TV = "Apple TV";
+ const PLATFORM_TERMINAL = "Terminal";
+ const PLATFORM_FIRE_OS = "Fire OS";
+ const PLATFORM_SMART_TV = "SMART-TV";
+ const PLATFORM_CHROME_OS = "Chrome OS";
+ const PLATFORM_JAVA_ANDROID = "Java/Android";
+ const PLATFORM_POSTMAN = "Postman";
+ const PLATFORM_I_FRAME = "Iframely";
+
+ const OPERATING_SYSTEM_UNKNOWN = 'unknown';
+
+ /**
+ * Class constructor
+ */
+ public function __construct($userAgent = "")
+ {
+ $this->reset();
+ if ($userAgent != "") {
+ $this->setUserAgent($userAgent);
+ } else {
+ $this->determine();
+ }
+ }
+
+ /**
+ * Reset all properties
+ */
+ public function reset()
+ {
+ $this->_agent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : "";
+ $this->_browser_name = self::BROWSER_UNKNOWN;
+ $this->_version = self::VERSION_UNKNOWN;
+ $this->_platform = self::PLATFORM_UNKNOWN;
+ $this->_os = self::OPERATING_SYSTEM_UNKNOWN;
+ $this->_is_aol = false;
+ $this->_is_mobile = false;
+ $this->_is_tablet = false;
+ $this->_is_robot = false;
+ $this->_is_facebook = false;
+ $this->_aol_version = self::VERSION_UNKNOWN;
+ }
+
+ /**
+ * Check to see if the specific browser is valid
+ * @param string $browserName
+ * @return bool True if the browser is the specified browser
+ */
+ function isBrowser($browserName)
+ {
+ return (0 == strcasecmp($this->_browser_name, trim($browserName)));
+ }
+
+ /**
+ * The name of the browser. All return types are from the class contants
+ * @return string Name of the browser
+ */
+ public function getBrowser()
+ {
+ return $this->_browser_name;
+ }
+
+ /**
+ * Set the name of the browser
+ * @param $browser string The name of the Browser
+ */
+ public function setBrowser($browser)
+ {
+ $this->_browser_name = $browser;
+ }
+
+ /**
+ * The name of the platform. All return types are from the class contants
+ * @return string Name of the browser
+ */
+ public function getPlatform()
+ {
+ return $this->_platform;
+ }
+
+ /**
+ * Set the name of the platform
+ * @param string $platform The name of the Platform
+ */
+ public function setPlatform($platform)
+ {
+ $this->_platform = $platform;
+ }
+
+ /**
+ * The version of the browser.
+ * @return string Version of the browser (will only contain alpha-numeric characters and a period)
+ */
+ public function getVersion()
+ {
+ return $this->_version;
+ }
+
+ /**
+ * Set the version of the browser
+ * @param string $version The version of the Browser
+ */
+ public function setVersion($version)
+ {
+ $this->_version = preg_replace('/[^0-9,.,a-z,A-Z-]/', '', $version);
+ }
+
+ /**
+ * The version of AOL.
+ * @return string Version of AOL (will only contain alpha-numeric characters and a period)
+ */
+ public function getAolVersion()
+ {
+ return $this->_aol_version;
+ }
+
+ /**
+ * Set the version of AOL
+ * @param string $version The version of AOL
+ */
+ public function setAolVersion($version)
+ {
+ $this->_aol_version = preg_replace('/[^0-9,.,a-z,A-Z]/', '', $version);
+ }
+
+ /**
+ * Is the browser from AOL?
+ * @return boolean True if the browser is from AOL otherwise false
+ */
+ public function isAol()
+ {
+ return $this->_is_aol;
+ }
+
+ /**
+ * Is the browser from a mobile device?
+ * @return boolean True if the browser is from a mobile device otherwise false
+ */
+ public function isMobile()
+ {
+ return $this->_is_mobile;
+ }
+
+ /**
+ * Is the browser from a tablet device?
+ * @return boolean True if the browser is from a tablet device otherwise false
+ */
+ public function isTablet()
+ {
+ return $this->_is_tablet;
+ }
+
+ /**
+ * Is the browser from a robot (ex Slurp,GoogleBot)?
+ * @return boolean True if the browser is from a robot otherwise false
+ */
+ public function isRobot()
+ {
+ return $this->_is_robot;
+ }
+
+ /**
+ * Is the browser from facebook?
+ * @return boolean True if the browser is from facebook otherwise false
+ */
+ public function isFacebook()
+ {
+ return $this->_is_facebook;
+ }
+
+ /**
+ * Set the browser to be from AOL
+ * @param $isAol
+ */
+ public function setAol($isAol)
+ {
+ $this->_is_aol = $isAol;
+ }
+
+ /**
+ * Set the Browser to be mobile
+ * @param boolean $value is the browser a mobile browser or not
+ */
+ protected function setMobile($value = true)
+ {
+ $this->_is_mobile = $value;
+ }
+
+ /**
+ * Set the Browser to be tablet
+ * @param boolean $value is the browser a tablet browser or not
+ */
+ protected function setTablet($value = true)
+ {
+ $this->_is_tablet = $value;
+ }
+
+ /**
+ * Set the Browser to be a robot
+ * @param boolean $value is the browser a robot or not
+ */
+ protected function setRobot($value = true)
+ {
+ $this->_is_robot = $value;
+ }
+
+ /**
+ * Set the Browser to be a Facebook request
+ * @param boolean $value is the browser a robot or not
+ */
+ protected function setFacebook($value = true)
+ {
+ $this->_is_facebook = $value;
+ }
+
+ /**
+ * Get the user agent value in use to determine the browser
+ * @return string The user agent from the HTTP header
+ */
+ public function getUserAgent()
+ {
+ return $this->_agent;
+ }
+
+ /**
+ * Set the user agent value (the construction will use the HTTP header value - this will overwrite it)
+ * @param string $agent_string The value for the User Agent
+ */
+ public function setUserAgent($agent_string)
+ {
+ $this->reset();
+ $this->_agent = $agent_string;
+ $this->determine();
+ }
+
+ /**
+ * Used to determine if the browser is actually "chromeframe"
+ * @since 1.7
+ * @return boolean True if the browser is using chromeframe
+ */
+ public function isChromeFrame()
+ {
+ return (strpos($this->_agent, "chromeframe") !== false);
+ }
+
+ /**
+ * Returns a formatted string with a summary of the details of the browser.
+ * @return string formatted string with a summary of the browser
+ */
+ public function __toString()
+ {
+ return "Browser Name: {$this->getBrowser()}
\n" .
+ "Browser Version: {$this->getVersion()}
\n" .
+ "Browser User Agent String: {$this->getUserAgent()}
\n" .
+ "Platform: {$this->getPlatform()}
";
+ }
+
+ /**
+ * Protected routine to calculate and determine what the browser is in use (including platform)
+ */
+ protected function determine()
+ {
+ $this->checkPlatform();
+ $this->checkBrowsers();
+ $this->checkForAol();
+ }
+
+ /**
+ * Protected routine to determine the browser type
+ * @return boolean True if the browser was detected otherwise false
+ */
+ protected function checkBrowsers()
+ {
+ return (
+ // well-known, well-used
+ // Special Notes:
+ // (1) Opera must be checked before FireFox due to the odd
+ // user agents used in some older versions of Opera
+ // (2) WebTV is strapped onto Internet Explorer so we must
+ // check for WebTV before IE
+ // (3) (deprecated) Galeon is based on Firefox and needs to be
+ // tested before Firefox is tested
+ // (4) OmniWeb is based on Safari so OmniWeb check must occur
+ // before Safari
+ // (5) Netscape 9+ is based on Firefox so Netscape checks
+ // before FireFox are necessary
+ // (6) Vivalid is UA contains both Firefox and Chrome so Vivalid checks
+ // before Firefox and Chrome
+ $this->checkBrowserWebTv() ||
+ $this->checkBrowserEdge() ||
+ $this->checkBrowserInternetExplorer() ||
+ $this->checkBrowserOpera() ||
+ $this->checkBrowserGaleon() ||
+ $this->checkBrowserNetscapeNavigator9Plus() ||
+ $this->checkBrowserVivaldi() ||
+ $this->checkBrowserYandex() ||
+ $this->checkBrowserFirefox() ||
+ $this->checkBrowserChrome() ||
+ $this->checkBrowserOmniWeb() ||
+
+ // common mobile
+ $this->checkBrowserAndroid() ||
+ $this->checkBrowseriPad() ||
+ $this->checkBrowseriPod() ||
+ $this->checkBrowseriPhone() ||
+ $this->checkBrowserBlackBerry() ||
+ $this->checkBrowserNokia() ||
+
+ // common bots
+ $this->checkBrowserGoogleBot() ||
+ $this->checkBrowserMSNBot() ||
+ $this->checkBrowserBingBot() ||
+ $this->checkBrowserSlurp() ||
+
+ // Yandex bots
+ $this->checkBrowserYandexBot() ||
+ $this->checkBrowserYandexImageResizerBot() ||
+ $this->checkBrowserYandexBlogsBot() ||
+ $this->checkBrowserYandexCatalogBot() ||
+ $this->checkBrowserYandexDirectBot() ||
+ $this->checkBrowserYandexFaviconsBot() ||
+ $this->checkBrowserYandexImagesBot() ||
+ $this->checkBrowserYandexMediaBot() ||
+ $this->checkBrowserYandexMetrikaBot() ||
+ $this->checkBrowserYandexNewsBot() ||
+ $this->checkBrowserYandexVideoBot() ||
+ $this->checkBrowserYandexWebmasterBot() ||
+
+ // check for facebook external hit when loading URL
+ $this->checkFacebookExternalHit() ||
+
+ // WebKit base check (post mobile and others)
+ $this->checkBrowserSamsung() ||
+ $this->checkBrowserSilk() ||
+ $this->checkBrowserSafari() ||
+
+ // everyone else
+ $this->checkBrowserNetPositive() ||
+ $this->checkBrowserFirebird() ||
+ $this->checkBrowserKonqueror() ||
+ $this->checkBrowserIcab() ||
+ $this->checkBrowserPhoenix() ||
+ $this->checkBrowserAmaya() ||
+ $this->checkBrowserLynx() ||
+ $this->checkBrowserShiretoko() ||
+ $this->checkBrowserIceCat() ||
+ $this->checkBrowserIceweasel() ||
+ $this->checkBrowserW3CValidator() ||
+ $this->checkBrowserPlayStation() ||
+ $this->checkBrowserIframely() ||
+ $this->checkBrowserCocoa() ||
+ $this->checkBrowserMozilla() /* Mozilla is such an open standard that you must check it last */
+
+
+ );
+ }
+
+ /**
+ * Determine if the user is using a BlackBerry (last updated 1.7)
+ * @return boolean True if the browser is the BlackBerry browser otherwise false
+ */
+ protected function checkBrowserBlackBerry()
+ {
+ if (stripos($this->_agent, 'blackberry') !== false) {
+ $aresult = explode("/", stristr($this->_agent, "BlackBerry"));
+ if (isset($aresult[1])) {
+ $aversion = explode(' ', $aresult[1]);
+ $this->setVersion($aversion[0]);
+ $this->_browser_name = self::BROWSER_BLACKBERRY;
+ $this->setMobile(true);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the user is using an AOL User Agent (last updated 1.7)
+ * @return boolean True if the browser is from AOL otherwise false
+ */
+ protected function checkForAol()
+ {
+ $this->setAol(false);
+ $this->setAolVersion(self::VERSION_UNKNOWN);
+
+ if (stripos($this->_agent, 'aol') !== false) {
+ $aversion = explode(' ', stristr($this->_agent, 'AOL'));
+ if (isset($aversion[1])) {
+ $this->setAol(true);
+ $this->setAolVersion(preg_replace('/[^0-9\.a-z]/i', '', $aversion[1]));
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is the GoogleBot or not (last updated 1.7)
+ * @return boolean True if the browser is the GoogletBot otherwise false
+ */
+ protected function checkBrowserGoogleBot()
+ {
+ if (stripos($this->_agent, 'googlebot') !== false) {
+ $aresult = explode('/', stristr($this->_agent, 'googlebot'));
+ if (isset($aresult[1])) {
+ $aversion = explode(' ', $aresult[1]);
+ $this->setVersion(str_replace(';', '', $aversion[0]));
+ $this->_browser_name = self::BROWSER_GOOGLEBOT;
+ $this->setRobot(true);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is the YandexBot or not
+ * @return boolean True if the browser is the YandexBot otherwise false
+ */
+ protected function checkBrowserYandexBot()
+ {
+ if (stripos($this->_agent, 'YandexBot') !== false) {
+ $aresult = explode('/', stristr($this->_agent, 'YandexBot'));
+ if (isset($aresult[1])) {
+ $aversion = explode(' ', $aresult[1]);
+ $this->setVersion(str_replace(';', '', $aversion[0]));
+ $this->_browser_name = self::BROWSER_YANDEXBOT;
+ $this->setRobot(true);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is the YandexImageResizer or not
+ * @return boolean True if the browser is the YandexImageResizer otherwise false
+ */
+ protected function checkBrowserYandexImageResizerBot()
+ {
+ if (stripos($this->_agent, 'YandexImageResizer') !== false) {
+ $aresult = explode('/', stristr($this->_agent, 'YandexImageResizer'));
+ if (isset($aresult[1])) {
+ $aversion = explode(' ', $aresult[1]);
+ $this->setVersion(str_replace(';', '', $aversion[0]));
+ $this->_browser_name = self::BROWSER_YANDEXIMAGERESIZER_BOT;
+ $this->setRobot(true);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is the YandexCatalog or not
+ * @return boolean True if the browser is the YandexCatalog otherwise false
+ */
+ protected function checkBrowserYandexCatalogBot()
+ {
+ if (stripos($this->_agent, 'YandexCatalog') !== false) {
+ $aresult = explode('/', stristr($this->_agent, 'YandexCatalog'));
+ if (isset($aresult[1])) {
+ $aversion = explode(' ', $aresult[1]);
+ $this->setVersion(str_replace(';', '', $aversion[0]));
+ $this->_browser_name = self::BROWSER_YANDEXCATALOG_BOT;
+ $this->setRobot(true);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is the YandexNews or not
+ * @return boolean True if the browser is the YandexNews otherwise false
+ */
+ protected function checkBrowserYandexNewsBot()
+ {
+ if (stripos($this->_agent, 'YandexNews') !== false) {
+ $aresult = explode('/', stristr($this->_agent, 'YandexNews'));
+ if (isset($aresult[1])) {
+ $aversion = explode(' ', $aresult[1]);
+ $this->setVersion(str_replace(';', '', $aversion[0]));
+ $this->_browser_name = self::BROWSER_YANDEXNEWS_BOT;
+ $this->setRobot(true);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is the YandexMetrika or not
+ * @return boolean True if the browser is the YandexMetrika otherwise false
+ */
+ protected function checkBrowserYandexMetrikaBot()
+ {
+ if (stripos($this->_agent, 'YandexMetrika') !== false) {
+ $aresult = explode('/', stristr($this->_agent, 'YandexMetrika'));
+ if (isset($aresult[1])) {
+ $aversion = explode(' ', $aresult[1]);
+ $this->setVersion(str_replace(';', '', $aversion[0]));
+ $this->_browser_name = self::BROWSER_YANDEXMETRIKA_BOT;
+ $this->setRobot(true);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is the YandexDirect or not
+ * @return boolean True if the browser is the YandexDirect otherwise false
+ */
+ protected function checkBrowserYandexDirectBot()
+ {
+ if (stripos($this->_agent, 'YandexDirect') !== false) {
+ $aresult = explode('/', stristr($this->_agent, 'YandexDirect'));
+ if (isset($aresult[1])) {
+ $aversion = explode(' ', $aresult[1]);
+ $this->setVersion(str_replace(';', '', $aversion[0]));
+ $this->_browser_name = self::BROWSER_YANDEXDIRECT_BOT;
+ $this->setRobot(true);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is the YandexWebmaster or not
+ * @return boolean True if the browser is the YandexWebmaster otherwise false
+ */
+ protected function checkBrowserYandexWebmasterBot()
+ {
+ if (stripos($this->_agent, 'YandexWebmaster') !== false) {
+ $aresult = explode('/', stristr($this->_agent, 'YandexWebmaster'));
+ if (isset($aresult[1])) {
+ $aversion = explode(' ', $aresult[1]);
+ $this->setVersion(str_replace(';', '', $aversion[0]));
+ $this->_browser_name = self::BROWSER_YANDEXWEBMASTER_BOT;
+ $this->setRobot(true);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is the YandexFavicons or not
+ * @return boolean True if the browser is the YandexFavicons otherwise false
+ */
+ protected function checkBrowserYandexFaviconsBot()
+ {
+ if (stripos($this->_agent, 'YandexFavicons') !== false) {
+ $aresult = explode('/', stristr($this->_agent, 'YandexFavicons'));
+ if (isset($aresult[1])) {
+ $aversion = explode(' ', $aresult[1]);
+ $this->setVersion(str_replace(';', '', $aversion[0]));
+ $this->_browser_name = self::BROWSER_YANDEXFAVICONS_BOT;
+ $this->setRobot(true);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is the YandexBlogs or not
+ * @return boolean True if the browser is the YandexBlogs otherwise false
+ */
+ protected function checkBrowserYandexBlogsBot()
+ {
+ if (stripos($this->_agent, 'YandexBlogs') !== false) {
+ $aresult = explode('/', stristr($this->_agent, 'YandexBlogs'));
+ if (isset($aresult[1])) {
+ $aversion = explode(' ', $aresult[1]);
+ $this->setVersion(str_replace(';', '', $aversion[0]));
+ $this->_browser_name = self::BROWSER_YANDEXBLOGS_BOT;
+ $this->setRobot(true);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is the YandexMedia or not
+ * @return boolean True if the browser is the YandexMedia otherwise false
+ */
+ protected function checkBrowserYandexMediaBot()
+ {
+ if (stripos($this->_agent, 'YandexMedia') !== false) {
+ $aresult = explode('/', stristr($this->_agent, 'YandexMedia'));
+ if (isset($aresult[1])) {
+ $aversion = explode(' ', $aresult[1]);
+ $this->setVersion(str_replace(';', '', $aversion[0]));
+ $this->_browser_name = self::BROWSER_YANDEXMEDIA_BOT;
+ $this->setRobot(true);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is the YandexVideo or not
+ * @return boolean True if the browser is the YandexVideo otherwise false
+ */
+ protected function checkBrowserYandexVideoBot()
+ {
+ if (stripos($this->_agent, 'YandexVideo') !== false) {
+ $aresult = explode('/', stristr($this->_agent, 'YandexVideo'));
+ if (isset($aresult[1])) {
+ $aversion = explode(' ', $aresult[1]);
+ $this->setVersion(str_replace(';', '', $aversion[0]));
+ $this->_browser_name = self::BROWSER_YANDEXVIDEO_BOT;
+ $this->setRobot(true);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is the YandexImages or not
+ * @return boolean True if the browser is the YandexImages otherwise false
+ */
+ protected function checkBrowserYandexImagesBot()
+ {
+ if (stripos($this->_agent, 'YandexImages') !== false) {
+ $aresult = explode('/', stristr($this->_agent, 'YandexImages'));
+ if (isset($aresult[1])) {
+ $aversion = explode(' ', $aresult[1]);
+ $this->setVersion(str_replace(';', '', $aversion[0]));
+ $this->_browser_name = self::BROWSER_YANDEXIMAGES_BOT;
+ $this->setRobot(true);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is the MSNBot or not (last updated 1.9)
+ * @return boolean True if the browser is the MSNBot otherwise false
+ */
+ protected function checkBrowserMSNBot()
+ {
+ if (stripos($this->_agent, "msnbot") !== false) {
+ $aresult = explode("/", stristr($this->_agent, "msnbot"));
+ if (isset($aresult[1])) {
+ $aversion = explode(" ", $aresult[1]);
+ $this->setVersion(str_replace(";", "", $aversion[0]));
+ $this->_browser_name = self::BROWSER_MSNBOT;
+ $this->setRobot(true);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is the BingBot or not (last updated 1.9)
+ * @return boolean True if the browser is the BingBot otherwise false
+ */
+ protected function checkBrowserBingBot()
+ {
+ if (stripos($this->_agent, "bingbot") !== false) {
+ $aresult = explode("/", stristr($this->_agent, "bingbot"));
+ if (isset($aresult[1])) {
+ $aversion = explode(" ", $aresult[1]);
+ $this->setVersion(str_replace(";", "", $aversion[0]));
+ $this->_browser_name = self::BROWSER_BINGBOT;
+ $this->setRobot(true);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is the W3C Validator or not (last updated 1.7)
+ * @return boolean True if the browser is the W3C Validator otherwise false
+ */
+ protected function checkBrowserW3CValidator()
+ {
+ if (stripos($this->_agent, 'W3C-checklink') !== false) {
+ $aresult = explode('/', stristr($this->_agent, 'W3C-checklink'));
+ if (isset($aresult[1])) {
+ $aversion = explode(' ', $aresult[1]);
+ $this->setVersion($aversion[0]);
+ $this->_browser_name = self::BROWSER_W3CVALIDATOR;
+ return true;
+ }
+ } else if (stripos($this->_agent, 'W3C_Validator') !== false) {
+ // Some of the Validator versions do not delineate w/ a slash - add it back in
+ $ua = str_replace("W3C_Validator ", "W3C_Validator/", $this->_agent);
+ $aresult = explode('/', stristr($ua, 'W3C_Validator'));
+ if (isset($aresult[1])) {
+ $aversion = explode(' ', $aresult[1]);
+ $this->setVersion($aversion[0]);
+ $this->_browser_name = self::BROWSER_W3CVALIDATOR;
+ return true;
+ }
+ } else if (stripos($this->_agent, 'W3C-mobileOK') !== false) {
+ $this->_browser_name = self::BROWSER_W3CVALIDATOR;
+ $this->setMobile(true);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is the Yahoo! Slurp Robot or not (last updated 1.7)
+ * @return boolean True if the browser is the Yahoo! Slurp Robot otherwise false
+ */
+ protected function checkBrowserSlurp()
+ {
+ if (stripos($this->_agent, 'slurp') !== false) {
+ $aresult = explode('/', stristr($this->_agent, 'Slurp'));
+ if (isset($aresult[1])) {
+ $aversion = explode(' ', $aresult[1]);
+ $this->setVersion($aversion[0]);
+ $this->_browser_name = self::BROWSER_SLURP;
+ $this->setRobot(true);
+ $this->setMobile(false);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is Edge or not
+ * @return boolean True if the browser is Edge otherwise false
+ */
+ protected function checkBrowserEdge()
+ {
+ if (stripos($this->_agent, 'Edge/') !== false) {
+ $aresult = explode('/', stristr($this->_agent, 'Edge'));
+ if (isset($aresult[1])) {
+ $aversion = explode(' ', $aresult[1]);
+ $this->setVersion($aversion[0]);
+ $this->setBrowser(self::BROWSER_EDGE);
+ if (stripos($this->_agent, 'Windows Phone') !== false || stripos($this->_agent, 'Android') !== false) {
+ $this->setMobile(true);
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is Internet Explorer or not (last updated 1.7)
+ * @return boolean True if the browser is Internet Explorer otherwise false
+ */
+ protected function checkBrowserInternetExplorer()
+ {
+ // Test for IE11
+ if (stripos($this->_agent, 'Trident/7.0; rv:11.0') !== false) {
+ $this->setBrowser(self::BROWSER_IE);
+ $this->setVersion('11.0');
+ return true;
+ } // Test for v1 - v1.5 IE
+ else if (stripos($this->_agent, 'microsoft internet explorer') !== false) {
+ $this->setBrowser(self::BROWSER_IE);
+ $this->setVersion('1.0');
+ $aresult = stristr($this->_agent, '/');
+ if (preg_match('/308|425|426|474|0b1/i', $aresult)) {
+ $this->setVersion('1.5');
+ }
+ return true;
+ } // Test for versions > 1.5
+ else if (stripos($this->_agent, 'msie') !== false && stripos($this->_agent, 'opera') === false) {
+ // See if the browser is the odd MSN Explorer
+ if (stripos($this->_agent, 'msnb') !== false) {
+ $aresult = explode(' ', stristr(str_replace(';', '; ', $this->_agent), 'MSN'));
+ if (isset($aresult[1])) {
+ $this->setBrowser(self::BROWSER_MSN);
+ $this->setVersion(str_replace(array('(', ')', ';'), '', $aresult[1]));
+ return true;
+ }
+ }
+ $aresult = explode(' ', stristr(str_replace(';', '; ', $this->_agent), 'msie'));
+ if (isset($aresult[1])) {
+ $this->setBrowser(self::BROWSER_IE);
+ $this->setVersion(str_replace(array('(', ')', ';'), '', $aresult[1]));
+ if(preg_match('#trident/([0-9\.]+);#i', $this->_agent, $aresult)){
+ if($aresult[1] == '3.1'){
+ $this->setVersion('7.0');
+ }
+ else if($aresult[1] == '4.0'){
+ $this->setVersion('8.0');
+ }
+ else if($aresult[1] == '5.0'){
+ $this->setVersion('9.0');
+ }
+ else if($aresult[1] == '6.0'){
+ $this->setVersion('10.0');
+ }
+ else if($aresult[1] == '7.0'){
+ $this->setVersion('11.0');
+ }
+ else if($aresult[1] == '8.0'){
+ $this->setVersion('11.0');
+ }
+ }
+ if(stripos($this->_agent, 'IEMobile') !== false) {
+ $this->setBrowser(self::BROWSER_POCKET_IE);
+ $this->setMobile(true);
+ }
+ return true;
+ }
+ } // Test for versions > IE 10
+ else if (stripos($this->_agent, 'trident') !== false) {
+ $this->setBrowser(self::BROWSER_IE);
+ $result = explode('rv:', $this->_agent);
+ if (isset($result[1])) {
+ $this->setVersion(preg_replace('/[^0-9.]+/', '', $result[1]));
+ $this->_agent = str_replace(array("Mozilla", "Gecko"), "MSIE", $this->_agent);
+ }
+ } // Test for Pocket IE
+ else if (stripos($this->_agent, 'mspie') !== false || stripos($this->_agent, 'pocket') !== false) {
+ $aresult = explode(' ', stristr($this->_agent, 'mspie'));
+ if (isset($aresult[1])) {
+ $this->setPlatform(self::PLATFORM_WINDOWS_CE);
+ $this->setBrowser(self::BROWSER_POCKET_IE);
+ $this->setMobile(true);
+
+ if (stripos($this->_agent, 'mspie') !== false) {
+ $this->setVersion($aresult[1]);
+ } else {
+ $aversion = explode('/', $this->_agent);
+ if (isset($aversion[1])) {
+ $this->setVersion($aversion[1]);
+ }
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is Opera or not (last updated 1.7)
+ * @return boolean True if the browser is Opera otherwise false
+ */
+ protected function checkBrowserOpera()
+ {
+ if (stripos($this->_agent, 'opera mini') !== false) {
+ $resultant = stristr($this->_agent, 'opera mini');
+ if (preg_match('/\//', $resultant)) {
+ $aresult = explode('/', $resultant);
+ if (isset($aresult[1])) {
+ $aversion = explode(' ', $aresult[1]);
+ $this->setVersion($aversion[0]);
+ }
+ } else {
+ $aversion = explode(' ', stristr($resultant, 'opera mini'));
+ if (isset($aversion[1])) {
+ $this->setVersion($aversion[1]);
+ }
+ }
+ $this->_browser_name = self::BROWSER_OPERA_MINI;
+ $this->setMobile(true);
+ return true;
+ } else if (stripos($this->_agent, 'opera') !== false) {
+ $resultant = stristr($this->_agent, 'opera');
+ if (preg_match('/Version\/(1*.*)$/', $resultant, $matches)) {
+ $this->setVersion($matches[1]);
+ } else if (preg_match('/\//', $resultant)) {
+ $aresult = explode('/', str_replace("(", " ", $resultant));
+ if (isset($aresult[1])) {
+ $aversion = explode(' ', $aresult[1]);
+ $this->setVersion($aversion[0]);
+ }
+ } else {
+ $aversion = explode(' ', stristr($resultant, 'opera'));
+ $this->setVersion(isset($aversion[1]) ? $aversion[1] : "");
+ }
+ if (stripos($this->_agent, 'Opera Mobi') !== false) {
+ $this->setMobile(true);
+ }
+ $this->_browser_name = self::BROWSER_OPERA;
+ return true;
+ } else if (stripos($this->_agent, 'OPR') !== false) {
+ $resultant = stristr($this->_agent, 'OPR');
+ if (preg_match('/\//', $resultant)) {
+ $aresult = explode('/', str_replace("(", " ", $resultant));
+ if (isset($aresult[1])) {
+ $aversion = explode(' ', $aresult[1]);
+ $this->setVersion($aversion[0]);
+ }
+ }
+ if (stripos($this->_agent, 'Mobile') !== false) {
+ $this->setMobile(true);
+ }
+ $this->_browser_name = self::BROWSER_OPERA;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is Chrome or not (last updated 1.7)
+ * @return boolean True if the browser is Chrome otherwise false
+ */
+ protected function checkBrowserChrome()
+ {
+ if (stripos($this->_agent, 'Chrome') !== false) {
+ $aresult = explode('/', stristr($this->_agent, 'Chrome'));
+ if (isset($aresult[1])) {
+ $aversion = explode(' ', $aresult[1]);
+ $this->setVersion($aversion[0]);
+ $this->setBrowser(self::BROWSER_CHROME);
+ //Chrome on Android
+ if (stripos($this->_agent, 'Android') !== false) {
+ if (stripos($this->_agent, 'Mobile') !== false) {
+ $this->setMobile(true);
+ } else {
+ $this->setTablet(true);
+ }
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+ /**
+ * Determine if the browser is WebTv or not (last updated 1.7)
+ * @return boolean True if the browser is WebTv otherwise false
+ */
+ protected function checkBrowserWebTv()
+ {
+ if (stripos($this->_agent, 'webtv') !== false) {
+ $aresult = explode('/', stristr($this->_agent, 'webtv'));
+ if (isset($aresult[1])) {
+ $aversion = explode(' ', $aresult[1]);
+ $this->setVersion($aversion[0]);
+ $this->setBrowser(self::BROWSER_WEBTV);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is NetPositive or not (last updated 1.7)
+ * @return boolean True if the browser is NetPositive otherwise false
+ */
+ protected function checkBrowserNetPositive()
+ {
+ if (stripos($this->_agent, 'NetPositive') !== false) {
+ $aresult = explode('/', stristr($this->_agent, 'NetPositive'));
+ if (isset($aresult[1])) {
+ $aversion = explode(' ', $aresult[1]);
+ $this->setVersion(str_replace(array('(', ')', ';'), '', $aversion[0]));
+ $this->setBrowser(self::BROWSER_NETPOSITIVE);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is Galeon or not (last updated 1.7)
+ * @return boolean True if the browser is Galeon otherwise false
+ */
+ protected function checkBrowserGaleon()
+ {
+ if (stripos($this->_agent, 'galeon') !== false) {
+ $aresult = explode(' ', stristr($this->_agent, 'galeon'));
+ $aversion = explode('/', $aresult[0]);
+ if (isset($aversion[1])) {
+ $this->setVersion($aversion[1]);
+ $this->setBrowser(self::BROWSER_GALEON);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is Konqueror or not (last updated 1.7)
+ * @return boolean True if the browser is Konqueror otherwise false
+ */
+ protected function checkBrowserKonqueror()
+ {
+ if (stripos($this->_agent, 'Konqueror') !== false) {
+ $aresult = explode(' ', stristr($this->_agent, 'Konqueror'));
+ $aversion = explode('/', $aresult[0]);
+ if (isset($aversion[1])) {
+ $this->setVersion($aversion[1]);
+ $this->setBrowser(self::BROWSER_KONQUEROR);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is iCab or not (last updated 1.7)
+ * @return boolean True if the browser is iCab otherwise false
+ */
+ protected function checkBrowserIcab()
+ {
+ if (stripos($this->_agent, 'icab') !== false) {
+ $aversion = explode(' ', stristr(str_replace('/', ' ', $this->_agent), 'icab'));
+ if (isset($aversion[1])) {
+ $this->setVersion($aversion[1]);
+ $this->setBrowser(self::BROWSER_ICAB);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is OmniWeb or not (last updated 1.7)
+ * @return boolean True if the browser is OmniWeb otherwise false
+ */
+ protected function checkBrowserOmniWeb()
+ {
+ if (stripos($this->_agent, 'omniweb') !== false) {
+ $aresult = explode('/', stristr($this->_agent, 'omniweb'));
+ $aversion = explode(' ', isset($aresult[1]) ? $aresult[1] : "");
+ $this->setVersion($aversion[0]);
+ $this->setBrowser(self::BROWSER_OMNIWEB);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is Phoenix or not (last updated 1.7)
+ * @return boolean True if the browser is Phoenix otherwise false
+ */
+ protected function checkBrowserPhoenix()
+ {
+ if (stripos($this->_agent, 'Phoenix') !== false) {
+ $aversion = explode('/', stristr($this->_agent, 'Phoenix'));
+ if (isset($aversion[1])) {
+ $this->setVersion($aversion[1]);
+ $this->setBrowser(self::BROWSER_PHOENIX);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is Firebird or not (last updated 1.7)
+ * @return boolean True if the browser is Firebird otherwise false
+ */
+ protected function checkBrowserFirebird()
+ {
+ if (stripos($this->_agent, 'Firebird') !== false) {
+ $aversion = explode('/', stristr($this->_agent, 'Firebird'));
+ if (isset($aversion[1])) {
+ $this->setVersion($aversion[1]);
+ $this->setBrowser(self::BROWSER_FIREBIRD);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is Netscape Navigator 9+ or not (last updated 1.7)
+ * NOTE: (http://browser.netscape.com/ - Official support ended on March 1st, 2008)
+ * @return boolean True if the browser is Netscape Navigator 9+ otherwise false
+ */
+ protected function checkBrowserNetscapeNavigator9Plus()
+ {
+ if (stripos($this->_agent, 'Firefox') !== false && preg_match('/Navigator\/([^ ]*)/i', $this->_agent, $matches)) {
+ $this->setVersion($matches[1]);
+ $this->setBrowser(self::BROWSER_NETSCAPE_NAVIGATOR);
+ return true;
+ } else if (stripos($this->_agent, 'Firefox') === false && preg_match('/Netscape6?\/([^ ]*)/i', $this->_agent, $matches)) {
+ $this->setVersion($matches[1]);
+ $this->setBrowser(self::BROWSER_NETSCAPE_NAVIGATOR);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is Shiretoko or not (https://wiki.mozilla.org/Projects/shiretoko) (last updated 1.7)
+ * @return boolean True if the browser is Shiretoko otherwise false
+ */
+ protected function checkBrowserShiretoko()
+ {
+ if (stripos($this->_agent, 'Mozilla') !== false && preg_match('/Shiretoko\/([^ ]*)/i', $this->_agent, $matches)) {
+ $this->setVersion($matches[1]);
+ $this->setBrowser(self::BROWSER_SHIRETOKO);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is Ice Cat or not (http://en.wikipedia.org/wiki/GNU_IceCat) (last updated 1.7)
+ * @return boolean True if the browser is Ice Cat otherwise false
+ */
+ protected function checkBrowserIceCat()
+ {
+ if (stripos($this->_agent, 'Mozilla') !== false && preg_match('/IceCat\/([^ ]*)/i', $this->_agent, $matches)) {
+ $this->setVersion($matches[1]);
+ $this->setBrowser(self::BROWSER_ICECAT);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is Nokia or not (last updated 1.7)
+ * @return boolean True if the browser is Nokia otherwise false
+ */
+ protected function checkBrowserNokia()
+ {
+ if (preg_match("/Nokia([^\/]+)\/([^ SP]+)/i", $this->_agent, $matches)) {
+ $this->setVersion($matches[2]);
+ if (stripos($this->_agent, 'Series60') !== false || strpos($this->_agent, 'S60') !== false) {
+ $this->setBrowser(self::BROWSER_NOKIA_S60);
+ } else {
+ $this->setBrowser(self::BROWSER_NOKIA);
+ }
+ $this->setMobile(true);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is Firefox or not (last updated 1.7)
+ * @return boolean True if the browser is Firefox otherwise false
+ */
+ protected function checkBrowserFirefox()
+ {
+ if (stripos($this->_agent, 'safari') === false) {
+ if (preg_match("/Firefox[\/ \(]([^ ;\)]+)/i", $this->_agent, $matches)) {
+ $this->setVersion($matches[1]);
+ $this->setBrowser(self::BROWSER_FIREFOX);
+ //Firefox on Android
+ if (stripos($this->_agent, 'Android') !== false) {
+ if (stripos($this->_agent, 'Mobile') !== false) {
+ $this->setMobile(true);
+ } else {
+ $this->setTablet(true);
+ }
+ }
+ return true;
+ } else if (preg_match("/Firefox$/i", $this->_agent, $matches)) {
+ $this->setVersion("");
+ $this->setBrowser(self::BROWSER_FIREFOX);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is Firefox or not (last updated 1.7)
+ * @return boolean True if the browser is Firefox otherwise false
+ */
+ protected function checkBrowserIceweasel()
+ {
+ if (stripos($this->_agent, 'Iceweasel') !== false) {
+ $aresult = explode('/', stristr($this->_agent, 'Iceweasel'));
+ if (isset($aresult[1])) {
+ $aversion = explode(' ', $aresult[1]);
+ $this->setVersion($aversion[0]);
+ $this->setBrowser(self::BROWSER_ICEWEASEL);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is Mozilla or not (last updated 1.7)
+ * @return boolean True if the browser is Mozilla otherwise false
+ */
+ protected function checkBrowserMozilla()
+ {
+ if (stripos($this->_agent, 'mozilla') !== false && preg_match('/rv:[0-9].[0-9][a-b]?/i', $this->_agent) && stripos($this->_agent, 'netscape') === false) {
+ $aversion = explode(' ', stristr($this->_agent, 'rv:'));
+ preg_match('/rv:[0-9].[0-9][a-b]?/i', $this->_agent, $aversion);
+ $this->setVersion(str_replace('rv:', '', $aversion[0]));
+ $this->setBrowser(self::BROWSER_MOZILLA);
+ return true;
+ } else if (stripos($this->_agent, 'mozilla') !== false && preg_match('/rv:[0-9]\.[0-9]/i', $this->_agent) && stripos($this->_agent, 'netscape') === false) {
+ $aversion = explode('', stristr($this->_agent, 'rv:'));
+ $this->setVersion(str_replace('rv:', '', $aversion[0]));
+ $this->setBrowser(self::BROWSER_MOZILLA);
+ return true;
+ } else if (stripos($this->_agent, 'mozilla') !== false && preg_match('/mozilla\/([^ ]*)/i', $this->_agent, $matches) && stripos($this->_agent, 'netscape') === false) {
+ $this->setVersion($matches[1]);
+ $this->setBrowser(self::BROWSER_MOZILLA);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is Lynx or not (last updated 1.7)
+ * @return boolean True if the browser is Lynx otherwise false
+ */
+ protected function checkBrowserLynx()
+ {
+ if (stripos($this->_agent, 'lynx') !== false) {
+ $aresult = explode('/', stristr($this->_agent, 'Lynx'));
+ $aversion = explode(' ', (isset($aresult[1]) ? $aresult[1] : ""));
+ $this->setVersion($aversion[0]);
+ $this->setBrowser(self::BROWSER_LYNX);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is Amaya or not (last updated 1.7)
+ * @return boolean True if the browser is Amaya otherwise false
+ */
+ protected function checkBrowserAmaya()
+ {
+ if (stripos($this->_agent, 'amaya') !== false) {
+ $aresult = explode('/', stristr($this->_agent, 'Amaya'));
+ if (isset($aresult[1])) {
+ $aversion = explode(' ', $aresult[1]);
+ $this->setVersion($aversion[0]);
+ $this->setBrowser(self::BROWSER_AMAYA);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is Safari or not (last updated 1.7)
+ * @return boolean True if the browser is Safari otherwise false
+ */
+ protected function checkBrowserSafari()
+ {
+ if (stripos($this->_agent, 'Safari') !== false
+ && stripos($this->_agent, 'iPhone') === false
+ && stripos($this->_agent, 'iPod') === false
+ ) {
+
+ $aresult = explode('/', stristr($this->_agent, 'Version'));
+ if (isset($aresult[1])) {
+ $aversion = explode(' ', $aresult[1]);
+ $this->setVersion($aversion[0]);
+ } else {
+ $this->setVersion(self::VERSION_UNKNOWN);
+ }
+ $this->setBrowser(self::BROWSER_SAFARI);
+ return true;
+ }
+ return false;
+ }
+
+ protected function checkBrowserSamsung()
+ {
+ if (stripos($this->_agent, 'SamsungBrowser') !== false) {
+
+ $aresult = explode('/', stristr($this->_agent, 'SamsungBrowser'));
+ if (isset($aresult[1])) {
+ $aversion = explode(' ', $aresult[1]);
+ $this->setVersion($aversion[0]);
+ } else {
+ $this->setVersion(self::VERSION_UNKNOWN);
+ }
+ $this->setBrowser(self::BROWSER_SAMSUNG);
+ return true;
+ }
+ return false;
+ }
+
+ protected function checkBrowserSilk()
+ {
+ if (stripos($this->_agent, 'Silk') !== false) {
+ $aresult = explode('/', stristr($this->_agent, 'Silk'));
+ if (isset($aresult[1])) {
+ $aversion = explode(' ', $aresult[1]);
+ $this->setVersion($aversion[0]);
+ } else {
+ $this->setVersion(self::VERSION_UNKNOWN);
+ }
+ $this->setBrowser(self::BROWSER_SILK);
+ return true;
+ }
+ return false;
+ }
+
+ protected function checkBrowserIframely()
+ {
+ if (stripos($this->_agent, 'Iframely') !== false) {
+ $aresult = explode('/', stristr($this->_agent, 'Iframely'));
+ if (isset($aresult[1])) {
+ $aversion = explode(' ', $aresult[1]);
+ $this->setVersion($aversion[0]);
+ } else {
+ $this->setVersion(self::VERSION_UNKNOWN);
+ }
+ $this->setBrowser(self::BROWSER_I_FRAME);
+ return true;
+ }
+ return false;
+ }
+
+ protected function checkBrowserCocoa()
+ {
+ if (stripos($this->_agent, 'CocoaRestClient') !== false) {
+ $aresult = explode('/', stristr($this->_agent, 'CocoaRestClient'));
+ if (isset($aresult[1])) {
+ $aversion = explode(' ', $aresult[1]);
+ $this->setVersion($aversion[0]);
+ } else {
+ $this->setVersion(self::VERSION_UNKNOWN);
+ }
+ $this->setBrowser(self::BROWSER_COCOA);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Detect if URL is loaded from FacebookExternalHit
+ * @return boolean True if it detects FacebookExternalHit otherwise false
+ */
+ protected function checkFacebookExternalHit()
+ {
+ if (stristr($this->_agent, 'FacebookExternalHit')) {
+ $this->setRobot(true);
+ $this->setFacebook(true);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Detect if URL is being loaded from internal Facebook browser
+ * @return boolean True if it detects internal Facebook browser otherwise false
+ */
+ protected function checkForFacebookIos()
+ {
+ if (stristr($this->_agent, 'FBIOS')) {
+ $this->setFacebook(true);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Detect Version for the Safari browser on iOS devices
+ * @return boolean True if it detects the version correctly otherwise false
+ */
+ protected function getSafariVersionOnIos()
+ {
+ $aresult = explode('/', stristr($this->_agent, 'Version'));
+ if (isset($aresult[1])) {
+ $aversion = explode(' ', $aresult[1]);
+ $this->setVersion($aversion[0]);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Detect Version for the Chrome browser on iOS devices
+ * @return boolean True if it detects the version correctly otherwise false
+ */
+ protected function getChromeVersionOnIos()
+ {
+ $aresult = explode('/', stristr($this->_agent, 'CriOS'));
+ if (isset($aresult[1])) {
+ $aversion = explode(' ', $aresult[1]);
+ $this->setVersion($aversion[0]);
+ $this->setBrowser(self::BROWSER_CHROME);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is iPhone or not (last updated 1.7)
+ * @return boolean True if the browser is iPhone otherwise false
+ */
+ protected function checkBrowseriPhone()
+ {
+ if (stripos($this->_agent, 'iPhone') !== false) {
+ $this->setVersion(self::VERSION_UNKNOWN);
+ $this->setBrowser(self::BROWSER_IPHONE);
+ $this->getSafariVersionOnIos();
+ $this->getChromeVersionOnIos();
+ $this->checkForFacebookIos();
+ $this->setMobile(true);
+ return true;
+
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is iPad or not (last updated 1.7)
+ * @return boolean True if the browser is iPad otherwise false
+ */
+ protected function checkBrowseriPad()
+ {
+ if (stripos($this->_agent, 'iPad') !== false) {
+ $this->setVersion(self::VERSION_UNKNOWN);
+ $this->setBrowser(self::BROWSER_IPAD);
+ $this->getSafariVersionOnIos();
+ $this->getChromeVersionOnIos();
+ $this->checkForFacebookIos();
+ $this->setTablet(true);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is iPod or not (last updated 1.7)
+ * @return boolean True if the browser is iPod otherwise false
+ */
+ protected function checkBrowseriPod()
+ {
+ if (stripos($this->_agent, 'iPod') !== false) {
+ $this->setVersion(self::VERSION_UNKNOWN);
+ $this->setBrowser(self::BROWSER_IPOD);
+ $this->getSafariVersionOnIos();
+ $this->getChromeVersionOnIos();
+ $this->checkForFacebookIos();
+ $this->setMobile(true);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is Android or not (last updated 1.7)
+ * @return boolean True if the browser is Android otherwise false
+ */
+ protected function checkBrowserAndroid()
+ {
+ if (stripos($this->_agent, 'Android') !== false) {
+ $aresult = explode(' ', stristr($this->_agent, 'Android'));
+ if (isset($aresult[1])) {
+ $aversion = explode(' ', $aresult[1]);
+ $this->setVersion($aversion[0]);
+ } else {
+ $this->setVersion(self::VERSION_UNKNOWN);
+ }
+ if (stripos($this->_agent, 'Mobile') !== false) {
+ $this->setMobile(true);
+ } else {
+ $this->setTablet(true);
+ }
+ $this->setBrowser(self::BROWSER_ANDROID);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is Vivaldi
+ * @return boolean True if the browser is Vivaldi otherwise false
+ */
+ protected function checkBrowserVivaldi()
+ {
+ if (stripos($this->_agent, 'Vivaldi') !== false) {
+ $aresult = explode('/', stristr($this->_agent, 'Vivaldi'));
+ if (isset($aresult[1])) {
+ $aversion = explode(' ', $aresult[1]);
+ $this->setVersion($aversion[0]);
+ $this->setBrowser(self::BROWSER_VIVALDI);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the browser is Yandex
+ * @return boolean True if the browser is Yandex otherwise false
+ */
+ protected function checkBrowserYandex()
+ {
+ if (stripos($this->_agent, 'YaBrowser') !== false) {
+ $aresult = explode('/', stristr($this->_agent, 'YaBrowser'));
+ if (isset($aresult[1])) {
+ $aversion = explode(' ', $aresult[1]);
+ $this->setVersion($aversion[0]);
+ $this->setBrowser(self::BROWSER_YANDEX);
+
+ if (stripos($this->_agent, 'iPad') !== false) {
+ $this->setTablet(true);
+ } elseif (stripos($this->_agent, 'Mobile') !== false) {
+ $this->setMobile(true);
+ } elseif (stripos($this->_agent, 'Android') !== false) {
+ $this->setTablet(true);
+ }
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Determine if the browser is a PlayStation
+ * @return boolean True if the browser is PlayStation otherwise false
+ */
+ protected function checkBrowserPlayStation()
+ {
+ if (stripos($this->_agent, 'PlayStation ') !== false) {
+ $aresult = explode(' ', stristr($this->_agent, 'PlayStation '));
+ $this->setBrowser(self::BROWSER_PLAYSTATION);
+ if (isset($aresult[0])) {
+ $aversion = explode(')', $aresult[2]);
+ $this->setVersion($aversion[0]);
+ if (stripos($this->_agent, 'Portable)') !== false || stripos($this->_agent, 'Vita') !== false) {
+ $this->setMobile(true);
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Determine the user's platform (last updated 2.0)
+ */
+ protected function checkPlatform()
+ {
+ if (stripos($this->_agent, 'windows') !== false) {
+ $this->_platform = self::PLATFORM_WINDOWS;
+ } else if (stripos($this->_agent, 'iPad') !== false) {
+ $this->_platform = self::PLATFORM_IPAD;
+ } else if (stripos($this->_agent, 'iPod') !== false) {
+ $this->_platform = self::PLATFORM_IPOD;
+ } else if (stripos($this->_agent, 'iPhone') !== false) {
+ $this->_platform = self::PLATFORM_IPHONE;
+ } elseif (stripos($this->_agent, 'mac') !== false) {
+ $this->_platform = self::PLATFORM_APPLE;
+ } elseif (stripos($this->_agent, 'android') !== false) {
+ $this->_platform = self::PLATFORM_ANDROID;
+ } elseif (stripos($this->_agent, 'Silk') !== false) {
+ $this->_platform = self::PLATFORM_FIRE_OS;
+ } elseif (stripos($this->_agent, 'linux') !== false && stripos($this->_agent, 'SMART-TV') !== false ) {
+ $this->_platform = self::PLATFORM_LINUX .'/'.self::PLATFORM_SMART_TV;
+ } elseif (stripos($this->_agent, 'linux') !== false) {
+ $this->_platform = self::PLATFORM_LINUX;
+ } else if (stripos($this->_agent, 'Nokia') !== false) {
+ $this->_platform = self::PLATFORM_NOKIA;
+ } else if (stripos($this->_agent, 'BlackBerry') !== false) {
+ $this->_platform = self::PLATFORM_BLACKBERRY;
+ } elseif (stripos($this->_agent, 'FreeBSD') !== false) {
+ $this->_platform = self::PLATFORM_FREEBSD;
+ } elseif (stripos($this->_agent, 'OpenBSD') !== false) {
+ $this->_platform = self::PLATFORM_OPENBSD;
+ } elseif (stripos($this->_agent, 'NetBSD') !== false) {
+ $this->_platform = self::PLATFORM_NETBSD;
+ } elseif (stripos($this->_agent, 'OpenSolaris') !== false) {
+ $this->_platform = self::PLATFORM_OPENSOLARIS;
+ } elseif (stripos($this->_agent, 'SunOS') !== false) {
+ $this->_platform = self::PLATFORM_SUNOS;
+ } elseif (stripos($this->_agent, 'OS\/2') !== false) {
+ $this->_platform = self::PLATFORM_OS2;
+ } elseif (stripos($this->_agent, 'BeOS') !== false) {
+ $this->_platform = self::PLATFORM_BEOS;
+ } elseif (stripos($this->_agent, 'win') !== false) {
+ $this->_platform = self::PLATFORM_WINDOWS;
+ } elseif (stripos($this->_agent, 'Playstation') !== false) {
+ $this->_platform = self::PLATFORM_PLAYSTATION;
+ } elseif (stripos($this->_agent, 'Roku') !== false) {
+ $this->_platform = self::PLATFORM_ROKU;
+ } elseif (stripos($this->_agent, 'iOS') !== false) {
+ $this->_platform = self::PLATFORM_IPHONE . '/' . self::PLATFORM_IPAD;
+ } elseif (stripos($this->_agent, 'tvOS') !== false) {
+ $this->_platform = self::PLATFORM_APPLE_TV;
+ } elseif (stripos($this->_agent, 'curl') !== false) {
+ $this->_platform = self::PLATFORM_TERMINAL;
+ } elseif (stripos($this->_agent, 'CrOS') !== false) {
+ $this->_platform = self::PLATFORM_CHROME_OS;
+ } elseif (stripos($this->_agent, 'okhttp') !== false) {
+ $this->_platform = self::PLATFORM_JAVA_ANDROID;
+ } elseif (stripos($this->_agent, 'PostmanRuntime') !== false) {
+ $this->_platform = self::PLATFORM_POSTMAN;
+ } elseif (stripos($this->_agent, 'Iframely') !== false) {
+ $this->_platform = self::PLATFORM_I_FRAME;
+ }
+
+ }
+}
diff --git a/k2shop/usr/k2shop/libs/browser/Readme.txt b/k2shop/usr/k2shop/libs/browser/Readme.txt
new file mode 100644
index 0000000..3a76660
--- /dev/null
+++ b/k2shop/usr/k2shop/libs/browser/Readme.txt
@@ -0,0 +1,9 @@
+Îïðåäåëåíèå âåðñèè è òèïà áðàóçåðà.
+Ïîñòîÿííî îáíîâëÿåòñÿ ïî àäðåñó: https://github.com/cbschuld/Browser.php
+Ñòàòüÿ ïî äàííîé òåìå: https://ruseller.com/adds.php?rub=11&id=1914
+
+Ïðèìåð èñïîëüçîâàíèÿ:
+$browser = new Browser();
+if( $browser->getBrowser() == Browser::BROWSER_FIREFOX && $browser->getVersion() >= 2 ) {
+ echo 'Âû èñïîëüçóåòå áðàóçåð FireFox âåðñèè 2 èëè âûøå';
+}
\ No newline at end of file
diff --git a/k2shop/usr/k2shop/libs/detectDevice/DetectDeviceTest.php b/k2shop/usr/k2shop/libs/detectDevice/DetectDeviceTest.php
new file mode 100644
index 0000000..5ac4ce0
--- /dev/null
+++ b/k2shop/usr/k2shop/libs/detectDevice/DetectDeviceTest.php
@@ -0,0 +1,71 @@
+device = new DetectDevice("Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.66 Safari/537.36");
+ }
+
+ public function testComputer() {
+ // Google Chrome 29 on Windows 8 x64
+ $this->device->setUserAgent("Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.66 Safari/537.36");
+ $this->assertEquals(true, $this->device->isComputer());
+
+ // Mozilla Firefox 22 on Windows 8 x64
+ $this->device->setUserAgent("Mozilla/5.0 (Windows NT 6.2; WOW64; rv:22.0) Gecko/20100101 Firefox/22.0");
+ $this->assertEquals(true, $this->device->isComputer());
+ }
+
+ public function testMobile() {
+ // LGE Nexus 4
+ $this->device->setUserAgent("Mozilla/5.0 (Linux; Android 4.2; Nexus 4 Build/JVP15Q) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19");
+ $this->assertEquals(true, $this->device->isMobile());
+
+ // Samsung Galaxy S4
+ $this->device->setUserAgent("Mozilla/5.0 (Linux; U; Android 4.0.4; en-gb; GT-I9300 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30");
+ $this->assertEquals(true, $this->device->isMobile());
+ }
+
+ public function testTablet() {
+ // Asus Nexus 7
+ $this->device->setUserAgent("Mozilla/5.0 (Linux; Android 4.1.1; Nexus 7 Build/JRO03D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19");
+ $this->assertEquals(true, $this->device->isTablet());
+
+ // Samsung Galaxy Note 10.1
+ $this->device->setUserAgent("Mozilla/5.0 (Linux; U; Android 4.0; xx-xx; GT-N8000 Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30");
+ $this->assertEquals(true, $this->device->isTablet());
+ }
+
+ public function testBot() {
+ // GoogleBot
+ $this->device->setUserAgent("Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)");
+ $this->assertEquals(true, $this->device->isBot());
+
+ // BingBot
+ $this->device->setUserAgent("Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)");
+ $this->assertEquals(true, $this->device->isBot());
+ }
+
+ public function testConsole() {
+ // PS3
+ $this->device->setUserAgent("Mozilla/5.0 (PLAYSTATION 3; 3.55)");
+ $this->assertEquals(true, $this->device->isConsole());
+
+ // XBox
+ $this->device->setUserAgent("Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; Xbox)");
+ $this->assertEquals(true, $this->device->isConsole());
+ }
+
+ public function testIs() {
+ // Google Chrome
+ $this->device->setUserAgent("Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.66 Safari/537.36");
+ $this->assertEquals(true, $this->device->is("chrome"));
+
+ // Nintendo DS
+ $this->device->setUserAgent("Mozilla/5.0 (Windows NT 6.2; WOW64; rv:22.0) Gecko/20100101 Firefox/22.0");
+ $this->assertEquals(true, $this->device->is("firefox"));
+ }
+}
\ No newline at end of file
diff --git a/k2shop/usr/k2shop/libs/detectDevice/README.md b/k2shop/usr/k2shop/libs/detectDevice/README.md
new file mode 100644
index 0000000..90eb4f6
--- /dev/null
+++ b/k2shop/usr/k2shop/libs/detectDevice/README.md
@@ -0,0 +1,56 @@
+DetectDevice
+============
+[](https://travis-ci.org/Kocal/DetectDevice)
+
+DetectDevice is a little (~70 lines), simply, and functional PHP class which detect what kind of device is used to navigate on your website, a pc, a mobile, a tablet or a bot.
+
+
+How use?
+--------
+#### Firstly, include DetectDevice class and initialize it
+```php
+setUserAgent($userAgent);
+```
+
+#### Use methods to find what kind of device is used
+```php
+isComputer();
+echo $device->isMobile();
+echo $device->isTablet();
+echo $device->isBot();
+echo $device->isConsole();
+
+// You can use the "getDeviceType()" to return a string
+echo $device->getDeviceType(); // may return "computer", "mobile, "tablet", "bot" or "console"
+// ...
+```
+
+#### Or use "is()"
+```php
+is($str)) {
+ // do stuff for Internet Explorer only
+}
+
+```
\ No newline at end of file
diff --git a/k2shop/usr/k2shop/libs/detectDevice/class.DetectDevice.php b/k2shop/usr/k2shop/libs/detectDevice/class.DetectDevice.php
new file mode 100644
index 0000000..823150a
--- /dev/null
+++ b/k2shop/usr/k2shop/libs/detectDevice/class.DetectDevice.php
@@ -0,0 +1,76 @@
+ array("msie 10", "msie 9", "msie 8", "windows.*firefox", "windows.*chrome", "x11.*chrome", "x11.*firefox", "macintosh.*chrome", "macintosh.*firefox", "opera"),
+ "tablet" => array("tablet", "android", "ipad", "tablet.*firefox"),
+ "mobile" => array("mobile ", "android.*mobile", "iphone", "ipod", "opera mobi", "opera mini"),
+ "bot" => array("googlebot", "mediapartners-google", "adsbot-google", "duckduckbot", "msnbot", "bingbot", "ask", "facebook", "yahoo", "addthis"),
+ "console" => array("ps2", "playstation", "xbox", "wii", "nintendo 3?ds")
+ );
+
+
+ private $deviceType = "";
+
+ private $isComputer = false;
+ private $isMobile = false;
+ private $isTablet = false;
+ private $isBot = false;
+ private $isConsole = false;
+
+
+ public function __construct($userAgent = "") {
+ if(!empty($userAgent)) {
+ $this->userAgent = $userAgent;
+ } else {
+ $this->userAgent = $_SERVER["HTTP_USER_AGENT"];
+ }
+
+ $this->detectDevice();
+ }
+
+ public function detectDevice() {
+ foreach($this->devices as $deviceType => $devices) {
+ foreach($devices as $device) {
+ if(preg_match("/" . $device . "/i", $this->userAgent)) {
+ $this->deviceType = $deviceType;
+ }
+ }
+ }
+
+ $d = "is" . ucfirst($this->deviceType);
+ $this->$d = true;
+ }
+
+ public function setUserAgent($userAgent) {
+ $this->userAgent = $userAgent;
+ $this->resetDevices();
+ $this->detectDevice();
+ }
+
+ public function resetDevices() {
+ $this->isComputer = false;
+ $this->isMobile = false;
+ $this->isTablet = false;
+ $this->isBot = false;
+ }
+
+ public function is($str, $userAgent = null) {
+ if(!$userAgent) {
+ $userAgent = $this->userAgent;
+ }
+
+ return preg_match('/' . $str . '/i', $userAgent);
+ }
+
+ public function getDeviceType() { return $this->deviceType; }
+ public function isComputer() { return $this->isComputer; }
+ public function isMobile() { return $this->isMobile; }
+ public function isTablet() { return $this->isTablet; }
+ public function isBot() { return $this->isBot; }
+ public function isConsole() { return $this->isConsole; }
+ public function getUserAgent() { return $this->userAgent; }
+
+
+}
diff --git a/k2shop/usr/k2shop/libs/nestmenu/index.html b/k2shop/usr/k2shop/libs/nestmenu/index.html
new file mode 100644
index 0000000..fe53bfe
--- /dev/null
+++ b/k2shop/usr/k2shop/libs/nestmenu/index.html
@@ -0,0 +1,279 @@
+
+
+
+
+
+
+
Drag & drop hierarchical list with mouse and touch compatibility (jQuery plugin)
+ + + + + + +PLEASE NOTE: I cannot provide any support or guidance beyond this README. If this code helps you that's great but I have no plans to develop Nestable beyond this demo (it's not a final product and has limited functionality). I cannot reply to any requests for help.
+ + + +Serialised Output (per list)
+ + + + ++ +
Draggable Handles
+ +If you're clever with your CSS and markup this can be achieved without any JavaScript changes.
+ +Copyright © David Bushell | Made for Browser
+ + + + + + \ No newline at end of file diff --git a/k2shop/usr/k2shop/libs/nestmenu/jquery.nestable.js b/k2shop/usr/k2shop/libs/nestmenu/jquery.nestable.js new file mode 100644 index 0000000..2908465 --- /dev/null +++ b/k2shop/usr/k2shop/libs/nestmenu/jquery.nestable.js @@ -0,0 +1,484 @@ +/*! + * Nestable jQuery Plugin - Copyright (c) 2012 David Bushell - http://dbushell.com/ + * Dual-licensed under the BSD or MIT licenses + */ +;(function($, window, document, undefined) +{ + var hasTouch = 'ontouchstart' in document; + + /** + * Detect CSS pointer-events property + * events are normally disabled on the dragging element to avoid conflicts + * https://github.com/ausi/Feature-detection-technique-for-pointer-events/blob/master/modernizr-pointerevents.js + */ + var hasPointerEvents = (function() + { + var el = document.createElement('div'), + docEl = document.documentElement; + if (!('pointerEvents' in el.style)) { + return false; + } + el.style.pointerEvents = 'auto'; + el.style.pointerEvents = 'x'; + docEl.appendChild(el); + var supports = window.getComputedStyle && window.getComputedStyle(el, '').pointerEvents === 'auto'; + docEl.removeChild(el); + return !!supports; + })(); + + var defaults = { + listNodeName : 'ol', + itemNodeName : 'li', + rootClass : 'dd', + listClass : 'dd-list', + itemClass : 'dd-item', + dragClass : 'dd-dragel', + handleClass : 'dd-handle', + collapsedClass : 'dd-collapsed', + placeClass : 'dd-placeholder', + noDragClass : 'dd-nodrag', + emptyClass : 'dd-empty', + expandBtnHTML : '', + collapseBtnHTML : '', + group : 0, + maxDepth : 5, + threshold : 20 + }; + + function Plugin(element, options) + { + this.w = $(document); + this.el = $(element); + this.options = $.extend({}, defaults, options); + this.init(); + } + + Plugin.prototype = { + + init: function() + { + var list = this; + + list.reset(); + + list.el.data('nestable-group', this.options.group); + + list.placeEl = $(''); + + $.each(this.el.find(list.options.itemNodeName), function(k, el) { + list.setParent($(el)); + }); + + list.el.on('click', 'button', function(e) { + if (list.dragEl) { + return; + } + var target = $(e.currentTarget), + action = target.data('action'), + item = target.parent(list.options.itemNodeName); + if (action === 'collapse') { + list.collapseItem(item); + } + if (action === 'expand') { + list.expandItem(item); + } + }); + + var onStartEvent = function(e) + { + var handle = $(e.target); + if (!handle.hasClass(list.options.handleClass)) { + if (handle.closest('.' + list.options.noDragClass).length) { + return; + } + handle = handle.closest('.' + list.options.handleClass); + } + + if (!handle.length || list.dragEl) { + return; + } + + list.isTouch = /^touch/.test(e.type); + if (list.isTouch && e.touches.length !== 1) { + return; + } + + e.preventDefault(); + list.dragStart(e.touches ? e.touches[0] : e); + }; + + var onMoveEvent = function(e) + { + if (list.dragEl) { + e.preventDefault(); + list.dragMove(e.touches ? e.touches[0] : e); + } + }; + + var onEndEvent = function(e) + { + if (list.dragEl) { + e.preventDefault(); + list.dragStop(e.touches ? e.touches[0] : e); + } + }; + + if (hasTouch) { + list.el[0].addEventListener('touchstart', onStartEvent, false); + window.addEventListener('touchmove', onMoveEvent, false); + window.addEventListener('touchend', onEndEvent, false); + window.addEventListener('touchcancel', onEndEvent, false); + } + + list.el.on('mousedown', onStartEvent); + list.w.on('mousemove', onMoveEvent); + list.w.on('mouseup', onEndEvent); + + }, + + serialize: function() + { + var data, + depth = 0, + list = this; + step = function(level, depth) + { + var array = [ ], + items = level.children(list.options.itemNodeName); + items.each(function() + { + var li = $(this), + item = $.extend({}, li.data()), + sub = li.children(list.options.listNodeName); + if (sub.length) { + item.children = step(sub, depth + 1); + } + array.push(item); + }); + return array; + }; + data = step(list.el.find(list.options.listNodeName).first(), depth); + return data; + }, + + serialise: function() + { + return this.serialize(); + }, + + reset: function() + { + this.mouse = { + offsetX : 0, + offsetY : 0, + startX : 0, + startY : 0, + lastX : 0, + lastY : 0, + nowX : 0, + nowY : 0, + distX : 0, + distY : 0, + dirAx : 0, + dirX : 0, + dirY : 0, + lastDirX : 0, + lastDirY : 0, + distAxX : 0, + distAxY : 0 + }; + this.isTouch = false; + this.moving = false; + this.dragEl = null; + this.dragRootEl = null; + this.dragDepth = 0; + this.hasNewRoot = false; + this.pointEl = null; + }, + + expandItem: function(li) + { + li.removeClass(this.options.collapsedClass); + li.children('[data-action="expand"]').hide(); + li.children('[data-action="collapse"]').show(); + li.children(this.options.listNodeName).show(); + }, + + collapseItem: function(li) + { + var lists = li.children(this.options.listNodeName); + if (lists.length) { + li.addClass(this.options.collapsedClass); + li.children('[data-action="collapse"]').hide(); + li.children('[data-action="expand"]').show(); + li.children(this.options.listNodeName).hide(); + } + }, + + expandAll: function() + { + var list = this; + list.el.find(list.options.itemNodeName).each(function() { + list.expandItem($(this)); + }); + }, + + collapseAll: function() + { + var list = this; + list.el.find(list.options.itemNodeName).each(function() { + list.collapseItem($(this)); + }); + }, + + setParent: function(li) + { + if (li.children(this.options.listNodeName).length) { + li.prepend($(this.options.expandBtnHTML)); + li.prepend($(this.options.collapseBtnHTML)); + } + li.children('[data-action="expand"]').hide(); + }, + + unsetParent: function(li) + { + li.removeClass(this.options.collapsedClass); + li.children('[data-action]').remove(); + li.children(this.options.listNodeName).remove(); + }, + + dragStart: function(e) + { + var mouse = this.mouse, + target = $(e.target), + dragItem = target.closest(this.options.itemNodeName); + + this.placeEl.css('height', dragItem.height()); + + mouse.offsetX = e.offsetX !== undefined ? e.offsetX : e.pageX - target.offset().left; + mouse.offsetY = e.offsetY !== undefined ? e.offsetY : e.pageY - target.offset().top; + mouse.startX = mouse.lastX = e.pageX; + mouse.startY = mouse.lastY = e.pageY; + + this.dragRootEl = this.el; + + this.dragEl = $(document.createElement(this.options.listNodeName)).addClass(this.options.listClass + ' ' + this.options.dragClass); + this.dragEl.css('width', dragItem.width()); + + dragItem.after(this.placeEl); + dragItem[0].parentNode.removeChild(dragItem[0]); + dragItem.appendTo(this.dragEl); + + $(document.body).append(this.dragEl); + this.dragEl.css({ + 'left' : e.pageX - mouse.offsetX, + 'top' : e.pageY - mouse.offsetY + }); + // total depth of dragging item + var i, depth, + items = this.dragEl.find(this.options.itemNodeName); + for (i = 0; i < items.length; i++) { + depth = $(items[i]).parents(this.options.listNodeName).length; + if (depth > this.dragDepth) { + this.dragDepth = depth; + } + } + }, + + dragStop: function(e) + { + var el = this.dragEl.children(this.options.itemNodeName).first(); + el[0].parentNode.removeChild(el[0]); + this.placeEl.replaceWith(el); + + this.dragEl.remove(); + this.el.trigger('change'); + if (this.hasNewRoot) { + this.dragRootEl.trigger('change'); + } + this.reset(); + }, + + dragMove: function(e) + { + var list, parent, prev, next, depth, + opt = this.options, + mouse = this.mouse; + + this.dragEl.css({ + 'left' : e.pageX - mouse.offsetX, + 'top' : e.pageY - mouse.offsetY + }); + + // mouse position last events + mouse.lastX = mouse.nowX; + mouse.lastY = mouse.nowY; + // mouse position this events + mouse.nowX = e.pageX; + mouse.nowY = e.pageY; + // distance mouse moved between events + mouse.distX = mouse.nowX - mouse.lastX; + mouse.distY = mouse.nowY - mouse.lastY; + // direction mouse was moving + mouse.lastDirX = mouse.dirX; + mouse.lastDirY = mouse.dirY; + // direction mouse is now moving (on both axis) + mouse.dirX = mouse.distX === 0 ? 0 : mouse.distX > 0 ? 1 : -1; + mouse.dirY = mouse.distY === 0 ? 0 : mouse.distY > 0 ? 1 : -1; + // axis mouse is now moving on + var newAx = Math.abs(mouse.distX) > Math.abs(mouse.distY) ? 1 : 0; + + // do nothing on first move + if (!mouse.moving) { + mouse.dirAx = newAx; + mouse.moving = true; + return; + } + + // calc distance moved on this axis (and direction) + if (mouse.dirAx !== newAx) { + mouse.distAxX = 0; + mouse.distAxY = 0; + } else { + mouse.distAxX += Math.abs(mouse.distX); + if (mouse.dirX !== 0 && mouse.dirX !== mouse.lastDirX) { + mouse.distAxX = 0; + } + mouse.distAxY += Math.abs(mouse.distY); + if (mouse.dirY !== 0 && mouse.dirY !== mouse.lastDirY) { + mouse.distAxY = 0; + } + } + mouse.dirAx = newAx; + + /** + * move horizontal + */ + if (mouse.dirAx && mouse.distAxX >= opt.threshold) { + // reset move distance on x-axis for new phase + mouse.distAxX = 0; + prev = this.placeEl.prev(opt.itemNodeName); + // increase horizontal level if previous sibling exists and is not collapsed + if (mouse.distX > 0 && prev.length && !prev.hasClass(opt.collapsedClass)) { + // cannot increase level when item above is collapsed + list = prev.find(opt.listNodeName).last(); + // check if depth limit has reached + depth = this.placeEl.parents(opt.listNodeName).length; + if (depth + this.dragDepth <= opt.maxDepth) { + // create new sub-level if one doesn't exist + if (!list.length) { + list = $('<' + opt.listNodeName + '/>').addClass(opt.listClass); + list.append(this.placeEl); + prev.append(list); + this.setParent(prev); + } else { + // else append to next level up + list = prev.children(opt.listNodeName).last(); + list.append(this.placeEl); + } + } + } + // decrease horizontal level + if (mouse.distX < 0) { + // we can't decrease a level if an item preceeds the current one + next = this.placeEl.next(opt.itemNodeName); + if (!next.length) { + parent = this.placeEl.parent(); + this.placeEl.closest(opt.itemNodeName).after(this.placeEl); + if (!parent.children().length) { + this.unsetParent(parent.parent()); + } + } + } + } + + var isEmpty = false; + + // find list item under cursor + if (!hasPointerEvents) { + this.dragEl[0].style.visibility = 'hidden'; + } + this.pointEl = $(document.elementFromPoint(e.pageX - document.body.scrollLeft, e.pageY - (window.pageYOffset || document.documentElement.scrollTop))); + if (!hasPointerEvents) { + this.dragEl[0].style.visibility = 'visible'; + } + if (this.pointEl.hasClass(opt.handleClass)) { + this.pointEl = this.pointEl.parent(opt.itemNodeName); + } + if (this.pointEl.hasClass(opt.emptyClass)) { + isEmpty = true; + } + else if (!this.pointEl.length || !this.pointEl.hasClass(opt.itemClass)) { + return; + } + + // find parent list of item under cursor + var pointElRoot = this.pointEl.closest('.' + opt.rootClass), + isNewRoot = this.dragRootEl.data('nestable-id') !== pointElRoot.data('nestable-id'); + + /** + * move vertical + */ + if (!mouse.dirAx || isNewRoot || isEmpty) { + // check if groups match if dragging over new root + if (isNewRoot && opt.group !== pointElRoot.data('nestable-group')) { + return; + } + // check depth limit + depth = this.dragDepth - 1 + this.pointEl.parents(opt.listNodeName).length; + if (depth > opt.maxDepth) { + return; + } + var before = e.pageY < (this.pointEl.offset().top + this.pointEl.height() / 2); + parent = this.placeEl.parent(); + // if empty create new list to replace empty placeholder + if (isEmpty) { + list = $(document.createElement(opt.listNodeName)).addClass(opt.listClass); + list.append(this.placeEl); + this.pointEl.replaceWith(list); + } + else if (before) { + this.pointEl.before(this.placeEl); + } + else { + this.pointEl.after(this.placeEl); + } + if (!parent.children().length) { + this.unsetParent(parent.parent()); + } + if (!this.dragRootEl.find(opt.itemNodeName).length) { + this.dragRootEl.append(''); + } + // parent root list has changed + if (isNewRoot) { + this.dragRootEl = pointElRoot; + this.hasNewRoot = this.el[0] !== this.dragRootEl[0]; + } + } + } + + }; + + $.fn.nestable = function(params) + { + var lists = this, + retval = this; + + lists.each(function() + { + var plugin = $(this).data("nestable"); + + if (!plugin) { + $(this).data("nestable", new Plugin(this, params)); + $(this).data("nestable-id", new Date().getTime()); + } else { + if (typeof params === 'string' && typeof plugin[params] === 'function') { + retval = plugin[params](); + } + } + }); + + return retval || lists; + }; + +})(window.jQuery || window.Zepto, window, document); \ No newline at end of file diff --git a/k2shop/usr/k2shop/libs/nestmenu/nestable.css b/k2shop/usr/k2shop/libs/nestmenu/nestable.css new file mode 100644 index 0000000..e128b61 --- /dev/null +++ b/k2shop/usr/k2shop/libs/nestmenu/nestable.css @@ -0,0 +1,94 @@ + +/** + * Nestable + */ +.dd { position: relative; display: block; margin: 0; padding: 0; /*max-width: 600px;*/ list-style: none; font-size: 13px; line-height: 20px; overflow:scroll; height:600px; } +.dd-list { display: block; position: relative; margin: 0; padding: 0; list-style: none; } +.dd-list .dd-list { padding-left: 30px; } +.dd-collapsed .dd-list { display: none; } +.dd-item, +.dd-empty, +.dd-placeholder { display: block; position: relative; margin: 0; padding: 0; min-height: 20px; font-size: 13px; line-height: 20px; } +.dd-handle { display: block; height: 30px; margin: 5px 0; padding: 5px 10px; color: #333; text-decoration: none; font-weight: bold; border: 1px solid #ccc; width:650px; + background: #fafafa; + background: -webkit-linear-gradient(top, #fafafa 0%, #eee 100%); + background: -moz-linear-gradient(top, #fafafa 0%, #eee 100%); + background: linear-gradient(top, #fafafa 0%, #eee 100%); + -webkit-border-radius: 3px; + border-radius: 3px; + box-sizing: border-box; -moz-box-sizing: border-box; +} +.dd-handle:hover { color: #2ea8e5; background: #fff; } +.dd-item > button { display: block; position: relative; cursor: pointer; float: left; width: 25px; height: 20px; margin: 5px 0; padding: 0; text-indent: 100%; white-space: nowrap; overflow: hidden; border: 0; background: transparent; font-size: 12px; line-height: 1; text-align: center; font-weight: bold; } +.dd-item > button:before { content: '+'; display: block; position: absolute; width: 100%; text-align: center; text-indent: 0; } +.dd-item > button[data-action="collapse"]:before { content: '-'; } +.dd-placeholder, +.dd-empty { margin: 5px 0; padding: 0; min-height: 30px; background: #f2fbff; border: 1px dashed #b6bcbf; box-sizing: border-box; -moz-box-sizing: border-box; } +.dd-empty { border: 1px dashed #bbb; min-height: 100px; background-color: #e5e5e5; + background-image: -webkit-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff), + -webkit-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff); + background-image: -moz-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff), + -moz-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff); + background-image: linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff), + linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff); + background-size: 60px 60px; + background-position: 0 0, 30px 30px; +} +.dd-dragel { position: absolute; pointer-events: none; z-index: 9999; } +.dd-dragel > .dd-item .dd-handle { margin-top: 0; } +.dd-dragel .dd-handle { + -webkit-box-shadow: 2px 4px 6px 0 rgba(0,0,0,.1); + box-shadow: 2px 4px 6px 0 rgba(0,0,0,.1); +} +/** + * Nestable Extras + */ +.nestable-lists { display: block; clear: both; padding: 30px 0; width: 100%; border: 0; border-top: 2px solid #ddd; border-bottom: 2px solid #ddd; } +#nestable-menu { padding: 0; margin: 20px 0; } +#nestable-output, +#nestable2-output { width: 100%; height: 7em; font-size: 0.75em; line-height: 1.333333em; font-family: Consolas, monospace; padding: 5px; box-sizing: border-box; -moz-box-sizing: border-box; } +#nestable2 .dd-handle { + color: #fff; + border: 1px solid #999; + background: #bbb; + background: -webkit-linear-gradient(top, #bbb 0%, #999 100%); + background: -moz-linear-gradient(top, #bbb 0%, #999 100%); + background: linear-gradient(top, #bbb 0%, #999 100%); +} +#nestable2 .dd-handle:hover { background: #bbb; } +#nestable2 .dd-item > button:before { color: #fff; } +@media only screen and (min-width: 700px) { + /*.dd { float: left; width: 48%; }*/ + .dd + .dd { margin-left: 2%; } +} +.dd-hover > .dd-handle { background: #2ea8e5 !important; } +/** + * Nestable Draggable Handles + */ +.dd3-content { display: block; height: 30px; margin: 5px 0; padding: 5px 10px 5px 40px; color: #333; text-decoration: none; font-weight: bold; border: 1px solid #ccc; + background: #fafafa; + background: -webkit-linear-gradient(top, #fafafa 0%, #eee 100%); + background: -moz-linear-gradient(top, #fafafa 0%, #eee 100%); + background: linear-gradient(top, #fafafa 0%, #eee 100%); + -webkit-border-radius: 3px; + border-radius: 3px; + box-sizing: border-box; -moz-box-sizing: border-box; +} +.dd3-content:hover { color: #2ea8e5; background: #fff; } +.dd-dragel > .dd3-item > .dd3-content { margin: 0; } +.dd3-item > button { margin-left: 30px; } +.dd3-handle { position: absolute; margin: 0; left: 0; top: 0; cursor: pointer; width: 30px; text-indent: 100%; white-space: nowrap; overflow: hidden; + border: 1px solid #aaa; + background: #ddd; + background: -webkit-linear-gradient(top, #ddd 0%, #bbb 100%); + background: -moz-linear-gradient(top, #ddd 0%, #bbb 100%); + background: linear-gradient(top, #ddd 0%, #bbb 100%); + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} +.dd3-handle:before { content: '?'; display: block; position: absolute; left: 0; top: 3px; width: 100%; text-align: center; text-indent: 0; color: #fff; font-size: 20px; font-weight: normal; } +.dd3-handle:hover { background: #ddd; } +/** + * Socialite + */ +.socialite { display: block; float: left; height: 35px; } \ No newline at end of file diff --git a/k2shop/usr/k2shop/libs/yaml/Spyc.php b/k2shop/usr/k2shop/libs/yaml/Spyc.php new file mode 100644 index 0000000..f9ba561 --- /dev/null +++ b/k2shop/usr/k2shop/libs/yaml/Spyc.php @@ -0,0 +1,994 @@ + + * @author Chris Wanstrath
+ * $Spyc = new Spyc;
+ * $array = $Spyc->load($file);
+ *
+ * or:
+ *
+ * $array = Spyc::YAMLLoad($file);
+ *
+ * or:
+ *
+ * $array = spyc_load_file($file);
+ *
+ * @package Spyc
+ */
+class Spyc {
+ // SETTINGS
+ const REMPTY = "\0\0\0\0\0";
+ /**
+ * Setting this to true will force YAMLDump to enclose any string value in
+ * quotes. False by default.
+ *
+ * @var bool
+ */
+ public $setting_dump_force_quotes = false;
+ /**
+ * Setting this to true will forse YAMLLoad to use syck_load function when
+ * possible. False by default.
+ * @var bool
+ */
+ public $setting_use_syck_is_possible = false;
+ /**#@+
+ * @access private
+ * @var mixed
+ */
+ private $_dumpIndent;
+ private $_dumpWordWrap;
+ private $_containsGroupAnchor = false;
+ private $_containsGroupAlias = false;
+ private $path;
+ private $result;
+ private $LiteralPlaceHolder = '___YAML_Literal_Block___';
+ private $SavedGroups = array();
+ private $indent;
+ /**
+ * Path modifier that should be applied after adding current element.
+ * @var array
+ */
+ private $delayedPath = array();
+ /**#@+
+ * @access public
+ * @var mixed
+ */
+ public $_nodeId;
+/**
+ * Load a valid YAML string to Spyc.
+ * @param string $input
+ * @return array
+ */
+ public function load ($input) {
+ return $this->_loadString($input);
+ }
+ /**
+ * Load a valid YAML file to Spyc.
+ * @param string $file
+ * @return array
+ */
+ public function loadFile ($file) {
+ return $this->_load($file);
+ }
+ /**
+ * Load YAML into a PHP array statically
+ *
+ * The load method, when supplied with a YAML stream (string or file),
+ * will do its best to convert YAML in a file into a PHP array. Pretty
+ * simple.
+ * Usage:
+ *
+ * $array = Spyc::YAMLLoad('lucky.yaml');
+ * print_r($array);
+ *
+ * @access public
+ * @return array
+ * @param string $input Path of YAML file or string containing YAML
+ */
+ public static function YAMLLoad($input) {
+ $Spyc = new Spyc;
+ return $Spyc->_load($input);
+ }
+ /**
+ * Load a string of YAML into a PHP array statically
+ *
+ * The load method, when supplied with a YAML string, will do its best
+ * to convert YAML in a string into a PHP array. Pretty simple.
+ *
+ * Note: use this function if you don't want files from the file system
+ * loaded and processed as YAML. This is of interest to people concerned
+ * about security whose input is from a string.
+ *
+ * Usage:
+ *
+ * $array = Spyc::YAMLLoadString("---\n0: hello world\n");
+ * print_r($array);
+ *
+ * @access public
+ * @return array
+ * @param string $input String containing YAML
+ */
+ public static function YAMLLoadString($input) {
+ $Spyc = new Spyc;
+ return $Spyc->_loadString($input);
+ }
+ /**
+ * Dump YAML from PHP array statically
+ *
+ * The dump method, when supplied with an array, will do its best
+ * to convert the array into friendly YAML. Pretty simple. Feel free to
+ * save the returned string as nothing.yaml and pass it around.
+ *
+ * Oh, and you can decide how big the indent is and what the wordwrap
+ * for folding is. Pretty cool -- just pass in 'false' for either if
+ * you want to use the default.
+ *
+ * Indent's default is 2 spaces, wordwrap's default is 40 characters. And
+ * you can turn off wordwrap by passing in 0.
+ *
+ * @access public
+ * @return string
+ * @param array|\stdClass $array PHP array
+ * @param int $indent Pass in false to use the default, which is 2
+ * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40)
+ * @param bool $no_opening_dashes Do not start YAML file with "---\n"
+ */
+ public static function YAMLDump($array, $indent = false, $wordwrap = false, $no_opening_dashes = false) {
+ $spyc = new Spyc;
+ return $spyc->dump($array, $indent, $wordwrap, $no_opening_dashes);
+ }
+ /**
+ * Dump PHP array to YAML
+ *
+ * The dump method, when supplied with an array, will do its best
+ * to convert the array into friendly YAML. Pretty simple. Feel free to
+ * save the returned string as tasteful.yaml and pass it around.
+ *
+ * Oh, and you can decide how big the indent is and what the wordwrap
+ * for folding is. Pretty cool -- just pass in 'false' for either if
+ * you want to use the default.
+ *
+ * Indent's default is 2 spaces, wordwrap's default is 40 characters. And
+ * you can turn off wordwrap by passing in 0.
+ *
+ * @access public
+ * @return string
+ * @param array $array PHP array
+ * @param int $indent Pass in false to use the default, which is 2
+ * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40)
+ */
+ public function dump($array,$indent = false,$wordwrap = false, $no_opening_dashes = false) {
+ // Dumps to some very clean YAML. We'll have to add some more features
+ // and options soon. And better support for folding.
+ // New features and options.
+ if ($indent === false or !is_numeric($indent)) {
+ $this->_dumpIndent = 2;
+ } else {
+ $this->_dumpIndent = $indent;
+ }
+ if ($wordwrap === false or !is_numeric($wordwrap)) {
+ $this->_dumpWordWrap = 40;
+ } else {
+ $this->_dumpWordWrap = $wordwrap;
+ }
+ // New YAML document
+ $string = "";
+ if (!$no_opening_dashes) $string = "---\n";
+ // Start at the base of the array and move through it.
+ if ($array) {
+ $array = (array)$array;
+ $previous_key = -1;
+ foreach ($array as $key => $value) {
+ if (!isset($first_key)) $first_key = $key;
+ $string .= $this->_yamlize($key,$value,0,$previous_key, $first_key, $array);
+ $previous_key = $key;
+ }
+ }
+ return $string;
+ }
+ /**
+ * Attempts to convert a key / value array item to YAML
+ * @access private
+ * @return string
+ * @param $key The name of the key
+ * @param $value The value of the item
+ * @param $indent The indent of the current node
+ */
+ private function _yamlize($key,$value,$indent, $previous_key = -1, $first_key = 0, $source_array = null) {
+ if(is_object($value)) $value = (array)$value;
+ if (is_array($value)) {
+ if (empty ($value))
+ return $this->_dumpNode($key, array(), $indent, $previous_key, $first_key, $source_array);
+ // It has children. What to do?
+ // Make it the right kind of item
+ $string = $this->_dumpNode($key, self::REMPTY, $indent, $previous_key, $first_key, $source_array);
+ // Add the indent
+ $indent += $this->_dumpIndent;
+ // Yamlize the array
+ $string .= $this->_yamlizeArray($value,$indent);
+ } elseif (!is_array($value)) {
+ // It doesn't have children. Yip.
+ $string = $this->_dumpNode($key, $value, $indent, $previous_key, $first_key, $source_array);
+ }
+ return $string;
+ }
+ /**
+ * Attempts to convert an array to YAML
+ * @access private
+ * @return string
+ * @param $array The array you want to convert
+ * @param $indent The indent of the current level
+ */
+ private function _yamlizeArray($array,$indent) {
+ if (is_array($array)) {
+ $string = '';
+ $previous_key = -1;
+ foreach ($array as $key => $value) {
+ if (!isset($first_key)) $first_key = $key;
+ $string .= $this->_yamlize($key, $value, $indent, $previous_key, $first_key, $array);
+ $previous_key = $key;
+ }
+ return $string;
+ } else {
+ return false;
+ }
+ }
+ /**
+ * Returns YAML from a key and a value
+ * @access private
+ * @return string
+ * @param $key The name of the key
+ * @param $value The value of the item
+ * @param $indent The indent of the current node
+ */
+ private function _dumpNode($key, $value, $indent, $previous_key = -1, $first_key = 0, $source_array = null) {
+ // do some folding here, for blocks
+ if (is_string ($value) && ((strpos($value,"\n") !== false || strpos($value,": ") !== false || strpos($value,"- ") !== false ||
+ strpos($value,"*") !== false || strpos($value,"#") !== false || strpos($value,"<") !== false || strpos($value,">") !== false || strpos ($value, '%') !== false || strpos ($value, ' ') !== false ||
+ strpos($value,"[") !== false || strpos($value,"]") !== false || strpos($value,"{") !== false || strpos($value,"}") !== false) || strpos($value,"&") !== false || strpos($value, "'") !== false || strpos($value, "!") === 0 ||
+ substr ($value, -1, 1) == ':')
+ ) {
+ $value = $this->_doLiteralBlock($value,$indent);
+ } else {
+ $value = $this->_doFolding($value,$indent);
+ }
+ if ($value === array()) $value = '[ ]';
+ if ($value === "") $value = '""';
+ if (self::isTranslationWord($value)) {
+ $value = $this->_doLiteralBlock($value, $indent);
+ }
+ if (trim ($value) != $value)
+ $value = $this->_doLiteralBlock($value,$indent);
+ if (is_bool($value)) {
+ $value = $value ? "true" : "false";
+ }
+ if ($value === null) $value = 'null';
+ if ($value === "'" . self::REMPTY . "'") $value = null;
+ $spaces = str_repeat(' ',$indent);
+ //if (is_int($key) && $key - 1 == $previous_key && $first_key===0) {
+ if (is_array ($source_array) && array_keys($source_array) === range(0, count($source_array) - 1)) {
+ // It's a sequence
+ $string = $spaces.'- '.$value."\n";
+ } else {
+ // if ($first_key===0) throw new Exception('Keys are all screwy. The first one was zero, now it\'s "'. $key .'"');
+ // It's mapped
+ if (strpos($key, ":") !== false || strpos($key, "#") !== false) { $key = '"' . $key . '"'; }
+ $string = rtrim ($spaces.$key.': '.$value)."\n";
+ }
+ return $string;
+ }
+ /**
+ * Creates a literal block for dumping
+ * @access private
+ * @return string
+ * @param $value
+ * @param $indent int The value of the indent
+ */
+ private function _doLiteralBlock($value,$indent) {
+ if ($value === "\n") return '\n';
+ if (strpos($value, "\n") === false && strpos($value, "'") === false) {
+ return sprintf ("'%s'", $value);
+ }
+ if (strpos($value, "\n") === false && strpos($value, '"') === false) {
+ return sprintf ('"%s"', $value);
+ }
+ $exploded = explode("\n",$value);
+ $newValue = '|';
+ if (isset($exploded[0]) && ($exploded[0] == "|" || $exploded[0] == "|-" || $exploded[0] == ">")) {
+ $newValue = $exploded[0];
+ unset($exploded[0]);
+ }
+ $indent += $this->_dumpIndent;
+ $spaces = str_repeat(' ',$indent);
+ foreach ($exploded as $line) {
+ $line = trim($line);
+ if (strpos($line, '"') === 0 && strrpos($line, '"') == (strlen($line)-1) || strpos($line, "'") === 0 && strrpos($line, "'") == (strlen($line)-1)) {
+ $line = substr($line, 1, -1);
+ }
+ $newValue .= "\n" . $spaces . ($line);
+ }
+ return $newValue;
+ }
+ /**
+ * Folds a string of text, if necessary
+ * @access private
+ * @return string
+ * @param $value The string you wish to fold
+ */
+ private function _doFolding($value,$indent) {
+ // Don't do anything if wordwrap is set to 0
+ if ($this->_dumpWordWrap !== 0 && is_string ($value) && strlen($value) > $this->_dumpWordWrap) {
+ $indent += $this->_dumpIndent;
+ $indent = str_repeat(' ',$indent);
+ $wrapped = wordwrap($value,$this->_dumpWordWrap,"\n$indent");
+ $value = ">\n".$indent.$wrapped;
+ } else {
+ if ($this->setting_dump_force_quotes && is_string ($value) && $value !== self::REMPTY)
+ $value = '"' . $value . '"';
+ if (is_numeric($value) && is_string($value))
+ $value = '"' . $value . '"';
+ }
+ return $value;
+ }
+ private function isTrueWord($value) {
+ $words = self::getTranslations(array('true', 'on', 'yes', 'y'));
+ return in_array($value, $words, true);
+ }
+ private function isFalseWord($value) {
+ $words = self::getTranslations(array('false', 'off', 'no', 'n'));
+ return in_array($value, $words, true);
+ }
+ private function isNullWord($value) {
+ $words = self::getTranslations(array('null', '~'));
+ return in_array($value, $words, true);
+ }
+ private function isTranslationWord($value) {
+ return (
+ self::isTrueWord($value) ||
+ self::isFalseWord($value) ||
+ self::isNullWord($value)
+ );
+ }
+ /**
+ * Coerce a string into a native type
+ * Reference: http://yaml.org/type/bool.html
+ * TODO: Use only words from the YAML spec.
+ * @access private
+ * @param $value The value to coerce
+ */
+ private function coerceValue(&$value) {
+ if (self::isTrueWord($value)) {
+ $value = true;
+ } else if (self::isFalseWord($value)) {
+ $value = false;
+ } else if (self::isNullWord($value)) {
+ $value = null;
+ }
+ }
+ /**
+ * Given a set of words, perform the appropriate translations on them to
+ * match the YAML 1.1 specification for type coercing.
+ * @param $words The words to translate
+ * @access private
+ */
+ private static function getTranslations(array $words) {
+ $result = array();
+ foreach ($words as $i) {
+ $result = array_merge($result, array(ucfirst($i), strtoupper($i), strtolower($i)));
+ }
+ return $result;
+ }
+// LOADING FUNCTIONS
+ private function _load($input) {
+ $Source = $this->loadFromSource($input);
+ return $this->loadWithSource($Source);
+ }
+ private function _loadString($input) {
+ $Source = $this->loadFromString($input);
+ return $this->loadWithSource($Source);
+ }
+ private function loadWithSource($Source) {
+ if (empty ($Source)) return array();
+ if ($this->setting_use_syck_is_possible && function_exists ('syck_load')) {
+ $array = syck_load (implode ("\n", $Source));
+ return is_array($array) ? $array : array();
+ }
+ $this->path = array();
+ $this->result = array();
+ $cnt = count($Source);
+ for ($i = 0; $i < $cnt; $i++) {
+ $line = $Source[$i];
+ $this->indent = strlen($line) - strlen(ltrim($line));
+ $tempPath = $this->getParentPathByIndent($this->indent);
+ $line = self::stripIndent($line, $this->indent);
+ if (self::isComment($line)) continue;
+ if (self::isEmpty($line)) continue;
+ $this->path = $tempPath;
+ $literalBlockStyle = self::startsLiteralBlock($line);
+ if ($literalBlockStyle) {
+ $line = rtrim ($line, $literalBlockStyle . " \n");
+ $literalBlock = '';
+ $line .= ' '.$this->LiteralPlaceHolder;
+ $literal_block_indent = strlen($Source[$i+1]) - strlen(ltrim($Source[$i+1]));
+ while (++$i < $cnt && $this->literalBlockContinues($Source[$i], $this->indent)) {
+ $literalBlock = $this->addLiteralLine($literalBlock, $Source[$i], $literalBlockStyle, $literal_block_indent);
+ }
+ $i--;
+ }
+ // Strip out comments
+ if (strpos ($line, '#')) {
+ $line = preg_replace('/\s*#([^"\']+)$/','',$line);
+ }
+ while (++$i < $cnt && self::greedilyNeedNextLine($line)) {
+ $line = rtrim ($line, " \n\t\r") . ' ' . ltrim ($Source[$i], " \t");
+ }
+ $i--;
+ $lineArray = $this->_parseLine($line);
+ if ($literalBlockStyle)
+ $lineArray = $this->revertLiteralPlaceHolder ($lineArray, $literalBlock);
+ $this->addArray($lineArray, $this->indent);
+ foreach ($this->delayedPath as $indent => $delayedPath)
+ $this->path[$indent] = $delayedPath;
+ $this->delayedPath = array();
+ }
+ return $this->result;
+ }
+ private function loadFromSource ($input) {
+ if (!empty($input) && strpos($input, "\n") === false && file_exists($input))
+ $input = file_get_contents($input);
+ return $this->loadFromString($input);
+ }
+ private function loadFromString ($input) {
+ $lines = explode("\n",$input);
+ foreach ($lines as $k => $_) {
+ $lines[$k] = rtrim ($_, "\r");
+ }
+ return $lines;
+ }
+ /**
+ * Parses YAML code and returns an array for a node
+ * @access private
+ * @return array
+ * @param string $line A line from the YAML file
+ */
+ private function _parseLine($line) {
+ if (!$line) return array();
+ $line = trim($line);
+ if (!$line) return array();
+ $array = array();
+ $group = $this->nodeContainsGroup($line);
+ if ($group) {
+ $this->addGroup($line, $group);
+ $line = $this->stripGroup ($line, $group);
+ }
+ if ($this->startsMappedSequence($line))
+ return $this->returnMappedSequence($line);
+ if ($this->startsMappedValue($line))
+ return $this->returnMappedValue($line);
+ if ($this->isArrayElement($line))
+ return $this->returnArrayElement($line);
+ if ($this->isPlainArray($line))
+ return $this->returnPlainArray($line);
+ return $this->returnKeyValuePair($line);
+ }
+ /**
+ * Finds the type of the passed value, returns the value as the new type.
+ * @access private
+ * @param string $value
+ * @return mixed
+ */
+ private function _toType($value) {
+ if ($value === '') return "";
+ $first_character = $value[0];
+ $last_character = substr($value, -1, 1);
+ $is_quoted = false;
+ do {
+ if (!$value) break;
+ if ($first_character != '"' && $first_character != "'") break;
+ if ($last_character != '"' && $last_character != "'") break;
+ $is_quoted = true;
+ } while (0);
+ if ($is_quoted) {
+ $value = str_replace('\n', "\n", $value);
+ if ($first_character == "'")
+ return strtr(substr ($value, 1, -1), array ('\'\'' => '\'', '\\\''=> '\''));
+ return strtr(substr ($value, 1, -1), array ('\\"' => '"', '\\\''=> '\''));
+ }
+ if (strpos($value, ' #') !== false && !$is_quoted)
+ $value = preg_replace('/\s+#(.+)$/','',$value);
+ if ($first_character == '[' && $last_character == ']') {
+ // Take out strings sequences and mappings
+ $innerValue = trim(substr ($value, 1, -1));
+ if ($innerValue === '') return array();
+ $explode = $this->_inlineEscape($innerValue);
+ // Propagate value array
+ $value = array();
+ foreach ($explode as $v) {
+ $value[] = $this->_toType($v);
+ }
+ return $value;
+ }
+ if (strpos($value,': ')!==false && $first_character != '{') {
+ $array = explode(': ',$value);
+ $key = trim($array[0]);
+ array_shift($array);
+ $value = trim(implode(': ',$array));
+ $value = $this->_toType($value);
+ return array($key => $value);
+ }
+ if ($first_character == '{' && $last_character == '}') {
+ $innerValue = trim(substr ($value, 1, -1));
+ if ($innerValue === '') return array();
+ // Inline Mapping
+ // Take out strings sequences and mappings
+ $explode = $this->_inlineEscape($innerValue);
+ // Propagate value array
+ $array = array();
+ foreach ($explode as $v) {
+ $SubArr = $this->_toType($v);
+ if (empty($SubArr)) continue;
+ if (is_array ($SubArr)) {
+ $array[key($SubArr)] = $SubArr[key($SubArr)]; continue;
+ }
+ $array[] = $SubArr;
+ }
+ return $array;
+ }
+ if ($value == 'null' || $value == 'NULL' || $value == 'Null' || $value == '' || $value == '~') {
+ return null;
+ }
+ if ( is_numeric($value) && preg_match ('/^(-|)[1-9]+[0-9]*$/', $value) ){
+ $intvalue = (int)$value;
+ if ($intvalue != PHP_INT_MAX && $intvalue != ~PHP_INT_MAX)
+ $value = $intvalue;
+ return $value;
+ }
+ if ( is_string($value) && preg_match('/^0[xX][0-9a-fA-F]+$/', $value)) {
+ // Hexadecimal value.
+ return hexdec($value);
+ }
+ $this->coerceValue($value);
+ if (is_numeric($value)) {
+ if ($value === '0') return 0;
+ if (rtrim ($value, 0) === $value)
+ $value = (float)$value;
+ return $value;
+ }
+ return $value;
+ }
+ /**
+ * Used in inlines to check for more inlines or quoted strings
+ * @access private
+ * @return array
+ */
+ private function _inlineEscape($inline) {
+ // There's gotta be a cleaner way to do this...
+ // While pure sequences seem to be nesting just fine,
+ // pure mappings and mappings with sequences inside can't go very
+ // deep. This needs to be fixed.
+ $seqs = array();
+ $maps = array();
+ $saved_strings = array();
+ $saved_empties = array();
+ // Check for empty strings
+ $regex = '/("")|(\'\')/';
+ if (preg_match_all($regex,$inline,$strings)) {
+ $saved_empties = $strings[0];
+ $inline = preg_replace($regex,'YAMLEmpty',$inline);
+ }
+ unset($regex);
+ // Check for strings
+ $regex = '/(?:(")|(?:\'))((?(1)[^"]+|[^\']+))(?(1)"|\')/';
+ if (preg_match_all($regex,$inline,$strings)) {
+ $saved_strings = $strings[0];
+ $inline = preg_replace($regex,'YAMLString',$inline);
+ }
+ unset($regex);
+ // echo $inline;
+ $i = 0;
+ do {
+ // Check for sequences
+ while (preg_match('/\[([^{}\[\]]+)\]/U',$inline,$matchseqs)) {
+ $seqs[] = $matchseqs[0];
+ $inline = preg_replace('/\[([^{}\[\]]+)\]/U', ('YAMLSeq' . (count($seqs) - 1) . 's'), $inline, 1);
+ }
+ // Check for mappings
+ while (preg_match('/{([^\[\]{}]+)}/U',$inline,$matchmaps)) {
+ $maps[] = $matchmaps[0];
+ $inline = preg_replace('/{([^\[\]{}]+)}/U', ('YAMLMap' . (count($maps) - 1) . 's'), $inline, 1);
+ }
+ if ($i++ >= 10) break;
+ } while (strpos ($inline, '[') !== false || strpos ($inline, '{') !== false);
+ $explode = explode(',',$inline);
+ $explode = array_map('trim', $explode);
+ $stringi = 0; $i = 0;
+ while (1) {
+ // Re-add the sequences
+ if (!empty($seqs)) {
+ foreach ($explode as $key => $value) {
+ if (strpos($value,'YAMLSeq') !== false) {
+ foreach ($seqs as $seqk => $seq) {
+ $explode[$key] = str_replace(('YAMLSeq'.$seqk.'s'),$seq,$value);
+ $value = $explode[$key];
+ }
+ }
+ }
+ }
+ // Re-add the mappings
+ if (!empty($maps)) {
+ foreach ($explode as $key => $value) {
+ if (strpos($value,'YAMLMap') !== false) {
+ foreach ($maps as $mapk => $map) {
+ $explode[$key] = str_replace(('YAMLMap'.$mapk.'s'), $map, $value);
+ $value = $explode[$key];
+ }
+ }
+ }
+ }
+ // Re-add the strings
+ if (!empty($saved_strings)) {
+ foreach ($explode as $key => $value) {
+ while (strpos($value,'YAMLString') !== false) {
+ $explode[$key] = preg_replace('/YAMLString/',$saved_strings[$stringi],$value, 1);
+ unset($saved_strings[$stringi]);
+ ++$stringi;
+ $value = $explode[$key];
+ }
+ }
+ }
+ // Re-add the empties
+ if (!empty($saved_empties)) {
+ foreach ($explode as $key => $value) {
+ while (strpos($value,'YAMLEmpty') !== false) {
+ $explode[$key] = preg_replace('/YAMLEmpty/', '', $value, 1);
+ $value = $explode[$key];
+ }
+ }
+ }
+ $finished = true;
+ foreach ($explode as $key => $value) {
+ if (strpos($value,'YAMLSeq') !== false) {
+ $finished = false; break;
+ }
+ if (strpos($value,'YAMLMap') !== false) {
+ $finished = false; break;
+ }
+ if (strpos($value,'YAMLString') !== false) {
+ $finished = false; break;
+ }
+ if (strpos($value,'YAMLEmpty') !== false) {
+ $finished = false; break;
+ }
+ }
+ if ($finished) break;
+ $i++;
+ if ($i > 10)
+ break; // Prevent infinite loops.
+ }
+ return $explode;
+ }
+ private function literalBlockContinues ($line, $lineIndent) {
+ if (!trim($line)) return true;
+ if (strlen($line) - strlen(ltrim($line)) > $lineIndent) return true;
+ return false;
+ }
+ private function referenceContentsByAlias ($alias) {
+ do {
+ if (!isset($this->SavedGroups[$alias])) { echo "Bad group name: $alias."; break; }
+ $groupPath = $this->SavedGroups[$alias];
+ $value = $this->result;
+ foreach ($groupPath as $k) {
+ $value = $value[$k];
+ }
+ } while (false);
+ return $value;
+ }
+ private function addArrayInline ($array, $indent) {
+ $CommonGroupPath = $this->path;
+ if (empty ($array)) return false;
+ foreach ($array as $k => $_) {
+ $this->addArray(array($k => $_), $indent);
+ $this->path = $CommonGroupPath;
+ }
+ return true;
+ }
+ private function addArray ($incoming_data, $incoming_indent) {
+ // print_r ($incoming_data);
+ if (count ($incoming_data) > 1)
+ return $this->addArrayInline ($incoming_data, $incoming_indent);
+ $key = key ($incoming_data);
+ $value = isset($incoming_data[$key]) ? $incoming_data[$key] : null;
+ if ($key === '__!YAMLZero') $key = '0';
+ if ($incoming_indent == 0 && !$this->_containsGroupAlias && !$this->_containsGroupAnchor) { // Shortcut for root-level values.
+ if ($key || $key === '' || $key === '0') {
+ $this->result[$key] = $value;
+ } else {
+ $this->result[] = $value; end ($this->result); $key = key ($this->result);
+ }
+ $this->path[$incoming_indent] = $key;
+ return;
+ }
+ $history = array();
+ // Unfolding inner array tree.
+ $history[] = $_arr = $this->result;
+ foreach ($this->path as $k) {
+ $history[] = $_arr = $_arr[$k];
+ }
+ if ($this->_containsGroupAlias) {
+ $value = $this->referenceContentsByAlias($this->_containsGroupAlias);
+ $this->_containsGroupAlias = false;
+ }
+ // Adding string or numeric key to the innermost level or $this->arr.
+ if (is_string($key) && $key == '<<') {
+ if (!is_array ($_arr)) { $_arr = array (); }
+ $_arr = array_merge ($_arr, $value);
+ } else if ($key || $key === '' || $key === '0') {
+ if (!is_array ($_arr))
+ $_arr = array ($key=>$value);
+ else
+ $_arr[$key] = $value;
+ } else {
+ if (!is_array ($_arr)) { $_arr = array ($value); $key = 0; }
+ else { $_arr[] = $value; end ($_arr); $key = key ($_arr); }
+ }
+ $reverse_path = array_reverse($this->path);
+ $reverse_history = array_reverse ($history);
+ $reverse_history[0] = $_arr;
+ $cnt = count($reverse_history) - 1;
+ for ($i = 0; $i < $cnt; $i++) {
+ $reverse_history[$i+1][$reverse_path[$i]] = $reverse_history[$i];
+ }
+ $this->result = $reverse_history[$cnt];
+ $this->path[$incoming_indent] = $key;
+ if ($this->_containsGroupAnchor) {
+ $this->SavedGroups[$this->_containsGroupAnchor] = $this->path;
+ if (is_array ($value)) {
+ $k = key ($value);
+ if (!is_int ($k)) {
+ $this->SavedGroups[$this->_containsGroupAnchor][$incoming_indent + 2] = $k;
+ }
+ }
+ $this->_containsGroupAnchor = false;
+ }
+ }
+ private static function startsLiteralBlock ($line) {
+ $lastChar = substr (trim($line), -1);
+ if ($lastChar != '>' && $lastChar != '|') return false;
+ if ($lastChar == '|') return $lastChar;
+ // HTML tags should not be counted as literal blocks.
+ if (preg_match ('#<.*?>$#', $line)) return false;
+ return $lastChar;
+ }
+ private static function greedilyNeedNextLine($line) {
+ $line = trim ($line);
+ if (!strlen($line)) return false;
+ if (substr ($line, -1, 1) == ']') return false;
+ if ($line[0] == '[') return true;
+ if (preg_match ('#^[^:]+?:\s*\[#', $line)) return true;
+ return false;
+ }
+ private function addLiteralLine ($literalBlock, $line, $literalBlockStyle, $indent = -1) {
+ $line = self::stripIndent($line, $indent);
+ if ($literalBlockStyle !== '|') {
+ $line = self::stripIndent($line);
+ }
+ $line = rtrim ($line, "\r\n\t ") . "\n";
+ if ($literalBlockStyle == '|') {
+ return $literalBlock . $line;
+ }
+ if (strlen($line) == 0)
+ return rtrim($literalBlock, ' ') . "\n";
+ if ($line == "\n" && $literalBlockStyle == '>') {
+ return rtrim ($literalBlock, " \t") . "\n";
+ }
+ if ($line != "\n")
+ $line = trim ($line, "\r\n ") . " ";
+ return $literalBlock . $line;
+ }
+ function revertLiteralPlaceHolder ($lineArray, $literalBlock) {
+ foreach ($lineArray as $k => $_) {
+ if (is_array($_))
+ $lineArray[$k] = $this->revertLiteralPlaceHolder ($_, $literalBlock);
+ else if (substr($_, -1 * strlen ($this->LiteralPlaceHolder)) == $this->LiteralPlaceHolder)
+ $lineArray[$k] = rtrim ($literalBlock, " \r\n");
+ }
+ return $lineArray;
+ }
+ private static function stripIndent ($line, $indent = -1) {
+ if ($indent == -1) $indent = strlen($line) - strlen(ltrim($line));
+ return substr ($line, $indent);
+ }
+ private function getParentPathByIndent ($indent) {
+ if ($indent == 0) return array();
+ $linePath = $this->path;
+ do {
+ end($linePath); $lastIndentInParentPath = key($linePath);
+ if ($indent <= $lastIndentInParentPath) array_pop ($linePath);
+ } while ($indent <= $lastIndentInParentPath);
+ return $linePath;
+ }
+ private function clearBiggerPathValues ($indent) {
+ if ($indent == 0) $this->path = array();
+ if (empty ($this->path)) return true;
+ foreach ($this->path as $k => $_) {
+ if ($k > $indent) unset ($this->path[$k]);
+ }
+ return true;
+ }
+ private static function isComment ($line) {
+ if (!$line) return false;
+ if ($line[0] == '#') return true;
+ if (trim($line, " \r\n\t") == '---') return true;
+ return false;
+ }
+ private static function isEmpty ($line) {
+ return (trim ($line) === '');
+ }
+ private function isArrayElement ($line) {
+ if (!$line || !is_scalar($line)) return false;
+ if (substr($line, 0, 2) != '- ') return false;
+ if (strlen ($line) > 3)
+ if (substr($line,0,3) == '---') return false;
+ return true;
+ }
+ private function isHashElement ($line) {
+ return strpos($line, ':');
+ }
+ private function isLiteral ($line) {
+ if ($this->isArrayElement($line)) return false;
+ if ($this->isHashElement($line)) return false;
+ return true;
+ }
+ private static function unquote ($value) {
+ if (!$value) return $value;
+ if (!is_string($value)) return $value;
+ if ($value[0] == '\'') return trim ($value, '\'');
+ if ($value[0] == '"') return trim ($value, '"');
+ return $value;
+ }
+ private function startsMappedSequence ($line) {
+ return (substr($line, 0, 2) == '- ' && substr ($line, -1, 1) == ':');
+ }
+ private function returnMappedSequence ($line) {
+ $array = array();
+ $key = self::unquote(trim(substr($line,1,-1)));
+ $array[$key] = array();
+ $this->delayedPath = array(strpos ($line, $key) + $this->indent => $key);
+ return array($array);
+ }
+ private function checkKeysInValue($value) {
+ if (strchr('[{"\'', $value[0]) === false) {
+ if (strchr($value, ': ') !== false) {
+ throw new Exception('Too many keys: '.$value);
+ }
+ }
+ }
+ private function returnMappedValue ($line) {
+ $this->checkKeysInValue($line);
+ $array = array();
+ $key = self::unquote (trim(substr($line,0,-1)));
+ $array[$key] = '';
+ return $array;
+ }
+ private function startsMappedValue ($line) {
+ return (substr ($line, -1, 1) == ':');
+ }
+ private function isPlainArray ($line) {
+ return ($line[0] == '[' && substr ($line, -1, 1) == ']');
+ }
+ private function returnPlainArray ($line) {
+ return $this->_toType($line);
+ }
+ private function returnKeyValuePair ($line) {
+ $array = array();
+ $key = '';
+ if (strpos ($line, ': ')) {
+ // It's a key/value pair most likely
+ // If the key is in double quotes pull it out
+ if (($line[0] == '"' || $line[0] == "'") && preg_match('/^(["\'](.*)["\'](\s)*:)/',$line,$matches)) {
+ $value = trim(str_replace($matches[1],'',$line));
+ $key = $matches[2];
+ } else {
+ // Do some guesswork as to the key and the value
+ $explode = explode(': ', $line);
+ $key = trim(array_shift($explode));
+ $value = trim(implode(': ', $explode));
+ $this->checkKeysInValue($value);
+ }
+ // Set the type of the value. Int, string, etc
+ $value = $this->_toType($value);
+ if ($key === '0') $key = '__!YAMLZero';
+ $array[$key] = $value;
+ } else {
+ $array = array ($line);
+ }
+ return $array;
+ }
+ private function returnArrayElement ($line) {
+ if (strlen($line) <= 1) return array(array()); // Weird %)
+ $array = array();
+ $value = trim(substr($line,1));
+ $value = $this->_toType($value);
+ if ($this->isArrayElement($value)) {
+ $value = $this->returnArrayElement($value);
+ }
+ $array[] = $value;
+ return $array;
+ }
+ private function nodeContainsGroup ($line) {
+ $symbolsForReference = 'A-z0-9_\-';
+ if (strpos($line, '&') === false && strpos($line, '*') === false) return false; // Please die fast ;-)
+ if ($line[0] == '&' && preg_match('/^(&['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1];
+ if ($line[0] == '*' && preg_match('/^(\*['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1];
+ if (preg_match('/(&['.$symbolsForReference.']+)$/', $line, $matches)) return $matches[1];
+ if (preg_match('/(\*['.$symbolsForReference.']+$)/', $line, $matches)) return $matches[1];
+ if (preg_match ('#^\s*<<\s*:\s*(\*[^\s]+).*$#', $line, $matches)) return $matches[1];
+ return false;
+ }
+ private function addGroup ($line, $group) {
+ if ($group[0] == '&') $this->_containsGroupAnchor = substr ($group, 1);
+ if ($group[0] == '*') $this->_containsGroupAlias = substr ($group, 1);
+ //print_r ($this->path);
+ }
+ private function stripGroup ($line, $group) {
+ $line = trim(str_replace($group, '', $line));
+ return $line;
+ }
+}
+}
+// Enable use of Spyc from command line
+// The syntax is the following: php Spyc.php spyc.yaml
+do {
+ if (PHP_SAPI != 'cli') break;
+ if (empty ($_SERVER['argc']) || $_SERVER['argc'] < 2) break;
+ if (empty ($_SERVER['PHP_SELF']) || FALSE === strpos ($_SERVER['PHP_SELF'], 'Spyc.php') ) break;
+ $file = $argv[1];
+ echo json_encode (spyc_load_file ($file));
+} while (0);
\ No newline at end of file