Commit fb724c0b7f08e51d20d11ba1f06c9b4b2bdab75c

Authored by renz78
1 parent 94c48719ea
Exists in master

test

Showing 9 changed files with 3795 additions and 0 deletions Inline Diff

k2shop/usr/k2shop/libs/browser/Browser.php
File was created 1 <?php
2
3 /**
4 * File: Browser.php
5 * Author: Chris Schuld (http://chrisschuld.com/)
6 * Last Modified: July 22nd, 2016
7 * @version 2.0
8 * @package PegasusPHP
9 *
10 * Copyright (C) 2008-2010 Chris Schuld (chris@chrisschuld.com)
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License as
14 * published by the Free Software Foundation; either version 2 of
15 * the License, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details at:
21 * http://www.gnu.org/copyleft/gpl.html
22 *
23 *
24 * Typical Usage:
25 *
26 * $browser = new Browser();
27 * if( $browser->getBrowser() == Browser::BROWSER_FIREFOX && $browser->getVersion() >= 2 ) {
28 * echo 'You have FireFox version 2 or greater';
29 * }
30 *
31 * User Agents Sampled from: http://www.useragentstring.com/
32 *
33 * This implementation is based on the original work from Gary White
34 * http://apptools.com/phptools/browser/
35 *
36 */
37 class Browser
38 {
39 private $_agent = '';
40 private $_browser_name = '';
41 private $_version = '';
42 private $_platform = '';
43 private $_os = '';
44 private $_is_aol = false;
45 private $_is_mobile = false;
46 private $_is_tablet = false;
47 private $_is_robot = false;
48 private $_is_facebook = false;
49 private $_aol_version = '';
50
51 const BROWSER_UNKNOWN = 'unknown';
52 const VERSION_UNKNOWN = 'unknown';
53
54 const BROWSER_OPERA = 'Opera'; // http://www.opera.com/
55 const BROWSER_OPERA_MINI = 'Opera Mini'; // http://www.opera.com/mini/
56 const BROWSER_WEBTV = 'WebTV'; // http://www.webtv.net/pc/
57 const BROWSER_EDGE = 'Edge'; // https://www.microsoft.com/edge
58 const BROWSER_IE = 'Internet Explorer'; // http://www.microsoft.com/ie/
59 const BROWSER_POCKET_IE = 'Pocket Internet Explorer'; // http://en.wikipedia.org/wiki/Internet_Explorer_Mobile
60 const BROWSER_KONQUEROR = 'Konqueror'; // http://www.konqueror.org/
61 const BROWSER_ICAB = 'iCab'; // http://www.icab.de/
62 const BROWSER_OMNIWEB = 'OmniWeb'; // http://www.omnigroup.com/applications/omniweb/
63 const BROWSER_FIREBIRD = 'Firebird'; // http://www.ibphoenix.com/
64 const BROWSER_FIREFOX = 'Firefox'; // http://www.mozilla.com/en-US/firefox/firefox.html
65 const BROWSER_ICEWEASEL = 'Iceweasel'; // http://www.geticeweasel.org/
66 const BROWSER_SHIRETOKO = 'Shiretoko'; // http://wiki.mozilla.org/Projects/shiretoko
67 const BROWSER_MOZILLA = 'Mozilla'; // http://www.mozilla.com/en-US/
68 const BROWSER_AMAYA = 'Amaya'; // http://www.w3.org/Amaya/
69 const BROWSER_LYNX = 'Lynx'; // http://en.wikipedia.org/wiki/Lynx
70 const BROWSER_SAFARI = 'Safari'; // http://apple.com
71 const BROWSER_IPHONE = 'iPhone'; // http://apple.com
72 const BROWSER_IPOD = 'iPod'; // http://apple.com
73 const BROWSER_IPAD = 'iPad'; // http://apple.com
74 const BROWSER_CHROME = 'Chrome'; // http://www.google.com/chrome
75 const BROWSER_ANDROID = 'Android'; // http://www.android.com/
76 const BROWSER_GOOGLEBOT = 'GoogleBot'; // http://en.wikipedia.org/wiki/Googlebot
77
78 const BROWSER_YANDEXBOT = 'YandexBot'; // http://yandex.com/bots
79 const BROWSER_YANDEXIMAGERESIZER_BOT = 'YandexImageResizer'; // http://yandex.com/bots
80 const BROWSER_YANDEXIMAGES_BOT = 'YandexImages'; // http://yandex.com/bots
81 const BROWSER_YANDEXVIDEO_BOT = 'YandexVideo'; // http://yandex.com/bots
82 const BROWSER_YANDEXMEDIA_BOT = 'YandexMedia'; // http://yandex.com/bots
83 const BROWSER_YANDEXBLOGS_BOT = 'YandexBlogs'; // http://yandex.com/bots
84 const BROWSER_YANDEXFAVICONS_BOT = 'YandexFavicons'; // http://yandex.com/bots
85 const BROWSER_YANDEXWEBMASTER_BOT = 'YandexWebmaster'; // http://yandex.com/bots
86 const BROWSER_YANDEXDIRECT_BOT = 'YandexDirect'; // http://yandex.com/bots
87 const BROWSER_YANDEXMETRIKA_BOT = 'YandexMetrika'; // http://yandex.com/bots
88 const BROWSER_YANDEXNEWS_BOT = 'YandexNews'; // http://yandex.com/bots
89 const BROWSER_YANDEXCATALOG_BOT = 'YandexCatalog'; // http://yandex.com/bots
90
91 const BROWSER_SLURP = 'Yahoo! Slurp'; // http://en.wikipedia.org/wiki/Yahoo!_Slurp
92 const BROWSER_W3CVALIDATOR = 'W3C Validator'; // http://validator.w3.org/
93 const BROWSER_BLACKBERRY = 'BlackBerry'; // http://www.blackberry.com/
94 const BROWSER_ICECAT = 'IceCat'; // http://en.wikipedia.org/wiki/GNU_IceCat
95 const BROWSER_NOKIA_S60 = 'Nokia S60 OSS Browser'; // http://en.wikipedia.org/wiki/Web_Browser_for_S60
96 const BROWSER_NOKIA = 'Nokia Browser'; // * all other WAP-based browsers on the Nokia Platform
97 const BROWSER_MSN = 'MSN Browser'; // http://explorer.msn.com/
98 const BROWSER_MSNBOT = 'MSN Bot'; // http://search.msn.com/msnbot.htm
99 const BROWSER_BINGBOT = 'Bing Bot'; // http://en.wikipedia.org/wiki/Bingbot
100 const BROWSER_VIVALDI = 'Vivalidi'; // https://vivaldi.com/
101 const BROWSER_YANDEX = 'Yandex'; // https://browser.yandex.ua/
102
103 const BROWSER_NETSCAPE_NAVIGATOR = 'Netscape Navigator'; // http://browser.netscape.com/ (DEPRECATED)
104 const BROWSER_GALEON = 'Galeon'; // http://galeon.sourceforge.net/ (DEPRECATED)
105 const BROWSER_NETPOSITIVE = 'NetPositive'; // http://en.wikipedia.org/wiki/NetPositive (DEPRECATED)
106 const BROWSER_PHOENIX = 'Phoenix'; // http://en.wikipedia.org/wiki/History_of_Mozilla_Firefox (DEPRECATED)
107 const BROWSER_PLAYSTATION = "PlayStation";
108 const BROWSER_SAMSUNG = "SamsungBrowser";
109 const BROWSER_SILK = "Silk";
110 const BROWSER_I_FRAME = "Iframely";
111 const BROWSER_COCOA = "CocoaRestClient";
112
113 const PLATFORM_UNKNOWN = 'unknown';
114 const PLATFORM_WINDOWS = 'Windows';
115 const PLATFORM_WINDOWS_CE = 'Windows CE';
116 const PLATFORM_APPLE = 'Apple';
117 const PLATFORM_LINUX = 'Linux';
118 const PLATFORM_OS2 = 'OS/2';
119 const PLATFORM_BEOS = 'BeOS';
120 const PLATFORM_IPHONE = 'iPhone';
121 const PLATFORM_IPOD = 'iPod';
122 const PLATFORM_IPAD = 'iPad';
123 const PLATFORM_BLACKBERRY = 'BlackBerry';
124 const PLATFORM_NOKIA = 'Nokia';
125 const PLATFORM_FREEBSD = 'FreeBSD';
126 const PLATFORM_OPENBSD = 'OpenBSD';
127 const PLATFORM_NETBSD = 'NetBSD';
128 const PLATFORM_SUNOS = 'SunOS';
129 const PLATFORM_OPENSOLARIS = 'OpenSolaris';
130 const PLATFORM_ANDROID = 'Android';
131 const PLATFORM_PLAYSTATION = "Sony PlayStation";
132 const PLATFORM_ROKU = "Roku";
133 const PLATFORM_APPLE_TV = "Apple TV";
134 const PLATFORM_TERMINAL = "Terminal";
135 const PLATFORM_FIRE_OS = "Fire OS";
136 const PLATFORM_SMART_TV = "SMART-TV";
137 const PLATFORM_CHROME_OS = "Chrome OS";
138 const PLATFORM_JAVA_ANDROID = "Java/Android";
139 const PLATFORM_POSTMAN = "Postman";
140 const PLATFORM_I_FRAME = "Iframely";
141
142 const OPERATING_SYSTEM_UNKNOWN = 'unknown';
143
144 /**
145 * Class constructor
146 */
147 public function __construct($userAgent = "")
148 {
149 $this->reset();
150 if ($userAgent != "") {
151 $this->setUserAgent($userAgent);
152 } else {
153 $this->determine();
154 }
155 }
156
157 /**
158 * Reset all properties
159 */
160 public function reset()
161 {
162 $this->_agent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : "";
163 $this->_browser_name = self::BROWSER_UNKNOWN;
164 $this->_version = self::VERSION_UNKNOWN;
165 $this->_platform = self::PLATFORM_UNKNOWN;
166 $this->_os = self::OPERATING_SYSTEM_UNKNOWN;
167 $this->_is_aol = false;
168 $this->_is_mobile = false;
169 $this->_is_tablet = false;
170 $this->_is_robot = false;
171 $this->_is_facebook = false;
172 $this->_aol_version = self::VERSION_UNKNOWN;
173 }
174
175 /**
176 * Check to see if the specific browser is valid
177 * @param string $browserName
178 * @return bool True if the browser is the specified browser
179 */
180 function isBrowser($browserName)
181 {
182 return (0 == strcasecmp($this->_browser_name, trim($browserName)));
183 }
184
185 /**
186 * The name of the browser. All return types are from the class contants
187 * @return string Name of the browser
188 */
189 public function getBrowser()
190 {
191 return $this->_browser_name;
192 }
193
194 /**
195 * Set the name of the browser
196 * @param $browser string The name of the Browser
197 */
198 public function setBrowser($browser)
199 {
200 $this->_browser_name = $browser;
201 }
202
203 /**
204 * The name of the platform. All return types are from the class contants
205 * @return string Name of the browser
206 */
207 public function getPlatform()
208 {
209 return $this->_platform;
210 }
211
212 /**
213 * Set the name of the platform
214 * @param string $platform The name of the Platform
215 */
216 public function setPlatform($platform)
217 {
218 $this->_platform = $platform;
219 }
220
221 /**
222 * The version of the browser.
223 * @return string Version of the browser (will only contain alpha-numeric characters and a period)
224 */
225 public function getVersion()
226 {
227 return $this->_version;
228 }
229
230 /**
231 * Set the version of the browser
232 * @param string $version The version of the Browser
233 */
234 public function setVersion($version)
235 {
236 $this->_version = preg_replace('/[^0-9,.,a-z,A-Z-]/', '', $version);
237 }
238
239 /**
240 * The version of AOL.
241 * @return string Version of AOL (will only contain alpha-numeric characters and a period)
242 */
243 public function getAolVersion()
244 {
245 return $this->_aol_version;
246 }
247
248 /**
249 * Set the version of AOL
250 * @param string $version The version of AOL
251 */
252 public function setAolVersion($version)
253 {
254 $this->_aol_version = preg_replace('/[^0-9,.,a-z,A-Z]/', '', $version);
255 }
256
257 /**
258 * Is the browser from AOL?
259 * @return boolean True if the browser is from AOL otherwise false
260 */
261 public function isAol()
262 {
263 return $this->_is_aol;
264 }
265
266 /**
267 * Is the browser from a mobile device?
268 * @return boolean True if the browser is from a mobile device otherwise false
269 */
270 public function isMobile()
271 {
272 return $this->_is_mobile;
273 }
274
275 /**
276 * Is the browser from a tablet device?
277 * @return boolean True if the browser is from a tablet device otherwise false
278 */
279 public function isTablet()
280 {
281 return $this->_is_tablet;
282 }
283
284 /**
285 * Is the browser from a robot (ex Slurp,GoogleBot)?
286 * @return boolean True if the browser is from a robot otherwise false
287 */
288 public function isRobot()
289 {
290 return $this->_is_robot;
291 }
292
293 /**
294 * Is the browser from facebook?
295 * @return boolean True if the browser is from facebook otherwise false
296 */
297 public function isFacebook()
298 {
299 return $this->_is_facebook;
300 }
301
302 /**
303 * Set the browser to be from AOL
304 * @param $isAol
305 */
306 public function setAol($isAol)
307 {
308 $this->_is_aol = $isAol;
309 }
310
311 /**
312 * Set the Browser to be mobile
313 * @param boolean $value is the browser a mobile browser or not
314 */
315 protected function setMobile($value = true)
316 {
317 $this->_is_mobile = $value;
318 }
319
320 /**
321 * Set the Browser to be tablet
322 * @param boolean $value is the browser a tablet browser or not
323 */
324 protected function setTablet($value = true)
325 {
326 $this->_is_tablet = $value;
327 }
328
329 /**
330 * Set the Browser to be a robot
331 * @param boolean $value is the browser a robot or not
332 */
333 protected function setRobot($value = true)
334 {
335 $this->_is_robot = $value;
336 }
337
338 /**
339 * Set the Browser to be a Facebook request
340 * @param boolean $value is the browser a robot or not
341 */
342 protected function setFacebook($value = true)
343 {
344 $this->_is_facebook = $value;
345 }
346
347 /**
348 * Get the user agent value in use to determine the browser
349 * @return string The user agent from the HTTP header
350 */
351 public function getUserAgent()
352 {
353 return $this->_agent;
354 }
355
356 /**
357 * Set the user agent value (the construction will use the HTTP header value - this will overwrite it)
358 * @param string $agent_string The value for the User Agent
359 */
360 public function setUserAgent($agent_string)
361 {
362 $this->reset();
363 $this->_agent = $agent_string;
364 $this->determine();
365 }
366
367 /**
368 * Used to determine if the browser is actually "chromeframe"
369 * @since 1.7
370 * @return boolean True if the browser is using chromeframe
371 */
372 public function isChromeFrame()
373 {
374 return (strpos($this->_agent, "chromeframe") !== false);
375 }
376
377 /**
378 * Returns a formatted string with a summary of the details of the browser.
379 * @return string formatted string with a summary of the browser
380 */
381 public function __toString()
382 {
383 return "<strong>Browser Name:</strong> {$this->getBrowser()}<br/>\n" .
384 "<strong>Browser Version:</strong> {$this->getVersion()}<br/>\n" .
385 "<strong>Browser User Agent String:</strong> {$this->getUserAgent()}<br/>\n" .
386 "<strong>Platform:</strong> {$this->getPlatform()}<br/>";
387 }
388
389 /**
390 * Protected routine to calculate and determine what the browser is in use (including platform)
391 */
392 protected function determine()
393 {
394 $this->checkPlatform();
395 $this->checkBrowsers();
396 $this->checkForAol();
397 }
398
399 /**
400 * Protected routine to determine the browser type
401 * @return boolean True if the browser was detected otherwise false
402 */
403 protected function checkBrowsers()
404 {
405 return (
406 // well-known, well-used
407 // Special Notes:
408 // (1) Opera must be checked before FireFox due to the odd
409 // user agents used in some older versions of Opera
410 // (2) WebTV is strapped onto Internet Explorer so we must
411 // check for WebTV before IE
412 // (3) (deprecated) Galeon is based on Firefox and needs to be
413 // tested before Firefox is tested
414 // (4) OmniWeb is based on Safari so OmniWeb check must occur
415 // before Safari
416 // (5) Netscape 9+ is based on Firefox so Netscape checks
417 // before FireFox are necessary
418 // (6) Vivalid is UA contains both Firefox and Chrome so Vivalid checks
419 // before Firefox and Chrome
420 $this->checkBrowserWebTv() ||
421 $this->checkBrowserEdge() ||
422 $this->checkBrowserInternetExplorer() ||
423 $this->checkBrowserOpera() ||
424 $this->checkBrowserGaleon() ||
425 $this->checkBrowserNetscapeNavigator9Plus() ||
426 $this->checkBrowserVivaldi() ||
427 $this->checkBrowserYandex() ||
428 $this->checkBrowserFirefox() ||
429 $this->checkBrowserChrome() ||
430 $this->checkBrowserOmniWeb() ||
431
432 // common mobile
433 $this->checkBrowserAndroid() ||
434 $this->checkBrowseriPad() ||
435 $this->checkBrowseriPod() ||
436 $this->checkBrowseriPhone() ||
437 $this->checkBrowserBlackBerry() ||
438 $this->checkBrowserNokia() ||
439
440 // common bots
441 $this->checkBrowserGoogleBot() ||
442 $this->checkBrowserMSNBot() ||
443 $this->checkBrowserBingBot() ||
444 $this->checkBrowserSlurp() ||
445
446 // Yandex bots
447 $this->checkBrowserYandexBot() ||
448 $this->checkBrowserYandexImageResizerBot() ||
449 $this->checkBrowserYandexBlogsBot() ||
450 $this->checkBrowserYandexCatalogBot() ||
451 $this->checkBrowserYandexDirectBot() ||
452 $this->checkBrowserYandexFaviconsBot() ||
453 $this->checkBrowserYandexImagesBot() ||
454 $this->checkBrowserYandexMediaBot() ||
455 $this->checkBrowserYandexMetrikaBot() ||
456 $this->checkBrowserYandexNewsBot() ||
457 $this->checkBrowserYandexVideoBot() ||
458 $this->checkBrowserYandexWebmasterBot() ||
459
460 // check for facebook external hit when loading URL
461 $this->checkFacebookExternalHit() ||
462
463 // WebKit base check (post mobile and others)
464 $this->checkBrowserSamsung() ||
465 $this->checkBrowserSilk() ||
466 $this->checkBrowserSafari() ||
467
468 // everyone else
469 $this->checkBrowserNetPositive() ||
470 $this->checkBrowserFirebird() ||
471 $this->checkBrowserKonqueror() ||
472 $this->checkBrowserIcab() ||
473 $this->checkBrowserPhoenix() ||
474 $this->checkBrowserAmaya() ||
475 $this->checkBrowserLynx() ||
476 $this->checkBrowserShiretoko() ||
477 $this->checkBrowserIceCat() ||
478 $this->checkBrowserIceweasel() ||
479 $this->checkBrowserW3CValidator() ||
480 $this->checkBrowserPlayStation() ||
481 $this->checkBrowserIframely() ||
482 $this->checkBrowserCocoa() ||
483 $this->checkBrowserMozilla() /* Mozilla is such an open standard that you must check it last */
484
485
486 );
487 }
488
489 /**
490 * Determine if the user is using a BlackBerry (last updated 1.7)
491 * @return boolean True if the browser is the BlackBerry browser otherwise false
492 */
493 protected function checkBrowserBlackBerry()
494 {
495 if (stripos($this->_agent, 'blackberry') !== false) {
496 $aresult = explode("/", stristr($this->_agent, "BlackBerry"));
497 if (isset($aresult[1])) {
498 $aversion = explode(' ', $aresult[1]);
499 $this->setVersion($aversion[0]);
500 $this->_browser_name = self::BROWSER_BLACKBERRY;
501 $this->setMobile(true);
502 return true;
503 }
504 }
505 return false;
506 }
507
508 /**
509 * Determine if the user is using an AOL User Agent (last updated 1.7)
510 * @return boolean True if the browser is from AOL otherwise false
511 */
512 protected function checkForAol()
513 {
514 $this->setAol(false);
515 $this->setAolVersion(self::VERSION_UNKNOWN);
516
517 if (stripos($this->_agent, 'aol') !== false) {
518 $aversion = explode(' ', stristr($this->_agent, 'AOL'));
519 if (isset($aversion[1])) {
520 $this->setAol(true);
521 $this->setAolVersion(preg_replace('/[^0-9\.a-z]/i', '', $aversion[1]));
522 return true;
523 }
524 }
525 return false;
526 }
527
528 /**
529 * Determine if the browser is the GoogleBot or not (last updated 1.7)
530 * @return boolean True if the browser is the GoogletBot otherwise false
531 */
532 protected function checkBrowserGoogleBot()
533 {
534 if (stripos($this->_agent, 'googlebot') !== false) {
535 $aresult = explode('/', stristr($this->_agent, 'googlebot'));
536 if (isset($aresult[1])) {
537 $aversion = explode(' ', $aresult[1]);
538 $this->setVersion(str_replace(';', '', $aversion[0]));
539 $this->_browser_name = self::BROWSER_GOOGLEBOT;
540 $this->setRobot(true);
541 return true;
542 }
543 }
544 return false;
545 }
546
547 /**
548 * Determine if the browser is the YandexBot or not
549 * @return boolean True if the browser is the YandexBot otherwise false
550 */
551 protected function checkBrowserYandexBot()
552 {
553 if (stripos($this->_agent, 'YandexBot') !== false) {
554 $aresult = explode('/', stristr($this->_agent, 'YandexBot'));
555 if (isset($aresult[1])) {
556 $aversion = explode(' ', $aresult[1]);
557 $this->setVersion(str_replace(';', '', $aversion[0]));
558 $this->_browser_name = self::BROWSER_YANDEXBOT;
559 $this->setRobot(true);
560 return true;
561 }
562 }
563 return false;
564 }
565
566 /**
567 * Determine if the browser is the YandexImageResizer or not
568 * @return boolean True if the browser is the YandexImageResizer otherwise false
569 */
570 protected function checkBrowserYandexImageResizerBot()
571 {
572 if (stripos($this->_agent, 'YandexImageResizer') !== false) {
573 $aresult = explode('/', stristr($this->_agent, 'YandexImageResizer'));
574 if (isset($aresult[1])) {
575 $aversion = explode(' ', $aresult[1]);
576 $this->setVersion(str_replace(';', '', $aversion[0]));
577 $this->_browser_name = self::BROWSER_YANDEXIMAGERESIZER_BOT;
578 $this->setRobot(true);
579 return true;
580 }
581 }
582 return false;
583 }
584
585 /**
586 * Determine if the browser is the YandexCatalog or not
587 * @return boolean True if the browser is the YandexCatalog otherwise false
588 */
589 protected function checkBrowserYandexCatalogBot()
590 {
591 if (stripos($this->_agent, 'YandexCatalog') !== false) {
592 $aresult = explode('/', stristr($this->_agent, 'YandexCatalog'));
593 if (isset($aresult[1])) {
594 $aversion = explode(' ', $aresult[1]);
595 $this->setVersion(str_replace(';', '', $aversion[0]));
596 $this->_browser_name = self::BROWSER_YANDEXCATALOG_BOT;
597 $this->setRobot(true);
598 return true;
599 }
600 }
601 return false;
602 }
603
604 /**
605 * Determine if the browser is the YandexNews or not
606 * @return boolean True if the browser is the YandexNews otherwise false
607 */
608 protected function checkBrowserYandexNewsBot()
609 {
610 if (stripos($this->_agent, 'YandexNews') !== false) {
611 $aresult = explode('/', stristr($this->_agent, 'YandexNews'));
612 if (isset($aresult[1])) {
613 $aversion = explode(' ', $aresult[1]);
614 $this->setVersion(str_replace(';', '', $aversion[0]));
615 $this->_browser_name = self::BROWSER_YANDEXNEWS_BOT;
616 $this->setRobot(true);
617 return true;
618 }
619 }
620 return false;
621 }
622
623 /**
624 * Determine if the browser is the YandexMetrika or not
625 * @return boolean True if the browser is the YandexMetrika otherwise false
626 */
627 protected function checkBrowserYandexMetrikaBot()
628 {
629 if (stripos($this->_agent, 'YandexMetrika') !== false) {
630 $aresult = explode('/', stristr($this->_agent, 'YandexMetrika'));
631 if (isset($aresult[1])) {
632 $aversion = explode(' ', $aresult[1]);
633 $this->setVersion(str_replace(';', '', $aversion[0]));
634 $this->_browser_name = self::BROWSER_YANDEXMETRIKA_BOT;
635 $this->setRobot(true);
636 return true;
637 }
638 }
639 return false;
640 }
641
642 /**
643 * Determine if the browser is the YandexDirect or not
644 * @return boolean True if the browser is the YandexDirect otherwise false
645 */
646 protected function checkBrowserYandexDirectBot()
647 {
648 if (stripos($this->_agent, 'YandexDirect') !== false) {
649 $aresult = explode('/', stristr($this->_agent, 'YandexDirect'));
650 if (isset($aresult[1])) {
651 $aversion = explode(' ', $aresult[1]);
652 $this->setVersion(str_replace(';', '', $aversion[0]));
653 $this->_browser_name = self::BROWSER_YANDEXDIRECT_BOT;
654 $this->setRobot(true);
655 return true;
656 }
657 }
658 return false;
659 }
660
661 /**
662 * Determine if the browser is the YandexWebmaster or not
663 * @return boolean True if the browser is the YandexWebmaster otherwise false
664 */
665 protected function checkBrowserYandexWebmasterBot()
666 {
667 if (stripos($this->_agent, 'YandexWebmaster') !== false) {
668 $aresult = explode('/', stristr($this->_agent, 'YandexWebmaster'));
669 if (isset($aresult[1])) {
670 $aversion = explode(' ', $aresult[1]);
671 $this->setVersion(str_replace(';', '', $aversion[0]));
672 $this->_browser_name = self::BROWSER_YANDEXWEBMASTER_BOT;
673 $this->setRobot(true);
674 return true;
675 }
676 }
677 return false;
678 }
679
680 /**
681 * Determine if the browser is the YandexFavicons or not
682 * @return boolean True if the browser is the YandexFavicons otherwise false
683 */
684 protected function checkBrowserYandexFaviconsBot()
685 {
686 if (stripos($this->_agent, 'YandexFavicons') !== false) {
687 $aresult = explode('/', stristr($this->_agent, 'YandexFavicons'));
688 if (isset($aresult[1])) {
689 $aversion = explode(' ', $aresult[1]);
690 $this->setVersion(str_replace(';', '', $aversion[0]));
691 $this->_browser_name = self::BROWSER_YANDEXFAVICONS_BOT;
692 $this->setRobot(true);
693 return true;
694 }
695 }
696 return false;
697 }
698
699 /**
700 * Determine if the browser is the YandexBlogs or not
701 * @return boolean True if the browser is the YandexBlogs otherwise false
702 */
703 protected function checkBrowserYandexBlogsBot()
704 {
705 if (stripos($this->_agent, 'YandexBlogs') !== false) {
706 $aresult = explode('/', stristr($this->_agent, 'YandexBlogs'));
707 if (isset($aresult[1])) {
708 $aversion = explode(' ', $aresult[1]);
709 $this->setVersion(str_replace(';', '', $aversion[0]));
710 $this->_browser_name = self::BROWSER_YANDEXBLOGS_BOT;
711 $this->setRobot(true);
712 return true;
713 }
714 }
715 return false;
716 }
717
718 /**
719 * Determine if the browser is the YandexMedia or not
720 * @return boolean True if the browser is the YandexMedia otherwise false
721 */
722 protected function checkBrowserYandexMediaBot()
723 {
724 if (stripos($this->_agent, 'YandexMedia') !== false) {
725 $aresult = explode('/', stristr($this->_agent, 'YandexMedia'));
726 if (isset($aresult[1])) {
727 $aversion = explode(' ', $aresult[1]);
728 $this->setVersion(str_replace(';', '', $aversion[0]));
729 $this->_browser_name = self::BROWSER_YANDEXMEDIA_BOT;
730 $this->setRobot(true);
731 return true;
732 }
733 }
734 return false;
735 }
736
737 /**
738 * Determine if the browser is the YandexVideo or not
739 * @return boolean True if the browser is the YandexVideo otherwise false
740 */
741 protected function checkBrowserYandexVideoBot()
742 {
743 if (stripos($this->_agent, 'YandexVideo') !== false) {
744 $aresult = explode('/', stristr($this->_agent, 'YandexVideo'));
745 if (isset($aresult[1])) {
746 $aversion = explode(' ', $aresult[1]);
747 $this->setVersion(str_replace(';', '', $aversion[0]));
748 $this->_browser_name = self::BROWSER_YANDEXVIDEO_BOT;
749 $this->setRobot(true);
750 return true;
751 }
752 }
753 return false;
754 }
755
756 /**
757 * Determine if the browser is the YandexImages or not
758 * @return boolean True if the browser is the YandexImages otherwise false
759 */
760 protected function checkBrowserYandexImagesBot()
761 {
762 if (stripos($this->_agent, 'YandexImages') !== false) {
763 $aresult = explode('/', stristr($this->_agent, 'YandexImages'));
764 if (isset($aresult[1])) {
765 $aversion = explode(' ', $aresult[1]);
766 $this->setVersion(str_replace(';', '', $aversion[0]));
767 $this->_browser_name = self::BROWSER_YANDEXIMAGES_BOT;
768 $this->setRobot(true);
769 return true;
770 }
771 }
772 return false;
773 }
774
775 /**
776 * Determine if the browser is the MSNBot or not (last updated 1.9)
777 * @return boolean True if the browser is the MSNBot otherwise false
778 */
779 protected function checkBrowserMSNBot()
780 {
781 if (stripos($this->_agent, "msnbot") !== false) {
782 $aresult = explode("/", stristr($this->_agent, "msnbot"));
783 if (isset($aresult[1])) {
784 $aversion = explode(" ", $aresult[1]);
785 $this->setVersion(str_replace(";", "", $aversion[0]));
786 $this->_browser_name = self::BROWSER_MSNBOT;
787 $this->setRobot(true);
788 return true;
789 }
790 }
791 return false;
792 }
793
794 /**
795 * Determine if the browser is the BingBot or not (last updated 1.9)
796 * @return boolean True if the browser is the BingBot otherwise false
797 */
798 protected function checkBrowserBingBot()
799 {
800 if (stripos($this->_agent, "bingbot") !== false) {
801 $aresult = explode("/", stristr($this->_agent, "bingbot"));
802 if (isset($aresult[1])) {
803 $aversion = explode(" ", $aresult[1]);
804 $this->setVersion(str_replace(";", "", $aversion[0]));
805 $this->_browser_name = self::BROWSER_BINGBOT;
806 $this->setRobot(true);
807 return true;
808 }
809 }
810 return false;
811 }
812
813 /**
814 * Determine if the browser is the W3C Validator or not (last updated 1.7)
815 * @return boolean True if the browser is the W3C Validator otherwise false
816 */
817 protected function checkBrowserW3CValidator()
818 {
819 if (stripos($this->_agent, 'W3C-checklink') !== false) {
820 $aresult = explode('/', stristr($this->_agent, 'W3C-checklink'));
821 if (isset($aresult[1])) {
822 $aversion = explode(' ', $aresult[1]);
823 $this->setVersion($aversion[0]);
824 $this->_browser_name = self::BROWSER_W3CVALIDATOR;
825 return true;
826 }
827 } else if (stripos($this->_agent, 'W3C_Validator') !== false) {
828 // Some of the Validator versions do not delineate w/ a slash - add it back in
829 $ua = str_replace("W3C_Validator ", "W3C_Validator/", $this->_agent);
830 $aresult = explode('/', stristr($ua, 'W3C_Validator'));
831 if (isset($aresult[1])) {
832 $aversion = explode(' ', $aresult[1]);
833 $this->setVersion($aversion[0]);
834 $this->_browser_name = self::BROWSER_W3CVALIDATOR;
835 return true;
836 }
837 } else if (stripos($this->_agent, 'W3C-mobileOK') !== false) {
838 $this->_browser_name = self::BROWSER_W3CVALIDATOR;
839 $this->setMobile(true);
840 return true;
841 }
842 return false;
843 }
844
845 /**
846 * Determine if the browser is the Yahoo! Slurp Robot or not (last updated 1.7)
847 * @return boolean True if the browser is the Yahoo! Slurp Robot otherwise false
848 */
849 protected function checkBrowserSlurp()
850 {
851 if (stripos($this->_agent, 'slurp') !== false) {
852 $aresult = explode('/', stristr($this->_agent, 'Slurp'));
853 if (isset($aresult[1])) {
854 $aversion = explode(' ', $aresult[1]);
855 $this->setVersion($aversion[0]);
856 $this->_browser_name = self::BROWSER_SLURP;
857 $this->setRobot(true);
858 $this->setMobile(false);
859 return true;
860 }
861 }
862 return false;
863 }
864
865 /**
866 * Determine if the browser is Edge or not
867 * @return boolean True if the browser is Edge otherwise false
868 */
869 protected function checkBrowserEdge()
870 {
871 if (stripos($this->_agent, 'Edge/') !== false) {
872 $aresult = explode('/', stristr($this->_agent, 'Edge'));
873 if (isset($aresult[1])) {
874 $aversion = explode(' ', $aresult[1]);
875 $this->setVersion($aversion[0]);
876 $this->setBrowser(self::BROWSER_EDGE);
877 if (stripos($this->_agent, 'Windows Phone') !== false || stripos($this->_agent, 'Android') !== false) {
878 $this->setMobile(true);
879 }
880 return true;
881 }
882 }
883 return false;
884 }
885
886 /**
887 * Determine if the browser is Internet Explorer or not (last updated 1.7)
888 * @return boolean True if the browser is Internet Explorer otherwise false
889 */
890 protected function checkBrowserInternetExplorer()
891 {
892 // Test for IE11
893 if (stripos($this->_agent, 'Trident/7.0; rv:11.0') !== false) {
894 $this->setBrowser(self::BROWSER_IE);
895 $this->setVersion('11.0');
896 return true;
897 } // Test for v1 - v1.5 IE
898 else if (stripos($this->_agent, 'microsoft internet explorer') !== false) {
899 $this->setBrowser(self::BROWSER_IE);
900 $this->setVersion('1.0');
901 $aresult = stristr($this->_agent, '/');
902 if (preg_match('/308|425|426|474|0b1/i', $aresult)) {
903 $this->setVersion('1.5');
904 }
905 return true;
906 } // Test for versions > 1.5
907 else if (stripos($this->_agent, 'msie') !== false && stripos($this->_agent, 'opera') === false) {
908 // See if the browser is the odd MSN Explorer
909 if (stripos($this->_agent, 'msnb') !== false) {
910 $aresult = explode(' ', stristr(str_replace(';', '; ', $this->_agent), 'MSN'));
911 if (isset($aresult[1])) {
912 $this->setBrowser(self::BROWSER_MSN);
913 $this->setVersion(str_replace(array('(', ')', ';'), '', $aresult[1]));
914 return true;
915 }
916 }
917 $aresult = explode(' ', stristr(str_replace(';', '; ', $this->_agent), 'msie'));
918 if (isset($aresult[1])) {
919 $this->setBrowser(self::BROWSER_IE);
920 $this->setVersion(str_replace(array('(', ')', ';'), '', $aresult[1]));
921 if(preg_match('#trident/([0-9\.]+);#i', $this->_agent, $aresult)){
922 if($aresult[1] == '3.1'){
923 $this->setVersion('7.0');
924 }
925 else if($aresult[1] == '4.0'){
926 $this->setVersion('8.0');
927 }
928 else if($aresult[1] == '5.0'){
929 $this->setVersion('9.0');
930 }
931 else if($aresult[1] == '6.0'){
932 $this->setVersion('10.0');
933 }
934 else if($aresult[1] == '7.0'){
935 $this->setVersion('11.0');
936 }
937 else if($aresult[1] == '8.0'){
938 $this->setVersion('11.0');
939 }
940 }
941 if(stripos($this->_agent, 'IEMobile') !== false) {
942 $this->setBrowser(self::BROWSER_POCKET_IE);
943 $this->setMobile(true);
944 }
945 return true;
946 }
947 } // Test for versions > IE 10
948 else if (stripos($this->_agent, 'trident') !== false) {
949 $this->setBrowser(self::BROWSER_IE);
950 $result = explode('rv:', $this->_agent);
951 if (isset($result[1])) {
952 $this->setVersion(preg_replace('/[^0-9.]+/', '', $result[1]));
953 $this->_agent = str_replace(array("Mozilla", "Gecko"), "MSIE", $this->_agent);
954 }
955 } // Test for Pocket IE
956 else if (stripos($this->_agent, 'mspie') !== false || stripos($this->_agent, 'pocket') !== false) {
957 $aresult = explode(' ', stristr($this->_agent, 'mspie'));
958 if (isset($aresult[1])) {
959 $this->setPlatform(self::PLATFORM_WINDOWS_CE);
960 $this->setBrowser(self::BROWSER_POCKET_IE);
961 $this->setMobile(true);
962
963 if (stripos($this->_agent, 'mspie') !== false) {
964 $this->setVersion($aresult[1]);
965 } else {
966 $aversion = explode('/', $this->_agent);
967 if (isset($aversion[1])) {
968 $this->setVersion($aversion[1]);
969 }
970 }
971 return true;
972 }
973 }
974 return false;
975 }
976
977 /**
978 * Determine if the browser is Opera or not (last updated 1.7)
979 * @return boolean True if the browser is Opera otherwise false
980 */
981 protected function checkBrowserOpera()
982 {
983 if (stripos($this->_agent, 'opera mini') !== false) {
984 $resultant = stristr($this->_agent, 'opera mini');
985 if (preg_match('/\//', $resultant)) {
986 $aresult = explode('/', $resultant);
987 if (isset($aresult[1])) {
988 $aversion = explode(' ', $aresult[1]);
989 $this->setVersion($aversion[0]);
990 }
991 } else {
992 $aversion = explode(' ', stristr($resultant, 'opera mini'));
993 if (isset($aversion[1])) {
994 $this->setVersion($aversion[1]);
995 }
996 }
997 $this->_browser_name = self::BROWSER_OPERA_MINI;
998 $this->setMobile(true);
999 return true;
1000 } else if (stripos($this->_agent, 'opera') !== false) {
1001 $resultant = stristr($this->_agent, 'opera');
1002 if (preg_match('/Version\/(1*.*)$/', $resultant, $matches)) {
1003 $this->setVersion($matches[1]);
1004 } else if (preg_match('/\//', $resultant)) {
1005 $aresult = explode('/', str_replace("(", " ", $resultant));
1006 if (isset($aresult[1])) {
1007 $aversion = explode(' ', $aresult[1]);
1008 $this->setVersion($aversion[0]);
1009 }
1010 } else {
1011 $aversion = explode(' ', stristr($resultant, 'opera'));
1012 $this->setVersion(isset($aversion[1]) ? $aversion[1] : "");
1013 }
1014 if (stripos($this->_agent, 'Opera Mobi') !== false) {
1015 $this->setMobile(true);
1016 }
1017 $this->_browser_name = self::BROWSER_OPERA;
1018 return true;
1019 } else if (stripos($this->_agent, 'OPR') !== false) {
1020 $resultant = stristr($this->_agent, 'OPR');
1021 if (preg_match('/\//', $resultant)) {
1022 $aresult = explode('/', str_replace("(", " ", $resultant));
1023 if (isset($aresult[1])) {
1024 $aversion = explode(' ', $aresult[1]);
1025 $this->setVersion($aversion[0]);
1026 }
1027 }
1028 if (stripos($this->_agent, 'Mobile') !== false) {
1029 $this->setMobile(true);
1030 }
1031 $this->_browser_name = self::BROWSER_OPERA;
1032 return true;
1033 }
1034 return false;
1035 }
1036
1037 /**
1038 * Determine if the browser is Chrome or not (last updated 1.7)
1039 * @return boolean True if the browser is Chrome otherwise false
1040 */
1041 protected function checkBrowserChrome()
1042 {
1043 if (stripos($this->_agent, 'Chrome') !== false) {
1044 $aresult = explode('/', stristr($this->_agent, 'Chrome'));
1045 if (isset($aresult[1])) {
1046 $aversion = explode(' ', $aresult[1]);
1047 $this->setVersion($aversion[0]);
1048 $this->setBrowser(self::BROWSER_CHROME);
1049 //Chrome on Android
1050 if (stripos($this->_agent, 'Android') !== false) {
1051 if (stripos($this->_agent, 'Mobile') !== false) {
1052 $this->setMobile(true);
1053 } else {
1054 $this->setTablet(true);
1055 }
1056 }
1057 return true;
1058 }
1059 }
1060 return false;
1061 }
1062
1063
1064 /**
1065 * Determine if the browser is WebTv or not (last updated 1.7)
1066 * @return boolean True if the browser is WebTv otherwise false
1067 */
1068 protected function checkBrowserWebTv()
1069 {
1070 if (stripos($this->_agent, 'webtv') !== false) {
1071 $aresult = explode('/', stristr($this->_agent, 'webtv'));
1072 if (isset($aresult[1])) {
1073 $aversion = explode(' ', $aresult[1]);
1074 $this->setVersion($aversion[0]);
1075 $this->setBrowser(self::BROWSER_WEBTV);
1076 return true;
1077 }
1078 }
1079 return false;
1080 }
1081
1082 /**
1083 * Determine if the browser is NetPositive or not (last updated 1.7)
1084 * @return boolean True if the browser is NetPositive otherwise false
1085 */
1086 protected function checkBrowserNetPositive()
1087 {
1088 if (stripos($this->_agent, 'NetPositive') !== false) {
1089 $aresult = explode('/', stristr($this->_agent, 'NetPositive'));
1090 if (isset($aresult[1])) {
1091 $aversion = explode(' ', $aresult[1]);
1092 $this->setVersion(str_replace(array('(', ')', ';'), '', $aversion[0]));
1093 $this->setBrowser(self::BROWSER_NETPOSITIVE);
1094 return true;
1095 }
1096 }
1097 return false;
1098 }
1099
1100 /**
1101 * Determine if the browser is Galeon or not (last updated 1.7)
1102 * @return boolean True if the browser is Galeon otherwise false
1103 */
1104 protected function checkBrowserGaleon()
1105 {
1106 if (stripos($this->_agent, 'galeon') !== false) {
1107 $aresult = explode(' ', stristr($this->_agent, 'galeon'));
1108 $aversion = explode('/', $aresult[0]);
1109 if (isset($aversion[1])) {
1110 $this->setVersion($aversion[1]);
1111 $this->setBrowser(self::BROWSER_GALEON);
1112 return true;
1113 }
1114 }
1115 return false;
1116 }
1117
1118 /**
1119 * Determine if the browser is Konqueror or not (last updated 1.7)
1120 * @return boolean True if the browser is Konqueror otherwise false
1121 */
1122 protected function checkBrowserKonqueror()
1123 {
1124 if (stripos($this->_agent, 'Konqueror') !== false) {
1125 $aresult = explode(' ', stristr($this->_agent, 'Konqueror'));
1126 $aversion = explode('/', $aresult[0]);
1127 if (isset($aversion[1])) {
1128 $this->setVersion($aversion[1]);
1129 $this->setBrowser(self::BROWSER_KONQUEROR);
1130 return true;
1131 }
1132 }
1133 return false;
1134 }
1135
1136 /**
1137 * Determine if the browser is iCab or not (last updated 1.7)
1138 * @return boolean True if the browser is iCab otherwise false
1139 */
1140 protected function checkBrowserIcab()
1141 {
1142 if (stripos($this->_agent, 'icab') !== false) {
1143 $aversion = explode(' ', stristr(str_replace('/', ' ', $this->_agent), 'icab'));
1144 if (isset($aversion[1])) {
1145 $this->setVersion($aversion[1]);
1146 $this->setBrowser(self::BROWSER_ICAB);
1147 return true;
1148 }
1149 }
1150 return false;
1151 }
1152
1153 /**
1154 * Determine if the browser is OmniWeb or not (last updated 1.7)
1155 * @return boolean True if the browser is OmniWeb otherwise false
1156 */
1157 protected function checkBrowserOmniWeb()
1158 {
1159 if (stripos($this->_agent, 'omniweb') !== false) {
1160 $aresult = explode('/', stristr($this->_agent, 'omniweb'));
1161 $aversion = explode(' ', isset($aresult[1]) ? $aresult[1] : "");
1162 $this->setVersion($aversion[0]);
1163 $this->setBrowser(self::BROWSER_OMNIWEB);
1164 return true;
1165 }
1166 return false;
1167 }
1168
1169 /**
1170 * Determine if the browser is Phoenix or not (last updated 1.7)
1171 * @return boolean True if the browser is Phoenix otherwise false
1172 */
1173 protected function checkBrowserPhoenix()
1174 {
1175 if (stripos($this->_agent, 'Phoenix') !== false) {
1176 $aversion = explode('/', stristr($this->_agent, 'Phoenix'));
1177 if (isset($aversion[1])) {
1178 $this->setVersion($aversion[1]);
1179 $this->setBrowser(self::BROWSER_PHOENIX);
1180 return true;
1181 }
1182 }
1183 return false;
1184 }
1185
1186 /**
1187 * Determine if the browser is Firebird or not (last updated 1.7)
1188 * @return boolean True if the browser is Firebird otherwise false
1189 */
1190 protected function checkBrowserFirebird()
1191 {
1192 if (stripos($this->_agent, 'Firebird') !== false) {
1193 $aversion = explode('/', stristr($this->_agent, 'Firebird'));
1194 if (isset($aversion[1])) {
1195 $this->setVersion($aversion[1]);
1196 $this->setBrowser(self::BROWSER_FIREBIRD);
1197 return true;
1198 }
1199 }
1200 return false;
1201 }
1202
1203 /**
1204 * Determine if the browser is Netscape Navigator 9+ or not (last updated 1.7)
1205 * NOTE: (http://browser.netscape.com/ - Official support ended on March 1st, 2008)
1206 * @return boolean True if the browser is Netscape Navigator 9+ otherwise false
1207 */
1208 protected function checkBrowserNetscapeNavigator9Plus()
1209 {
1210 if (stripos($this->_agent, 'Firefox') !== false && preg_match('/Navigator\/([^ ]*)/i', $this->_agent, $matches)) {
1211 $this->setVersion($matches[1]);
1212 $this->setBrowser(self::BROWSER_NETSCAPE_NAVIGATOR);
1213 return true;
1214 } else if (stripos($this->_agent, 'Firefox') === false && preg_match('/Netscape6?\/([^ ]*)/i', $this->_agent, $matches)) {
1215 $this->setVersion($matches[1]);
1216 $this->setBrowser(self::BROWSER_NETSCAPE_NAVIGATOR);
1217 return true;
1218 }
1219 return false;
1220 }
1221
1222 /**
1223 * Determine if the browser is Shiretoko or not (https://wiki.mozilla.org/Projects/shiretoko) (last updated 1.7)
1224 * @return boolean True if the browser is Shiretoko otherwise false
1225 */
1226 protected function checkBrowserShiretoko()
1227 {
1228 if (stripos($this->_agent, 'Mozilla') !== false && preg_match('/Shiretoko\/([^ ]*)/i', $this->_agent, $matches)) {
1229 $this->setVersion($matches[1]);
1230 $this->setBrowser(self::BROWSER_SHIRETOKO);
1231 return true;
1232 }
1233 return false;
1234 }
1235
1236 /**
1237 * Determine if the browser is Ice Cat or not (http://en.wikipedia.org/wiki/GNU_IceCat) (last updated 1.7)
1238 * @return boolean True if the browser is Ice Cat otherwise false
1239 */
1240 protected function checkBrowserIceCat()
1241 {
1242 if (stripos($this->_agent, 'Mozilla') !== false && preg_match('/IceCat\/([^ ]*)/i', $this->_agent, $matches)) {
1243 $this->setVersion($matches[1]);
1244 $this->setBrowser(self::BROWSER_ICECAT);
1245 return true;
1246 }
1247 return false;
1248 }
1249
1250 /**
1251 * Determine if the browser is Nokia or not (last updated 1.7)
1252 * @return boolean True if the browser is Nokia otherwise false
1253 */
1254 protected function checkBrowserNokia()
1255 {
1256 if (preg_match("/Nokia([^\/]+)\/([^ SP]+)/i", $this->_agent, $matches)) {
1257 $this->setVersion($matches[2]);
1258 if (stripos($this->_agent, 'Series60') !== false || strpos($this->_agent, 'S60') !== false) {
1259 $this->setBrowser(self::BROWSER_NOKIA_S60);
1260 } else {
1261 $this->setBrowser(self::BROWSER_NOKIA);
1262 }
1263 $this->setMobile(true);
1264 return true;
1265 }
1266 return false;
1267 }
1268
1269 /**
1270 * Determine if the browser is Firefox or not (last updated 1.7)
1271 * @return boolean True if the browser is Firefox otherwise false
1272 */
1273 protected function checkBrowserFirefox()
1274 {
1275 if (stripos($this->_agent, 'safari') === false) {
1276 if (preg_match("/Firefox[\/ \(]([^ ;\)]+)/i", $this->_agent, $matches)) {
1277 $this->setVersion($matches[1]);
1278 $this->setBrowser(self::BROWSER_FIREFOX);
1279 //Firefox on Android
1280 if (stripos($this->_agent, 'Android') !== false) {
1281 if (stripos($this->_agent, 'Mobile') !== false) {
1282 $this->setMobile(true);
1283 } else {
1284 $this->setTablet(true);
1285 }
1286 }
1287 return true;
1288 } else if (preg_match("/Firefox$/i", $this->_agent, $matches)) {
1289 $this->setVersion("");
1290 $this->setBrowser(self::BROWSER_FIREFOX);
1291 return true;
1292 }
1293 }
1294 return false;
1295 }
1296
1297 /**
1298 * Determine if the browser is Firefox or not (last updated 1.7)
1299 * @return boolean True if the browser is Firefox otherwise false
1300 */
1301 protected function checkBrowserIceweasel()
1302 {
1303 if (stripos($this->_agent, 'Iceweasel') !== false) {
1304 $aresult = explode('/', stristr($this->_agent, 'Iceweasel'));
1305 if (isset($aresult[1])) {
1306 $aversion = explode(' ', $aresult[1]);
1307 $this->setVersion($aversion[0]);
1308 $this->setBrowser(self::BROWSER_ICEWEASEL);
1309 return true;
1310 }
1311 }
1312 return false;
1313 }
1314
1315 /**
1316 * Determine if the browser is Mozilla or not (last updated 1.7)
1317 * @return boolean True if the browser is Mozilla otherwise false
1318 */
1319 protected function checkBrowserMozilla()
1320 {
1321 if (stripos($this->_agent, 'mozilla') !== false && preg_match('/rv:[0-9].[0-9][a-b]?/i', $this->_agent) && stripos($this->_agent, 'netscape') === false) {
1322 $aversion = explode(' ', stristr($this->_agent, 'rv:'));
1323 preg_match('/rv:[0-9].[0-9][a-b]?/i', $this->_agent, $aversion);
1324 $this->setVersion(str_replace('rv:', '', $aversion[0]));
1325 $this->setBrowser(self::BROWSER_MOZILLA);
1326 return true;
1327 } else if (stripos($this->_agent, 'mozilla') !== false && preg_match('/rv:[0-9]\.[0-9]/i', $this->_agent) && stripos($this->_agent, 'netscape') === false) {
1328 $aversion = explode('', stristr($this->_agent, 'rv:'));
1329 $this->setVersion(str_replace('rv:', '', $aversion[0]));
1330 $this->setBrowser(self::BROWSER_MOZILLA);
1331 return true;
1332 } else if (stripos($this->_agent, 'mozilla') !== false && preg_match('/mozilla\/([^ ]*)/i', $this->_agent, $matches) && stripos($this->_agent, 'netscape') === false) {
1333 $this->setVersion($matches[1]);
1334 $this->setBrowser(self::BROWSER_MOZILLA);
1335 return true;
1336 }
1337 return false;
1338 }
1339
1340 /**
1341 * Determine if the browser is Lynx or not (last updated 1.7)
1342 * @return boolean True if the browser is Lynx otherwise false
1343 */
1344 protected function checkBrowserLynx()
1345 {
1346 if (stripos($this->_agent, 'lynx') !== false) {
1347 $aresult = explode('/', stristr($this->_agent, 'Lynx'));
1348 $aversion = explode(' ', (isset($aresult[1]) ? $aresult[1] : ""));
1349 $this->setVersion($aversion[0]);
1350 $this->setBrowser(self::BROWSER_LYNX);
1351 return true;
1352 }
1353 return false;
1354 }
1355
1356 /**
1357 * Determine if the browser is Amaya or not (last updated 1.7)
1358 * @return boolean True if the browser is Amaya otherwise false
1359 */
1360 protected function checkBrowserAmaya()
1361 {
1362 if (stripos($this->_agent, 'amaya') !== false) {
1363 $aresult = explode('/', stristr($this->_agent, 'Amaya'));
1364 if (isset($aresult[1])) {
1365 $aversion = explode(' ', $aresult[1]);
1366 $this->setVersion($aversion[0]);
1367 $this->setBrowser(self::BROWSER_AMAYA);
1368 return true;
1369 }
1370 }
1371 return false;
1372 }
1373
1374 /**
1375 * Determine if the browser is Safari or not (last updated 1.7)
1376 * @return boolean True if the browser is Safari otherwise false
1377 */
1378 protected function checkBrowserSafari()
1379 {
1380 if (stripos($this->_agent, 'Safari') !== false
1381 && stripos($this->_agent, 'iPhone') === false
1382 && stripos($this->_agent, 'iPod') === false
1383 ) {
1384
1385 $aresult = explode('/', stristr($this->_agent, 'Version'));
1386 if (isset($aresult[1])) {
1387 $aversion = explode(' ', $aresult[1]);
1388 $this->setVersion($aversion[0]);
1389 } else {
1390 $this->setVersion(self::VERSION_UNKNOWN);
1391 }
1392 $this->setBrowser(self::BROWSER_SAFARI);
1393 return true;
1394 }
1395 return false;
1396 }
1397
1398 protected function checkBrowserSamsung()
1399 {
1400 if (stripos($this->_agent, 'SamsungBrowser') !== false) {
1401
1402 $aresult = explode('/', stristr($this->_agent, 'SamsungBrowser'));
1403 if (isset($aresult[1])) {
1404 $aversion = explode(' ', $aresult[1]);
1405 $this->setVersion($aversion[0]);
1406 } else {
1407 $this->setVersion(self::VERSION_UNKNOWN);
1408 }
1409 $this->setBrowser(self::BROWSER_SAMSUNG);
1410 return true;
1411 }
1412 return false;
1413 }
1414
1415 protected function checkBrowserSilk()
1416 {
1417 if (stripos($this->_agent, 'Silk') !== false) {
1418 $aresult = explode('/', stristr($this->_agent, 'Silk'));
1419 if (isset($aresult[1])) {
1420 $aversion = explode(' ', $aresult[1]);
1421 $this->setVersion($aversion[0]);
1422 } else {
1423 $this->setVersion(self::VERSION_UNKNOWN);
1424 }
1425 $this->setBrowser(self::BROWSER_SILK);
1426 return true;
1427 }
1428 return false;
1429 }
1430
1431 protected function checkBrowserIframely()
1432 {
1433 if (stripos($this->_agent, 'Iframely') !== false) {
1434 $aresult = explode('/', stristr($this->_agent, 'Iframely'));
1435 if (isset($aresult[1])) {
1436 $aversion = explode(' ', $aresult[1]);
1437 $this->setVersion($aversion[0]);
1438 } else {
1439 $this->setVersion(self::VERSION_UNKNOWN);
1440 }
1441 $this->setBrowser(self::BROWSER_I_FRAME);
1442 return true;
1443 }
1444 return false;
1445 }
1446
1447 protected function checkBrowserCocoa()
1448 {
1449 if (stripos($this->_agent, 'CocoaRestClient') !== false) {
1450 $aresult = explode('/', stristr($this->_agent, 'CocoaRestClient'));
1451 if (isset($aresult[1])) {
1452 $aversion = explode(' ', $aresult[1]);
1453 $this->setVersion($aversion[0]);
1454 } else {
1455 $this->setVersion(self::VERSION_UNKNOWN);
1456 }
1457 $this->setBrowser(self::BROWSER_COCOA);
1458 return true;
1459 }
1460 return false;
1461 }
1462
1463 /**
1464 * Detect if URL is loaded from FacebookExternalHit
1465 * @return boolean True if it detects FacebookExternalHit otherwise false
1466 */
1467 protected function checkFacebookExternalHit()
1468 {
1469 if (stristr($this->_agent, 'FacebookExternalHit')) {
1470 $this->setRobot(true);
1471 $this->setFacebook(true);
1472 return true;
1473 }
1474 return false;
1475 }
1476
1477 /**
1478 * Detect if URL is being loaded from internal Facebook browser
1479 * @return boolean True if it detects internal Facebook browser otherwise false
1480 */
1481 protected function checkForFacebookIos()
1482 {
1483 if (stristr($this->_agent, 'FBIOS')) {
1484 $this->setFacebook(true);
1485 return true;
1486 }
1487 return false;
1488 }
1489
1490 /**
1491 * Detect Version for the Safari browser on iOS devices
1492 * @return boolean True if it detects the version correctly otherwise false
1493 */
1494 protected function getSafariVersionOnIos()
1495 {
1496 $aresult = explode('/', stristr($this->_agent, 'Version'));
1497 if (isset($aresult[1])) {
1498 $aversion = explode(' ', $aresult[1]);
1499 $this->setVersion($aversion[0]);
1500 return true;
1501 }
1502 return false;
1503 }
1504
1505 /**
1506 * Detect Version for the Chrome browser on iOS devices
1507 * @return boolean True if it detects the version correctly otherwise false
1508 */
1509 protected function getChromeVersionOnIos()
1510 {
1511 $aresult = explode('/', stristr($this->_agent, 'CriOS'));
1512 if (isset($aresult[1])) {
1513 $aversion = explode(' ', $aresult[1]);
1514 $this->setVersion($aversion[0]);
1515 $this->setBrowser(self::BROWSER_CHROME);
1516 return true;
1517 }
1518 return false;
1519 }
1520
1521 /**
1522 * Determine if the browser is iPhone or not (last updated 1.7)
1523 * @return boolean True if the browser is iPhone otherwise false
1524 */
1525 protected function checkBrowseriPhone()
1526 {
1527 if (stripos($this->_agent, 'iPhone') !== false) {
1528 $this->setVersion(self::VERSION_UNKNOWN);
1529 $this->setBrowser(self::BROWSER_IPHONE);
1530 $this->getSafariVersionOnIos();
1531 $this->getChromeVersionOnIos();
1532 $this->checkForFacebookIos();
1533 $this->setMobile(true);
1534 return true;
1535
1536 }
1537 return false;
1538 }
1539
1540 /**
1541 * Determine if the browser is iPad or not (last updated 1.7)
1542 * @return boolean True if the browser is iPad otherwise false
1543 */
1544 protected function checkBrowseriPad()
1545 {
1546 if (stripos($this->_agent, 'iPad') !== false) {
1547 $this->setVersion(self::VERSION_UNKNOWN);
1548 $this->setBrowser(self::BROWSER_IPAD);
1549 $this->getSafariVersionOnIos();
1550 $this->getChromeVersionOnIos();
1551 $this->checkForFacebookIos();
1552 $this->setTablet(true);
1553 return true;
1554 }
1555 return false;
1556 }
1557
1558 /**
1559 * Determine if the browser is iPod or not (last updated 1.7)
1560 * @return boolean True if the browser is iPod otherwise false
1561 */
1562 protected function checkBrowseriPod()
1563 {
1564 if (stripos($this->_agent, 'iPod') !== false) {
1565 $this->setVersion(self::VERSION_UNKNOWN);
1566 $this->setBrowser(self::BROWSER_IPOD);
1567 $this->getSafariVersionOnIos();
1568 $this->getChromeVersionOnIos();
1569 $this->checkForFacebookIos();
1570 $this->setMobile(true);
1571 return true;
1572 }
1573 return false;
1574 }
1575
1576 /**
1577 * Determine if the browser is Android or not (last updated 1.7)
1578 * @return boolean True if the browser is Android otherwise false
1579 */
1580 protected function checkBrowserAndroid()
1581 {
1582 if (stripos($this->_agent, 'Android') !== false) {
1583 $aresult = explode(' ', stristr($this->_agent, 'Android'));
1584 if (isset($aresult[1])) {
1585 $aversion = explode(' ', $aresult[1]);
1586 $this->setVersion($aversion[0]);
1587 } else {
1588 $this->setVersion(self::VERSION_UNKNOWN);
1589 }
1590 if (stripos($this->_agent, 'Mobile') !== false) {
1591 $this->setMobile(true);
1592 } else {
1593 $this->setTablet(true);
1594 }
1595 $this->setBrowser(self::BROWSER_ANDROID);
1596 return true;
1597 }
1598 return false;
1599 }
1600
1601 /**
1602 * Determine if the browser is Vivaldi
1603 * @return boolean True if the browser is Vivaldi otherwise false
1604 */
1605 protected function checkBrowserVivaldi()
1606 {
1607 if (stripos($this->_agent, 'Vivaldi') !== false) {
1608 $aresult = explode('/', stristr($this->_agent, 'Vivaldi'));
1609 if (isset($aresult[1])) {
1610 $aversion = explode(' ', $aresult[1]);
1611 $this->setVersion($aversion[0]);
1612 $this->setBrowser(self::BROWSER_VIVALDI);
1613 return true;
1614 }
1615 }
1616 return false;
1617 }
1618
1619 /**
1620 * Determine if the browser is Yandex
1621 * @return boolean True if the browser is Yandex otherwise false
1622 */
1623 protected function checkBrowserYandex()
1624 {
1625 if (stripos($this->_agent, 'YaBrowser') !== false) {
1626 $aresult = explode('/', stristr($this->_agent, 'YaBrowser'));
1627 if (isset($aresult[1])) {
1628 $aversion = explode(' ', $aresult[1]);
1629 $this->setVersion($aversion[0]);
1630 $this->setBrowser(self::BROWSER_YANDEX);
1631
1632 if (stripos($this->_agent, 'iPad') !== false) {
1633 $this->setTablet(true);
1634 } elseif (stripos($this->_agent, 'Mobile') !== false) {
1635 $this->setMobile(true);
1636 } elseif (stripos($this->_agent, 'Android') !== false) {
1637 $this->setTablet(true);
1638 }
1639
1640 return true;
1641 }
1642 }
1643
1644 return false;
1645 }
1646
1647 /**
1648 * Determine if the browser is a PlayStation
1649 * @return boolean True if the browser is PlayStation otherwise false
1650 */
1651 protected function checkBrowserPlayStation()
1652 {
1653 if (stripos($this->_agent, 'PlayStation ') !== false) {
1654 $aresult = explode(' ', stristr($this->_agent, 'PlayStation '));
1655 $this->setBrowser(self::BROWSER_PLAYSTATION);
1656 if (isset($aresult[0])) {
1657 $aversion = explode(')', $aresult[2]);
1658 $this->setVersion($aversion[0]);
1659 if (stripos($this->_agent, 'Portable)') !== false || stripos($this->_agent, 'Vita') !== false) {
1660 $this->setMobile(true);
1661 }
1662 return true;
1663 }
1664 }
1665 return false;
1666 }
1667
1668 /**
1669 * Determine the user's platform (last updated 2.0)
1670 */
1671 protected function checkPlatform()
1672 {
1673 if (stripos($this->_agent, 'windows') !== false) {
1674 $this->_platform = self::PLATFORM_WINDOWS;
1675 } else if (stripos($this->_agent, 'iPad') !== false) {
1676 $this->_platform = self::PLATFORM_IPAD;
1677 } else if (stripos($this->_agent, 'iPod') !== false) {
1678 $this->_platform = self::PLATFORM_IPOD;
1679 } else if (stripos($this->_agent, 'iPhone') !== false) {
1680 $this->_platform = self::PLATFORM_IPHONE;
1681 } elseif (stripos($this->_agent, 'mac') !== false) {
1682 $this->_platform = self::PLATFORM_APPLE;
1683 } elseif (stripos($this->_agent, 'android') !== false) {
1684 $this->_platform = self::PLATFORM_ANDROID;
1685 } elseif (stripos($this->_agent, 'Silk') !== false) {
1686 $this->_platform = self::PLATFORM_FIRE_OS;
1687 } elseif (stripos($this->_agent, 'linux') !== false && stripos($this->_agent, 'SMART-TV') !== false ) {
1688 $this->_platform = self::PLATFORM_LINUX .'/'.self::PLATFORM_SMART_TV;
1689 } elseif (stripos($this->_agent, 'linux') !== false) {
1690 $this->_platform = self::PLATFORM_LINUX;
1691 } else if (stripos($this->_agent, 'Nokia') !== false) {
1692 $this->_platform = self::PLATFORM_NOKIA;
1693 } else if (stripos($this->_agent, 'BlackBerry') !== false) {
1694 $this->_platform = self::PLATFORM_BLACKBERRY;
1695 } elseif (stripos($this->_agent, 'FreeBSD') !== false) {
1696 $this->_platform = self::PLATFORM_FREEBSD;
1697 } elseif (stripos($this->_agent, 'OpenBSD') !== false) {
1698 $this->_platform = self::PLATFORM_OPENBSD;
1699 } elseif (stripos($this->_agent, 'NetBSD') !== false) {
1700 $this->_platform = self::PLATFORM_NETBSD;
1701 } elseif (stripos($this->_agent, 'OpenSolaris') !== false) {
1702 $this->_platform = self::PLATFORM_OPENSOLARIS;
1703 } elseif (stripos($this->_agent, 'SunOS') !== false) {
1704 $this->_platform = self::PLATFORM_SUNOS;
1705 } elseif (stripos($this->_agent, 'OS\/2') !== false) {
1706 $this->_platform = self::PLATFORM_OS2;
1707 } elseif (stripos($this->_agent, 'BeOS') !== false) {
1708 $this->_platform = self::PLATFORM_BEOS;
1709 } elseif (stripos($this->_agent, 'win') !== false) {
1710 $this->_platform = self::PLATFORM_WINDOWS;
1711 } elseif (stripos($this->_agent, 'Playstation') !== false) {
1712 $this->_platform = self::PLATFORM_PLAYSTATION;
1713 } elseif (stripos($this->_agent, 'Roku') !== false) {
1714 $this->_platform = self::PLATFORM_ROKU;
1715 } elseif (stripos($this->_agent, 'iOS') !== false) {
1716 $this->_platform = self::PLATFORM_IPHONE . '/' . self::PLATFORM_IPAD;
1717 } elseif (stripos($this->_agent, 'tvOS') !== false) {
1718 $this->_platform = self::PLATFORM_APPLE_TV;
1719 } elseif (stripos($this->_agent, 'curl') !== false) {
1720 $this->_platform = self::PLATFORM_TERMINAL;
1721 } elseif (stripos($this->_agent, 'CrOS') !== false) {
1722 $this->_platform = self::PLATFORM_CHROME_OS;
1723 } elseif (stripos($this->_agent, 'okhttp') !== false) {
1724 $this->_platform = self::PLATFORM_JAVA_ANDROID;
1725 } elseif (stripos($this->_agent, 'PostmanRuntime') !== false) {
1726 $this->_platform = self::PLATFORM_POSTMAN;
1727 } elseif (stripos($this->_agent, 'Iframely') !== false) {
1728 $this->_platform = self::PLATFORM_I_FRAME;
1729 }
1730
1731 }
1732 }
1733
k2shop/usr/k2shop/libs/browser/Readme.txt
File was created 1 Определение версии и типа браузера.
2 Постоянно обновляется по адресу: https://github.com/cbschuld/Browser.php
3 Статья по данной теме: https://ruseller.com/adds.php?rub=11&id=1914
4
5 Пример использования:
6 $browser = new Browser();
7 if( $browser->getBrowser() == Browser::BROWSER_FIREFOX && $browser->getVersion() >= 2 ) {
8 echo 'Вы используете браузер FireFox версии 2 или выше';
9 }
k2shop/usr/k2shop/libs/detectDevice/DetectDeviceTest.php
File was created 1 <?php
2 require "class.DetectDevice.php";
3
4 class DetectDeviceTest extends PHPUnit_Framework_TestCase {
5
6 private $device;
7
8 public function __construct() {
9 $this->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");
10 }
11
12 public function testComputer() {
13 // Google Chrome 29 on Windows 8 x64
14 $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");
15 $this->assertEquals(true, $this->device->isComputer());
16
17 // Mozilla Firefox 22 on Windows 8 x64
18 $this->device->setUserAgent("Mozilla/5.0 (Windows NT 6.2; WOW64; rv:22.0) Gecko/20100101 Firefox/22.0");
19 $this->assertEquals(true, $this->device->isComputer());
20 }
21
22 public function testMobile() {
23 // LGE Nexus 4
24 $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");
25 $this->assertEquals(true, $this->device->isMobile());
26
27 // Samsung Galaxy S4
28 $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");
29 $this->assertEquals(true, $this->device->isMobile());
30 }
31
32 public function testTablet() {
33 // Asus Nexus 7
34 $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");
35 $this->assertEquals(true, $this->device->isTablet());
36
37 // Samsung Galaxy Note 10.1
38 $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");
39 $this->assertEquals(true, $this->device->isTablet());
40 }
41
42 public function testBot() {
43 // GoogleBot
44 $this->device->setUserAgent("Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)");
45 $this->assertEquals(true, $this->device->isBot());
46
47 // BingBot
48 $this->device->setUserAgent("Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)");
49 $this->assertEquals(true, $this->device->isBot());
50 }
51
52 public function testConsole() {
53 // PS3
54 $this->device->setUserAgent("Mozilla/5.0 (PLAYSTATION 3; 3.55)");
55 $this->assertEquals(true, $this->device->isConsole());
56
57 // XBox
58 $this->device->setUserAgent("Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; Xbox)");
59 $this->assertEquals(true, $this->device->isConsole());
60 }
61
62 public function testIs() {
63 // Google Chrome
64 $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");
65 $this->assertEquals(true, $this->device->is("chrome"));
66
67 // Nintendo DS
68 $this->device->setUserAgent("Mozilla/5.0 (Windows NT 6.2; WOW64; rv:22.0) Gecko/20100101 Firefox/22.0");
69 $this->assertEquals(true, $this->device->is("firefox"));
70 }
71 }
k2shop/usr/k2shop/libs/detectDevice/README.md
File was created 1 DetectDevice
2 ============
3 [![Build Status](https://travis-ci.org/Kocal/DetectDevice.png?branch=master)](https://travis-ci.org/Kocal/DetectDevice)
4
5 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.
6
7
8 How use?
9 --------
10 #### Firstly, include DetectDevice class and initialize it
11 ```php
12 <?php
13 require "class.DetectDevice.php";
14 $device = new DetectDevice();
15 // ...
16 ```
17
18 #### Optional : If you want, you can set an other user-agent
19 ```php
20 <?php
21 $userAgent = "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.66 Safari/537.36";
22
23 // in the constructor
24 $device = new DetectDevice($userAgent);
25
26 // or with the "setUserAgent()" method
27 $device->setUserAgent($userAgent);
28 ```
29
30 #### Use methods to find what kind of device is used
31 ```php
32 <?php
33 // return a boolean (true or false)
34 echo $device->isComputer();
35 echo $device->isMobile();
36 echo $device->isTablet();
37 echo $device->isBot();
38 echo $device->isConsole();
39
40 // You can use the "getDeviceType()" to return a string
41 echo $device->getDeviceType(); // may return "computer", "mobile, "tablet", "bot" or "console"
42 // ...
43 ```
44
45 #### Or use "is()"
46 ```php
47 <?php
48 // The "is()" method match $str in UserAgent $str, and return true or false
49
50 $str = "msie";
51
52 if($device->is($str)) {
53 // do stuff for Internet Explorer only
54 }
55
56 ```
k2shop/usr/k2shop/libs/detectDevice/class.DetectDevice.php
File was created 1 <?php class DetectDevice {
2
3 private $userAgent = "";
4
5 private $devices = array(
6 "computer" => array("msie 10", "msie 9", "msie 8", "windows.*firefox", "windows.*chrome", "x11.*chrome", "x11.*firefox", "macintosh.*chrome", "macintosh.*firefox", "opera"),
7 "tablet" => array("tablet", "android", "ipad", "tablet.*firefox"),
8 "mobile" => array("mobile ", "android.*mobile", "iphone", "ipod", "opera mobi", "opera mini"),
9 "bot" => array("googlebot", "mediapartners-google", "adsbot-google", "duckduckbot", "msnbot", "bingbot", "ask", "facebook", "yahoo", "addthis"),
10 "console" => array("ps2", "playstation", "xbox", "wii", "nintendo 3?ds")
11 );
12
13
14 private $deviceType = "";
15
16 private $isComputer = false;
17 private $isMobile = false;
18 private $isTablet = false;
19 private $isBot = false;
20 private $isConsole = false;
21
22
23 public function __construct($userAgent = "") {
24 if(!empty($userAgent)) {
25 $this->userAgent = $userAgent;
26 } else {
27 $this->userAgent = $_SERVER["HTTP_USER_AGENT"];
28 }
29
30 $this->detectDevice();
31 }
32
33 public function detectDevice() {
34 foreach($this->devices as $deviceType => $devices) {
35 foreach($devices as $device) {
36 if(preg_match("/" . $device . "/i", $this->userAgent)) {
37 $this->deviceType = $deviceType;
38 }
39 }
40 }
41
42 $d = "is" . ucfirst($this->deviceType);
43 $this->$d = true;
44 }
45
46 public function setUserAgent($userAgent) {
47 $this->userAgent = $userAgent;
48 $this->resetDevices();
49 $this->detectDevice();
50 }
51
52 public function resetDevices() {
53 $this->isComputer = false;
54 $this->isMobile = false;
55 $this->isTablet = false;
56 $this->isBot = false;
57 }
58
59 public function is($str, $userAgent = null) {
60 if(!$userAgent) {
61 $userAgent = $this->userAgent;
62 }
63
64 return preg_match('/' . $str . '/i', $userAgent);
65 }
66
67 public function getDeviceType() { return $this->deviceType; }
68 public function isComputer() { return $this->isComputer; }
69 public function isMobile() { return $this->isMobile; }
70 public function isTablet() { return $this->isTablet; }
71 public function isBot() { return $this->isBot; }
72 public function isConsole() { return $this->isConsole; }
73 public function getUserAgent() { return $this->userAgent; }
74
75
76 }
77
k2shop/usr/k2shop/libs/nestmenu/index.html
File was created 1 <!DOCTYPE html>
2 <!--[if lt IE 7]> <html lang="en" class="lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
3 <!--[if IE 7]> <html lang="en" class="lt-ie9 lt-ie8"> <![endif]-->
4 <!--[if IE 8]> <html lang="en" class="lt-ie9"> <![endif]-->
5 <!--[if IE 9]> <html lang="en" class="ie9"> <![endif]-->
6 <!--[if gt IE 9]><!--> <html lang="en"> <!--<![endif]-->
7 <head>
8 <meta charset="utf-8">
9 <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
10 <title>Nestable</title>
11 <style type="text/css">
12 .cf:after { visibility: hidden; display: block; font-size: 0; content: " "; clear: both; height: 0; }
13 * html .cf { zoom: 1; }
14 *:first-child+html .cf { zoom: 1; }
15 html { margin: 0; padding: 0; }
16 body { font-size: 100%; margin: 0; padding: 1.75em; font-family: 'Helvetica Neue', Arial, sans-serif; }
17 h1 { font-size: 1.75em; margin: 0 0 0.6em 0; }
18 a { color: #2996cc; }
19 a:hover { text-decoration: none; }
20 p { line-height: 1.5em; }
21 .small { color: #666; font-size: 0.875em; }
22 .large { font-size: 1.25em; }
23 /**
24 * Nestable
25 */
26 .dd { position: relative; display: block; margin: 0; padding: 0; max-width: 600px; list-style: none; font-size: 13px; line-height: 20px; }
27 .dd-list { display: block; position: relative; margin: 0; padding: 0; list-style: none; }
28 .dd-list .dd-list { padding-left: 30px; }
29 .dd-collapsed .dd-list { display: none; }
30 .dd-item,
31 .dd-empty,
32 .dd-placeholder { display: block; position: relative; margin: 0; padding: 0; min-height: 20px; font-size: 13px; line-height: 20px; }
33 .dd-handle { display: block; height: 30px; margin: 5px 0; padding: 5px 10px; color: #333; text-decoration: none; font-weight: bold; border: 1px solid #ccc;
34 background: #fafafa;
35 background: -webkit-linear-gradient(top, #fafafa 0%, #eee 100%);
36 background: -moz-linear-gradient(top, #fafafa 0%, #eee 100%);
37 background: linear-gradient(top, #fafafa 0%, #eee 100%);
38 -webkit-border-radius: 3px;
39 border-radius: 3px;
40 box-sizing: border-box; -moz-box-sizing: border-box;
41 }
42 .dd-handle:hover { color: #2ea8e5; background: #fff; }
43 .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; }
44 .dd-item > button:before { content: '+'; display: block; position: absolute; width: 100%; text-align: center; text-indent: 0; }
45 .dd-item > button[data-action="collapse"]:before { content: '-'; }
46 .dd-placeholder,
47 .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; }
48 .dd-empty { border: 1px dashed #bbb; min-height: 100px; background-color: #e5e5e5;
49 background-image: -webkit-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff),
50 -webkit-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff);
51 background-image: -moz-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff),
52 -moz-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff);
53 background-image: linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff),
54 linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff);
55 background-size: 60px 60px;
56 background-position: 0 0, 30px 30px;
57 }
58 .dd-dragel { position: absolute; pointer-events: none; z-index: 9999; }
59 .dd-dragel > .dd-item .dd-handle { margin-top: 0; }
60 .dd-dragel .dd-handle {
61 -webkit-box-shadow: 2px 4px 6px 0 rgba(0,0,0,.1);
62 box-shadow: 2px 4px 6px 0 rgba(0,0,0,.1);
63 }
64 /**
65 * Nestable Extras
66 */
67 .nestable-lists { display: block; clear: both; padding: 30px 0; width: 100%; border: 0; border-top: 2px solid #ddd; border-bottom: 2px solid #ddd; }
68 #nestable-menu { padding: 0; margin: 20px 0; }
69 #nestable-output,
70 #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; }
71 #nestable2 .dd-handle {
72 color: #fff;
73 border: 1px solid #999;
74 background: #bbb;
75 background: -webkit-linear-gradient(top, #bbb 0%, #999 100%);
76 background: -moz-linear-gradient(top, #bbb 0%, #999 100%);
77 background: linear-gradient(top, #bbb 0%, #999 100%);
78 }
79 #nestable2 .dd-handle:hover { background: #bbb; }
80 #nestable2 .dd-item > button:before { color: #fff; }
81 @media only screen and (min-width: 700px) {
82 .dd { float: left; width: 48%; }
83 .dd + .dd { margin-left: 2%; }
84 }
85 .dd-hover > .dd-handle { background: #2ea8e5 !important; }
86 /**
87 * Nestable Draggable Handles
88 */
89 .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;
90 background: #fafafa;
91 background: -webkit-linear-gradient(top, #fafafa 0%, #eee 100%);
92 background: -moz-linear-gradient(top, #fafafa 0%, #eee 100%);
93 background: linear-gradient(top, #fafafa 0%, #eee 100%);
94 -webkit-border-radius: 3px;
95 border-radius: 3px;
96 box-sizing: border-box; -moz-box-sizing: border-box;
97 }
98 .dd3-content:hover { color: #2ea8e5; background: #fff; }
99 .dd-dragel > .dd3-item > .dd3-content { margin: 0; }
100 .dd3-item > button { margin-left: 30px; }
101 .dd3-handle { position: absolute; margin: 0; left: 0; top: 0; cursor: pointer; width: 30px; text-indent: 100%; white-space: nowrap; overflow: hidden;
102 border: 1px solid #aaa;
103 background: #ddd;
104 background: -webkit-linear-gradient(top, #ddd 0%, #bbb 100%);
105 background: -moz-linear-gradient(top, #ddd 0%, #bbb 100%);
106 background: linear-gradient(top, #ddd 0%, #bbb 100%);
107 border-top-right-radius: 0;
108 border-bottom-right-radius: 0;
109 }
110 .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; }
111 .dd3-handle:hover { background: #ddd; }
112 /**
113 * Socialite
114 */
115 .socialite { display: block; float: left; height: 35px; }
116 </style>
117 </head>
118 <body>
119
120 <h1>Nestable</h1>
121
122 <p>Drag &amp; drop hierarchical list with mouse and touch compatibility (jQuery plugin)</p>
123
124 <p><strong><a href="https://github.com/dbushell/Nestable">Download on GitHub</a></strong></p>
125
126 <div class="cf">
127 <a href="http://twitter.com/share" class="socialite twitter-share" data-via="dbushell" data-text="jQuery Nestable plugin" data-url="http://dbushell.github.com/Nestable/" data-size="large" rel="nofollow" target="_blank">
128 <span class="vhidden">Share on Twitter</span>
129 </a>
130 </div>
131
132
133 <p><strong>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.</strong></p>
134
135 <menu id="nestable-menu">
136 <button type="button" data-action="expand-all">Expand All</button>
137 <button type="button" data-action="collapse-all">Collapse All</button>
138 </menu>
139
140 <div class="cf nestable-lists">
141
142 <div class="dd" id="nestable">
143 <ol class="dd-list">
144 <li class="dd-item" data-id="1">
145 <div class="dd-handle">Item 1</div>
146 </li>
147 <li class="dd-item" data-id="2">
148 <div class="dd-handle">Item 2</div>
149 <ol class="dd-list">
150 <li class="dd-item" data-id="3"><div class="dd-handle">Item 3</div></li>
151 <li class="dd-item" data-id="4"><div class="dd-handle">Item 4</div></li>
152 <li class="dd-item" data-id="5">
153 <div class="dd-handle">Item 5</div>
154 <ol class="dd-list">
155 <li class="dd-item" data-id="6"><div class="dd-handle">Item 6</div></li>
156 <li class="dd-item" data-id="7"><div class="dd-handle">Item 7</div></li>
157 <li class="dd-item" data-id="8"><div class="dd-handle">Item 8</div></li>
158 </ol>
159 </li>
160 <li class="dd-item" data-id="9"><div class="dd-handle">Item 9</div></li>
161 <li class="dd-item" data-id="10"><div class="dd-handle">Item 10</div></li>
162 </ol>
163 </li>
164 <li class="dd-item" data-id="11">
165 <div class="dd-handle">Item 11</div>
166 </li>
167 <li class="dd-item" data-id="12">
168 <div class="dd-handle">Item 12</div>
169 </li>
170 </ol>
171 </div>
172
173 <div class="dd" id="nestable2">
174 <ol class="dd-list">
175 <li class="dd-item" data-id="13">
176 <div class="dd-handle">Item 13</div>
177 </li>
178 <li class="dd-item" data-id="14">
179 <div class="dd-handle">Item 14</div>
180 </li>
181 <li class="dd-item" data-id="15">
182 <div class="dd-handle">Item 15</div>
183 <ol class="dd-list">
184 <li class="dd-item" data-id="16"><div class="dd-handle">Item 16</div></li>
185 <li class="dd-item" data-id="17"><div class="dd-handle">Item 17</div></li>
186 <li class="dd-item" data-id="18"><div class="dd-handle">Item 18</div></li>
187 </ol>
188 </li>
189 </ol>
190 </div>
191
192 </div>
193
194 <p><strong>Serialised Output (per list)</strong></p>
195
196 <textarea id="nestable-output"></textarea>
197 <textarea id="nestable2-output"></textarea>
198
199 <p>&nbsp;</p>
200
201 <div class="cf nestable-lists">
202
203 <p><strong>Draggable Handles</strong></p>
204
205 <p>If you're clever with your CSS and markup this can be achieved without any JavaScript changes.</p>
206
207 <div class="dd" id="nestable3">
208 <ol class="dd-list">
209 <li class="dd-item dd3-item" data-id="13">
210 <div class="dd-handle dd3-handle">Drag</div><div class="dd3-content">Item 13</div>
211 </li>
212 <li class="dd-item dd3-item" data-id="14">
213 <div class="dd-handle dd3-handle">Drag</div><div class="dd3-content">Item 14</div>
214 </li>
215 <li class="dd-item dd3-item" data-id="15">
216 <div class="dd-handle dd3-handle">Drag</div><div class="dd3-content">Item 15</div>
217 <ol class="dd-list">
218 <li class="dd-item dd3-item" data-id="16">
219 <div class="dd-handle dd3-handle">Drag</div><div class="dd3-content">Item 16</div>
220 </li>
221 <li class="dd-item dd3-item" data-id="17">
222 <div class="dd-handle dd3-handle">Drag</div><div class="dd3-content">Item 17</div>
223 </li>
224 <li class="dd-item dd3-item" data-id="18">
225 <div class="dd-handle dd3-handle">Drag</div><div class="dd3-content">Item 18</div>
226 </li>
227 </ol>
228 </li>
229 </ol>
230 </div>
231
232 </div>
233
234 <p class="small">Copyright &copy; <a href="https://dbushell.com/">David Bushell</a> | Made for <a href="http://www.browserlondon.com/">Browser</a></p>
235
236 <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
237 <script src="jquery.nestable.js"></script>
238 <script>
239 $(document).ready(function()
240 {
241 var updateOutput = function(e)
242 {
243 var list = e.length ? e : $(e.target),
244 output = list.data('output');
245 if (window.JSON) {
246 output.val(window.JSON.stringify(list.nestable('serialize')));//, null, 2));
247 } else {
248 output.val('JSON browser support required for this demo.');
249 }
250 };
251 // activate Nestable for list 1
252 $('#nestable').nestable({
253 group: 1
254 })
255 .on('change', updateOutput);
256 // activate Nestable for list 2
257 $('#nestable2').nestable({
258 group: 1
259 })
260 .on('change', updateOutput);
261 // output initial serialised data
262 updateOutput($('#nestable').data('output', $('#nestable-output')));
263 updateOutput($('#nestable2').data('output', $('#nestable2-output')));
264 $('#nestable-menu').on('click', function(e)
265 {
266 var target = $(e.target),
267 action = target.data('action');
268 if (action === 'expand-all') {
269 $('.dd').nestable('expandAll');
270 }
271 if (action === 'collapse-all') {
272 $('.dd').nestable('collapseAll');
273 }
274 });
275 $('#nestable3').nestable();
276 });
277 </script>
278 </body>
279 </html>
k2shop/usr/k2shop/libs/nestmenu/jquery.nestable.js
File was created 1 /*!
2 * Nestable jQuery Plugin - Copyright (c) 2012 David Bushell - http://dbushell.com/
3 * Dual-licensed under the BSD or MIT licenses
4 */
5 ;(function($, window, document, undefined)
6 {
7 var hasTouch = 'ontouchstart' in document;
8
9 /**
10 * Detect CSS pointer-events property
11 * events are normally disabled on the dragging element to avoid conflicts
12 * https://github.com/ausi/Feature-detection-technique-for-pointer-events/blob/master/modernizr-pointerevents.js
13 */
14 var hasPointerEvents = (function()
15 {
16 var el = document.createElement('div'),
17 docEl = document.documentElement;
18 if (!('pointerEvents' in el.style)) {
19 return false;
20 }
21 el.style.pointerEvents = 'auto';
22 el.style.pointerEvents = 'x';
23 docEl.appendChild(el);
24 var supports = window.getComputedStyle && window.getComputedStyle(el, '').pointerEvents === 'auto';
25 docEl.removeChild(el);
26 return !!supports;
27 })();
28
29 var defaults = {
30 listNodeName : 'ol',
31 itemNodeName : 'li',
32 rootClass : 'dd',
33 listClass : 'dd-list',
34 itemClass : 'dd-item',
35 dragClass : 'dd-dragel',
36 handleClass : 'dd-handle',
37 collapsedClass : 'dd-collapsed',
38 placeClass : 'dd-placeholder',
39 noDragClass : 'dd-nodrag',
40 emptyClass : 'dd-empty',
41 expandBtnHTML : '<button data-action="expand" type="button">Expand</button>',
42 collapseBtnHTML : '<button data-action="collapse" type="button">Collapse</button>',
43 group : 0,
44 maxDepth : 5,
45 threshold : 20
46 };
47
48 function Plugin(element, options)
49 {
50 this.w = $(document);
51 this.el = $(element);
52 this.options = $.extend({}, defaults, options);
53 this.init();
54 }
55
56 Plugin.prototype = {
57
58 init: function()
59 {
60 var list = this;
61
62 list.reset();
63
64 list.el.data('nestable-group', this.options.group);
65
66 list.placeEl = $('<div class="' + list.options.placeClass + '"/>');
67
68 $.each(this.el.find(list.options.itemNodeName), function(k, el) {
69 list.setParent($(el));
70 });
71
72 list.el.on('click', 'button', function(e) {
73 if (list.dragEl) {
74 return;
75 }
76 var target = $(e.currentTarget),
77 action = target.data('action'),
78 item = target.parent(list.options.itemNodeName);
79 if (action === 'collapse') {
80 list.collapseItem(item);
81 }
82 if (action === 'expand') {
83 list.expandItem(item);
84 }
85 });
86
87 var onStartEvent = function(e)
88 {
89 var handle = $(e.target);
90 if (!handle.hasClass(list.options.handleClass)) {
91 if (handle.closest('.' + list.options.noDragClass).length) {
92 return;
93 }
94 handle = handle.closest('.' + list.options.handleClass);
95 }
96
97 if (!handle.length || list.dragEl) {
98 return;
99 }
100
101 list.isTouch = /^touch/.test(e.type);
102 if (list.isTouch && e.touches.length !== 1) {
103 return;
104 }
105
106 e.preventDefault();
107 list.dragStart(e.touches ? e.touches[0] : e);
108 };
109
110 var onMoveEvent = function(e)
111 {
112 if (list.dragEl) {
113 e.preventDefault();
114 list.dragMove(e.touches ? e.touches[0] : e);
115 }
116 };
117
118 var onEndEvent = function(e)
119 {
120 if (list.dragEl) {
121 e.preventDefault();
122 list.dragStop(e.touches ? e.touches[0] : e);
123 }
124 };
125
126 if (hasTouch) {
127 list.el[0].addEventListener('touchstart', onStartEvent, false);
128 window.addEventListener('touchmove', onMoveEvent, false);
129 window.addEventListener('touchend', onEndEvent, false);
130 window.addEventListener('touchcancel', onEndEvent, false);
131 }
132
133 list.el.on('mousedown', onStartEvent);
134 list.w.on('mousemove', onMoveEvent);
135 list.w.on('mouseup', onEndEvent);
136
137 },
138
139 serialize: function()
140 {
141 var data,
142 depth = 0,
143 list = this;
144 step = function(level, depth)
145 {
146 var array = [ ],
147 items = level.children(list.options.itemNodeName);
148 items.each(function()
149 {
150 var li = $(this),
151 item = $.extend({}, li.data()),
152 sub = li.children(list.options.listNodeName);
153 if (sub.length) {
154 item.children = step(sub, depth + 1);
155 }
156 array.push(item);
157 });
158 return array;
159 };
160 data = step(list.el.find(list.options.listNodeName).first(), depth);
161 return data;
162 },
163
164 serialise: function()
165 {
166 return this.serialize();
167 },
168
169 reset: function()
170 {
171 this.mouse = {
172 offsetX : 0,
173 offsetY : 0,
174 startX : 0,
175 startY : 0,
176 lastX : 0,
177 lastY : 0,
178 nowX : 0,
179 nowY : 0,
180 distX : 0,
181 distY : 0,
182 dirAx : 0,
183 dirX : 0,
184 dirY : 0,
185 lastDirX : 0,
186 lastDirY : 0,
187 distAxX : 0,
188 distAxY : 0
189 };
190 this.isTouch = false;
191 this.moving = false;
192 this.dragEl = null;
193 this.dragRootEl = null;
194 this.dragDepth = 0;
195 this.hasNewRoot = false;
196 this.pointEl = null;
197 },
198
199 expandItem: function(li)
200 {
201 li.removeClass(this.options.collapsedClass);
202 li.children('[data-action="expand"]').hide();
203 li.children('[data-action="collapse"]').show();
204 li.children(this.options.listNodeName).show();
205 },
206
207 collapseItem: function(li)
208 {
209 var lists = li.children(this.options.listNodeName);
210 if (lists.length) {
211 li.addClass(this.options.collapsedClass);
212 li.children('[data-action="collapse"]').hide();
213 li.children('[data-action="expand"]').show();
214 li.children(this.options.listNodeName).hide();
215 }
216 },
217
218 expandAll: function()
219 {
220 var list = this;
221 list.el.find(list.options.itemNodeName).each(function() {
222 list.expandItem($(this));
223 });
224 },
225
226 collapseAll: function()
227 {
228 var list = this;
229 list.el.find(list.options.itemNodeName).each(function() {
230 list.collapseItem($(this));
231 });
232 },
233
234 setParent: function(li)
235 {
236 if (li.children(this.options.listNodeName).length) {
237 li.prepend($(this.options.expandBtnHTML));
238 li.prepend($(this.options.collapseBtnHTML));
239 }
240 li.children('[data-action="expand"]').hide();
241 },
242
243 unsetParent: function(li)
244 {
245 li.removeClass(this.options.collapsedClass);
246 li.children('[data-action]').remove();
247 li.children(this.options.listNodeName).remove();
248 },
249
250 dragStart: function(e)
251 {
252 var mouse = this.mouse,
253 target = $(e.target),
254 dragItem = target.closest(this.options.itemNodeName);
255
256 this.placeEl.css('height', dragItem.height());
257
258 mouse.offsetX = e.offsetX !== undefined ? e.offsetX : e.pageX - target.offset().left;
259 mouse.offsetY = e.offsetY !== undefined ? e.offsetY : e.pageY - target.offset().top;
260 mouse.startX = mouse.lastX = e.pageX;
261 mouse.startY = mouse.lastY = e.pageY;
262
263 this.dragRootEl = this.el;
264
265 this.dragEl = $(document.createElement(this.options.listNodeName)).addClass(this.options.listClass + ' ' + this.options.dragClass);
266 this.dragEl.css('width', dragItem.width());
267
268 dragItem.after(this.placeEl);
269 dragItem[0].parentNode.removeChild(dragItem[0]);
270 dragItem.appendTo(this.dragEl);
271
272 $(document.body).append(this.dragEl);
273 this.dragEl.css({
274 'left' : e.pageX - mouse.offsetX,
275 'top' : e.pageY - mouse.offsetY
276 });
277 // total depth of dragging item
278 var i, depth,
279 items = this.dragEl.find(this.options.itemNodeName);
280 for (i = 0; i < items.length; i++) {
281 depth = $(items[i]).parents(this.options.listNodeName).length;
282 if (depth > this.dragDepth) {
283 this.dragDepth = depth;
284 }
285 }
286 },
287
288 dragStop: function(e)
289 {
290 var el = this.dragEl.children(this.options.itemNodeName).first();
291 el[0].parentNode.removeChild(el[0]);
292 this.placeEl.replaceWith(el);
293
294 this.dragEl.remove();
295 this.el.trigger('change');
296 if (this.hasNewRoot) {
297 this.dragRootEl.trigger('change');
298 }
299 this.reset();
300 },
301
302 dragMove: function(e)
303 {
304 var list, parent, prev, next, depth,
305 opt = this.options,
306 mouse = this.mouse;
307
308 this.dragEl.css({
309 'left' : e.pageX - mouse.offsetX,
310 'top' : e.pageY - mouse.offsetY
311 });
312
313 // mouse position last events
314 mouse.lastX = mouse.nowX;
315 mouse.lastY = mouse.nowY;
316 // mouse position this events
317 mouse.nowX = e.pageX;
318 mouse.nowY = e.pageY;
319 // distance mouse moved between events
320 mouse.distX = mouse.nowX - mouse.lastX;
321 mouse.distY = mouse.nowY - mouse.lastY;
322 // direction mouse was moving
323 mouse.lastDirX = mouse.dirX;
324 mouse.lastDirY = mouse.dirY;
325 // direction mouse is now moving (on both axis)
326 mouse.dirX = mouse.distX === 0 ? 0 : mouse.distX > 0 ? 1 : -1;
327 mouse.dirY = mouse.distY === 0 ? 0 : mouse.distY > 0 ? 1 : -1;
328 // axis mouse is now moving on
329 var newAx = Math.abs(mouse.distX) > Math.abs(mouse.distY) ? 1 : 0;
330
331 // do nothing on first move
332 if (!mouse.moving) {
333 mouse.dirAx = newAx;
334 mouse.moving = true;
335 return;
336 }
337
338 // calc distance moved on this axis (and direction)
339 if (mouse.dirAx !== newAx) {
340 mouse.distAxX = 0;
341 mouse.distAxY = 0;
342 } else {
343 mouse.distAxX += Math.abs(mouse.distX);
344 if (mouse.dirX !== 0 && mouse.dirX !== mouse.lastDirX) {
345 mouse.distAxX = 0;
346 }
347 mouse.distAxY += Math.abs(mouse.distY);
348 if (mouse.dirY !== 0 && mouse.dirY !== mouse.lastDirY) {
349 mouse.distAxY = 0;
350 }
351 }
352 mouse.dirAx = newAx;
353
354 /**
355 * move horizontal
356 */
357 if (mouse.dirAx && mouse.distAxX >= opt.threshold) {
358 // reset move distance on x-axis for new phase
359 mouse.distAxX = 0;
360 prev = this.placeEl.prev(opt.itemNodeName);
361 // increase horizontal level if previous sibling exists and is not collapsed
362 if (mouse.distX > 0 && prev.length && !prev.hasClass(opt.collapsedClass)) {
363 // cannot increase level when item above is collapsed
364 list = prev.find(opt.listNodeName).last();
365 // check if depth limit has reached
366 depth = this.placeEl.parents(opt.listNodeName).length;
367 if (depth + this.dragDepth <= opt.maxDepth) {
368 // create new sub-level if one doesn't exist
369 if (!list.length) {
370 list = $('<' + opt.listNodeName + '/>').addClass(opt.listClass);
371 list.append(this.placeEl);
372 prev.append(list);
373 this.setParent(prev);
374 } else {
375 // else append to next level up
376 list = prev.children(opt.listNodeName).last();
377 list.append(this.placeEl);
378 }
379 }
380 }
381 // decrease horizontal level
382 if (mouse.distX < 0) {
383 // we can't decrease a level if an item preceeds the current one
384 next = this.placeEl.next(opt.itemNodeName);
385 if (!next.length) {
386 parent = this.placeEl.parent();
387 this.placeEl.closest(opt.itemNodeName).after(this.placeEl);
388 if (!parent.children().length) {
389 this.unsetParent(parent.parent());
390 }
391 }
392 }
393 }
394
395 var isEmpty = false;
396
397 // find list item under cursor
398 if (!hasPointerEvents) {
399 this.dragEl[0].style.visibility = 'hidden';
400 }
401 this.pointEl = $(document.elementFromPoint(e.pageX - document.body.scrollLeft, e.pageY - (window.pageYOffset || document.documentElement.scrollTop)));
402 if (!hasPointerEvents) {
403 this.dragEl[0].style.visibility = 'visible';
404 }
405 if (this.pointEl.hasClass(opt.handleClass)) {
406 this.pointEl = this.pointEl.parent(opt.itemNodeName);
407 }
408 if (this.pointEl.hasClass(opt.emptyClass)) {
409 isEmpty = true;
410 }
411 else if (!this.pointEl.length || !this.pointEl.hasClass(opt.itemClass)) {
412 return;
413 }
414
415 // find parent list of item under cursor
416 var pointElRoot = this.pointEl.closest('.' + opt.rootClass),
417 isNewRoot = this.dragRootEl.data('nestable-id') !== pointElRoot.data('nestable-id');
418
419 /**
420 * move vertical
421 */
422 if (!mouse.dirAx || isNewRoot || isEmpty) {
423 // check if groups match if dragging over new root
424 if (isNewRoot && opt.group !== pointElRoot.data('nestable-group')) {
425 return;
426 }
427 // check depth limit
428 depth = this.dragDepth - 1 + this.pointEl.parents(opt.listNodeName).length;
429 if (depth > opt.maxDepth) {
430 return;
431 }
432 var before = e.pageY < (this.pointEl.offset().top + this.pointEl.height() / 2);
433 parent = this.placeEl.parent();
434 // if empty create new list to replace empty placeholder
435 if (isEmpty) {
436 list = $(document.createElement(opt.listNodeName)).addClass(opt.listClass);
437 list.append(this.placeEl);
438 this.pointEl.replaceWith(list);
439 }
440 else if (before) {
441 this.pointEl.before(this.placeEl);
442 }
443 else {
444 this.pointEl.after(this.placeEl);
445 }
446 if (!parent.children().length) {
447 this.unsetParent(parent.parent());
448 }
449 if (!this.dragRootEl.find(opt.itemNodeName).length) {
450 this.dragRootEl.append('<div class="' + opt.emptyClass + '"/>');
451 }
452 // parent root list has changed
453 if (isNewRoot) {
454 this.dragRootEl = pointElRoot;
455 this.hasNewRoot = this.el[0] !== this.dragRootEl[0];
456 }
457 }
458 }
459
460 };
461
462 $.fn.nestable = function(params)
463 {
464 var lists = this,
465 retval = this;
466
467 lists.each(function()
468 {
469 var plugin = $(this).data("nestable");
470
471 if (!plugin) {
472 $(this).data("nestable", new Plugin(this, params));
473 $(this).data("nestable-id", new Date().getTime());
474 } else {
475 if (typeof params === 'string' && typeof plugin[params] === 'function') {
476 retval = plugin[params]();
477 }
478 }
479 });
480
481 return retval || lists;
482 };
483
484 })(window.jQuery || window.Zepto, window, document);
k2shop/usr/k2shop/libs/nestmenu/nestable.css
File was created 1
2 /**
3 * Nestable
4 */
5 .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; }
6 .dd-list { display: block; position: relative; margin: 0; padding: 0; list-style: none; }
7 .dd-list .dd-list { padding-left: 30px; }
8 .dd-collapsed .dd-list { display: none; }
9 .dd-item,
10 .dd-empty,
11 .dd-placeholder { display: block; position: relative; margin: 0; padding: 0; min-height: 20px; font-size: 13px; line-height: 20px; }
12 .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;
13 background: #fafafa;
14 background: -webkit-linear-gradient(top, #fafafa 0%, #eee 100%);
15 background: -moz-linear-gradient(top, #fafafa 0%, #eee 100%);
16 background: linear-gradient(top, #fafafa 0%, #eee 100%);
17 -webkit-border-radius: 3px;
18 border-radius: 3px;
19 box-sizing: border-box; -moz-box-sizing: border-box;
20 }
21 .dd-handle:hover { color: #2ea8e5; background: #fff; }
22 .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; }
23 .dd-item > button:before { content: '+'; display: block; position: absolute; width: 100%; text-align: center; text-indent: 0; }
24 .dd-item > button[data-action="collapse"]:before { content: '-'; }
25 .dd-placeholder,
26 .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; }
27 .dd-empty { border: 1px dashed #bbb; min-height: 100px; background-color: #e5e5e5;
28 background-image: -webkit-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff),
29 -webkit-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff);
30 background-image: -moz-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff),
31 -moz-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff);
32 background-image: linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff),
33 linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff);
34 background-size: 60px 60px;
35 background-position: 0 0, 30px 30px;
36 }
37 .dd-dragel { position: absolute; pointer-events: none; z-index: 9999; }
38 .dd-dragel > .dd-item .dd-handle { margin-top: 0; }
39 .dd-dragel .dd-handle {
40 -webkit-box-shadow: 2px 4px 6px 0 rgba(0,0,0,.1);
41 box-shadow: 2px 4px 6px 0 rgba(0,0,0,.1);
42 }
43 /**
44 * Nestable Extras
45 */
46 .nestable-lists { display: block; clear: both; padding: 30px 0; width: 100%; border: 0; border-top: 2px solid #ddd; border-bottom: 2px solid #ddd; }
47 #nestable-menu { padding: 0; margin: 20px 0; }
48 #nestable-output,
49 #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; }
50 #nestable2 .dd-handle {
51 color: #fff;
52 border: 1px solid #999;
53 background: #bbb;
54 background: -webkit-linear-gradient(top, #bbb 0%, #999 100%);
55 background: -moz-linear-gradient(top, #bbb 0%, #999 100%);
56 background: linear-gradient(top, #bbb 0%, #999 100%);
57 }
58 #nestable2 .dd-handle:hover { background: #bbb; }
59 #nestable2 .dd-item > button:before { color: #fff; }
60 @media only screen and (min-width: 700px) {
61 /*.dd { float: left; width: 48%; }*/
62 .dd + .dd { margin-left: 2%; }
63 }
64 .dd-hover > .dd-handle { background: #2ea8e5 !important; }
65 /**
66 * Nestable Draggable Handles
67 */
68 .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;
69 background: #fafafa;
70 background: -webkit-linear-gradient(top, #fafafa 0%, #eee 100%);
71 background: -moz-linear-gradient(top, #fafafa 0%, #eee 100%);
72 background: linear-gradient(top, #fafafa 0%, #eee 100%);
73 -webkit-border-radius: 3px;
74 border-radius: 3px;
75 box-sizing: border-box; -moz-box-sizing: border-box;
76 }
77 .dd3-content:hover { color: #2ea8e5; background: #fff; }
78 .dd-dragel > .dd3-item > .dd3-content { margin: 0; }
79 .dd3-item > button { margin-left: 30px; }
80 .dd3-handle { position: absolute; margin: 0; left: 0; top: 0; cursor: pointer; width: 30px; text-indent: 100%; white-space: nowrap; overflow: hidden;
81 border: 1px solid #aaa;
82 background: #ddd;
83 background: -webkit-linear-gradient(top, #ddd 0%, #bbb 100%);
84 background: -moz-linear-gradient(top, #ddd 0%, #bbb 100%);
85 background: linear-gradient(top, #ddd 0%, #bbb 100%);
86 border-top-right-radius: 0;
87 border-bottom-right-radius: 0;
88 }
89 .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; }
90 .dd3-handle:hover { background: #ddd; }
91 /**
92 * Socialite
93 */
94 .socialite { display: block; float: left; height: 35px; }
k2shop/usr/k2shop/libs/yaml/Spyc.php
File was created 1 <?php
2 /**
3 * Spyc -- A Simple PHP YAML Class
4 * @version 0.6.2
5 * @author Vlad Andersen <vlad.andersen@gmail.com>
6 * @author Chris Wanstrath <chris@ozmm.org>
7 * @link https://github.com/mustangostang/spyc/
8 * @copyright Copyright 2005-2006 Chris Wanstrath, 2006-2011 Vlad Andersen
9 * @license http://www.opensource.org/licenses/mit-license.php MIT License
10 * @package Spyc
11 */
12 if (!function_exists('spyc_load')) {
13 /**
14 * Parses YAML to array.
15 * @param string $string YAML string.
16 * @return array
17 */
18 function spyc_load ($string) {
19 return Spyc::YAMLLoadString($string);
20 }
21 }
22 if (!function_exists('spyc_load_file')) {
23 /**
24 * Parses YAML to array.
25 * @param string $file Path to YAML file.
26 * @return array
27 */
28 function spyc_load_file ($file) {
29 return Spyc::YAMLLoad($file);
30 }
31 }
32 if (!function_exists('spyc_dump')) {
33 /**
34 * Dumps array to YAML.
35 * @param array $data Array.
36 * @return string
37 */
38 function spyc_dump ($data) {
39 return Spyc::YAMLDump($data, false, false, true);
40 }
41 }
42 if (!class_exists('Spyc')) {
43 /**
44 * The Simple PHP YAML Class.
45 *
46 * This class can be used to read a YAML file and convert its contents
47 * into a PHP array. It currently supports a very limited subsection of
48 * the YAML spec.
49 *
50 * Usage:
51 * <code>
52 * $Spyc = new Spyc;
53 * $array = $Spyc->load($file);
54 * </code>
55 * or:
56 * <code>
57 * $array = Spyc::YAMLLoad($file);
58 * </code>
59 * or:
60 * <code>
61 * $array = spyc_load_file($file);
62 * </code>
63 * @package Spyc
64 */
65 class Spyc {
66 // SETTINGS
67 const REMPTY = "\0\0\0\0\0";
68 /**
69 * Setting this to true will force YAMLDump to enclose any string value in
70 * quotes. False by default.
71 *
72 * @var bool
73 */
74 public $setting_dump_force_quotes = false;
75 /**
76 * Setting this to true will forse YAMLLoad to use syck_load function when
77 * possible. False by default.
78 * @var bool
79 */
80 public $setting_use_syck_is_possible = false;
81 /**#@+
82 * @access private
83 * @var mixed
84 */
85 private $_dumpIndent;
86 private $_dumpWordWrap;
87 private $_containsGroupAnchor = false;
88 private $_containsGroupAlias = false;
89 private $path;
90 private $result;
91 private $LiteralPlaceHolder = '___YAML_Literal_Block___';
92 private $SavedGroups = array();
93 private $indent;
94 /**
95 * Path modifier that should be applied after adding current element.
96 * @var array
97 */
98 private $delayedPath = array();
99 /**#@+
100 * @access public
101 * @var mixed
102 */
103 public $_nodeId;
104 /**
105 * Load a valid YAML string to Spyc.
106 * @param string $input
107 * @return array
108 */
109 public function load ($input) {
110 return $this->_loadString($input);
111 }
112 /**
113 * Load a valid YAML file to Spyc.
114 * @param string $file
115 * @return array
116 */
117 public function loadFile ($file) {
118 return $this->_load($file);
119 }
120 /**
121 * Load YAML into a PHP array statically
122 *
123 * The load method, when supplied with a YAML stream (string or file),
124 * will do its best to convert YAML in a file into a PHP array. Pretty
125 * simple.
126 * Usage:
127 * <code>
128 * $array = Spyc::YAMLLoad('lucky.yaml');
129 * print_r($array);
130 * </code>
131 * @access public
132 * @return array
133 * @param string $input Path of YAML file or string containing YAML
134 */
135 public static function YAMLLoad($input) {
136 $Spyc = new Spyc;
137 return $Spyc->_load($input);
138 }
139 /**
140 * Load a string of YAML into a PHP array statically
141 *
142 * The load method, when supplied with a YAML string, will do its best
143 * to convert YAML in a string into a PHP array. Pretty simple.
144 *
145 * Note: use this function if you don't want files from the file system
146 * loaded and processed as YAML. This is of interest to people concerned
147 * about security whose input is from a string.
148 *
149 * Usage:
150 * <code>
151 * $array = Spyc::YAMLLoadString("---\n0: hello world\n");
152 * print_r($array);
153 * </code>
154 * @access public
155 * @return array
156 * @param string $input String containing YAML
157 */
158 public static function YAMLLoadString($input) {
159 $Spyc = new Spyc;
160 return $Spyc->_loadString($input);
161 }
162 /**
163 * Dump YAML from PHP array statically
164 *
165 * The dump method, when supplied with an array, will do its best
166 * to convert the array into friendly YAML. Pretty simple. Feel free to
167 * save the returned string as nothing.yaml and pass it around.
168 *
169 * Oh, and you can decide how big the indent is and what the wordwrap
170 * for folding is. Pretty cool -- just pass in 'false' for either if
171 * you want to use the default.
172 *
173 * Indent's default is 2 spaces, wordwrap's default is 40 characters. And
174 * you can turn off wordwrap by passing in 0.
175 *
176 * @access public
177 * @return string
178 * @param array|\stdClass $array PHP array
179 * @param int $indent Pass in false to use the default, which is 2
180 * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40)
181 * @param bool $no_opening_dashes Do not start YAML file with "---\n"
182 */
183 public static function YAMLDump($array, $indent = false, $wordwrap = false, $no_opening_dashes = false) {
184 $spyc = new Spyc;
185 return $spyc->dump($array, $indent, $wordwrap, $no_opening_dashes);
186 }
187 /**
188 * Dump PHP array to YAML
189 *
190 * The dump method, when supplied with an array, will do its best
191 * to convert the array into friendly YAML. Pretty simple. Feel free to
192 * save the returned string as tasteful.yaml and pass it around.
193 *
194 * Oh, and you can decide how big the indent is and what the wordwrap
195 * for folding is. Pretty cool -- just pass in 'false' for either if
196 * you want to use the default.
197 *
198 * Indent's default is 2 spaces, wordwrap's default is 40 characters. And
199 * you can turn off wordwrap by passing in 0.
200 *
201 * @access public
202 * @return string
203 * @param array $array PHP array
204 * @param int $indent Pass in false to use the default, which is 2
205 * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40)
206 */
207 public function dump($array,$indent = false,$wordwrap = false, $no_opening_dashes = false) {
208 // Dumps to some very clean YAML. We'll have to add some more features
209 // and options soon. And better support for folding.
210 // New features and options.
211 if ($indent === false or !is_numeric($indent)) {
212 $this->_dumpIndent = 2;
213 } else {
214 $this->_dumpIndent = $indent;
215 }
216 if ($wordwrap === false or !is_numeric($wordwrap)) {
217 $this->_dumpWordWrap = 40;
218 } else {
219 $this->_dumpWordWrap = $wordwrap;
220 }
221 // New YAML document
222 $string = "";
223 if (!$no_opening_dashes) $string = "---\n";
224 // Start at the base of the array and move through it.
225 if ($array) {
226 $array = (array)$array;
227 $previous_key = -1;
228 foreach ($array as $key => $value) {
229 if (!isset($first_key)) $first_key = $key;
230 $string .= $this->_yamlize($key,$value,0,$previous_key, $first_key, $array);
231 $previous_key = $key;
232 }
233 }
234 return $string;
235 }
236 /**
237 * Attempts to convert a key / value array item to YAML
238 * @access private
239 * @return string
240 * @param $key The name of the key
241 * @param $value The value of the item
242 * @param $indent The indent of the current node
243 */
244 private function _yamlize($key,$value,$indent, $previous_key = -1, $first_key = 0, $source_array = null) {
245 if(is_object($value)) $value = (array)$value;
246 if (is_array($value)) {
247 if (empty ($value))
248 return $this->_dumpNode($key, array(), $indent, $previous_key, $first_key, $source_array);
249 // It has children. What to do?
250 // Make it the right kind of item
251 $string = $this->_dumpNode($key, self::REMPTY, $indent, $previous_key, $first_key, $source_array);
252 // Add the indent
253 $indent += $this->_dumpIndent;
254 // Yamlize the array
255 $string .= $this->_yamlizeArray($value,$indent);
256 } elseif (!is_array($value)) {
257 // It doesn't have children. Yip.
258 $string = $this->_dumpNode($key, $value, $indent, $previous_key, $first_key, $source_array);
259 }
260 return $string;
261 }
262 /**
263 * Attempts to convert an array to YAML
264 * @access private
265 * @return string
266 * @param $array The array you want to convert
267 * @param $indent The indent of the current level
268 */
269 private function _yamlizeArray($array,$indent) {
270 if (is_array($array)) {
271 $string = '';
272 $previous_key = -1;
273 foreach ($array as $key => $value) {
274 if (!isset($first_key)) $first_key = $key;
275 $string .= $this->_yamlize($key, $value, $indent, $previous_key, $first_key, $array);
276 $previous_key = $key;
277 }
278 return $string;
279 } else {
280 return false;
281 }
282 }
283 /**
284 * Returns YAML from a key and a value
285 * @access private
286 * @return string
287 * @param $key The name of the key
288 * @param $value The value of the item
289 * @param $indent The indent of the current node
290 */
291 private function _dumpNode($key, $value, $indent, $previous_key = -1, $first_key = 0, $source_array = null) {
292 // do some folding here, for blocks
293 if (is_string ($value) && ((strpos($value,"\n") !== false || strpos($value,": ") !== false || strpos($value,"- ") !== false ||
294 strpos($value,"*") !== false || strpos($value,"#") !== false || strpos($value,"<") !== false || strpos($value,">") !== false || strpos ($value, '%') !== false || strpos ($value, ' ') !== false ||
295 strpos($value,"[") !== false || strpos($value,"]") !== false || strpos($value,"{") !== false || strpos($value,"}") !== false) || strpos($value,"&") !== false || strpos($value, "'") !== false || strpos($value, "!") === 0 ||
296 substr ($value, -1, 1) == ':')
297 ) {
298 $value = $this->_doLiteralBlock($value,$indent);
299 } else {
300 $value = $this->_doFolding($value,$indent);
301 }
302 if ($value === array()) $value = '[ ]';
303 if ($value === "") $value = '""';
304 if (self::isTranslationWord($value)) {
305 $value = $this->_doLiteralBlock($value, $indent);
306 }
307 if (trim ($value) != $value)
308 $value = $this->_doLiteralBlock($value,$indent);
309 if (is_bool($value)) {
310 $value = $value ? "true" : "false";
311 }
312 if ($value === null) $value = 'null';
313 if ($value === "'" . self::REMPTY . "'") $value = null;
314 $spaces = str_repeat(' ',$indent);
315 //if (is_int($key) && $key - 1 == $previous_key && $first_key===0) {
316 if (is_array ($source_array) && array_keys($source_array) === range(0, count($source_array) - 1)) {
317 // It's a sequence
318 $string = $spaces.'- '.$value."\n";
319 } else {
320 // if ($first_key===0) throw new Exception('Keys are all screwy. The first one was zero, now it\'s "'. $key .'"');
321 // It's mapped
322 if (strpos($key, ":") !== false || strpos($key, "#") !== false) { $key = '"' . $key . '"'; }
323 $string = rtrim ($spaces.$key.': '.$value)."\n";
324 }
325 return $string;
326 }
327 /**
328 * Creates a literal block for dumping
329 * @access private
330 * @return string
331 * @param $value
332 * @param $indent int The value of the indent
333 */
334 private function _doLiteralBlock($value,$indent) {
335 if ($value === "\n") return '\n';
336 if (strpos($value, "\n") === false && strpos($value, "'") === false) {
337 return sprintf ("'%s'", $value);
338 }
339 if (strpos($value, "\n") === false && strpos($value, '"') === false) {
340 return sprintf ('"%s"', $value);
341 }
342 $exploded = explode("\n",$value);
343 $newValue = '|';
344 if (isset($exploded[0]) && ($exploded[0] == "|" || $exploded[0] == "|-" || $exploded[0] == ">")) {
345 $newValue = $exploded[0];
346 unset($exploded[0]);
347 }
348 $indent += $this->_dumpIndent;
349 $spaces = str_repeat(' ',$indent);
350 foreach ($exploded as $line) {
351 $line = trim($line);
352 if (strpos($line, '"') === 0 && strrpos($line, '"') == (strlen($line)-1) || strpos($line, "'") === 0 && strrpos($line, "'") == (strlen($line)-1)) {
353 $line = substr($line, 1, -1);
354 }
355 $newValue .= "\n" . $spaces . ($line);
356 }
357 return $newValue;
358 }
359 /**
360 * Folds a string of text, if necessary
361 * @access private
362 * @return string
363 * @param $value The string you wish to fold
364 */
365 private function _doFolding($value,$indent) {
366 // Don't do anything if wordwrap is set to 0
367 if ($this->_dumpWordWrap !== 0 && is_string ($value) && strlen($value) > $this->_dumpWordWrap) {
368 $indent += $this->_dumpIndent;
369 $indent = str_repeat(' ',$indent);
370 $wrapped = wordwrap($value,$this->_dumpWordWrap,"\n$indent");
371 $value = ">\n".$indent.$wrapped;
372 } else {
373 if ($this->setting_dump_force_quotes && is_string ($value) && $value !== self::REMPTY)
374 $value = '"' . $value . '"';
375 if (is_numeric($value) && is_string($value))
376 $value = '"' . $value . '"';
377 }
378 return $value;
379 }
380 private function isTrueWord($value) {
381 $words = self::getTranslations(array('true', 'on', 'yes', 'y'));
382 return in_array($value, $words, true);
383 }
384 private function isFalseWord($value) {
385 $words = self::getTranslations(array('false', 'off', 'no', 'n'));
386 return in_array($value, $words, true);
387 }
388 private function isNullWord($value) {
389 $words = self::getTranslations(array('null', '~'));
390 return in_array($value, $words, true);
391 }
392 private function isTranslationWord($value) {
393 return (
394 self::isTrueWord($value) ||
395 self::isFalseWord($value) ||
396 self::isNullWord($value)
397 );
398 }
399 /**
400 * Coerce a string into a native type
401 * Reference: http://yaml.org/type/bool.html
402 * TODO: Use only words from the YAML spec.
403 * @access private
404 * @param $value The value to coerce
405 */
406 private function coerceValue(&$value) {
407 if (self::isTrueWord($value)) {
408 $value = true;
409 } else if (self::isFalseWord($value)) {
410 $value = false;
411 } else if (self::isNullWord($value)) {
412 $value = null;
413 }
414 }
415 /**
416 * Given a set of words, perform the appropriate translations on them to
417 * match the YAML 1.1 specification for type coercing.
418 * @param $words The words to translate
419 * @access private
420 */
421 private static function getTranslations(array $words) {
422 $result = array();
423 foreach ($words as $i) {
424 $result = array_merge($result, array(ucfirst($i), strtoupper($i), strtolower($i)));
425 }
426 return $result;
427 }
428 // LOADING FUNCTIONS
429 private function _load($input) {
430 $Source = $this->loadFromSource($input);
431 return $this->loadWithSource($Source);
432 }
433 private function _loadString($input) {
434 $Source = $this->loadFromString($input);
435 return $this->loadWithSource($Source);
436 }
437 private function loadWithSource($Source) {
438 if (empty ($Source)) return array();
439 if ($this->setting_use_syck_is_possible && function_exists ('syck_load')) {
440 $array = syck_load (implode ("\n", $Source));
441 return is_array($array) ? $array : array();
442 }
443 $this->path = array();
444 $this->result = array();
445 $cnt = count($Source);
446 for ($i = 0; $i < $cnt; $i++) {
447 $line = $Source[$i];
448 $this->indent = strlen($line) - strlen(ltrim($line));
449 $tempPath = $this->getParentPathByIndent($this->indent);
450 $line = self::stripIndent($line, $this->indent);
451 if (self::isComment($line)) continue;
452 if (self::isEmpty($line)) continue;
453 $this->path = $tempPath;
454 $literalBlockStyle = self::startsLiteralBlock($line);
455 if ($literalBlockStyle) {
456 $line = rtrim ($line, $literalBlockStyle . " \n");
457 $literalBlock = '';
458 $line .= ' '.$this->LiteralPlaceHolder;
459 $literal_block_indent = strlen($Source[$i+1]) - strlen(ltrim($Source[$i+1]));
460 while (++$i < $cnt && $this->literalBlockContinues($Source[$i], $this->indent)) {
461 $literalBlock = $this->addLiteralLine($literalBlock, $Source[$i], $literalBlockStyle, $literal_block_indent);
462 }
463 $i--;
464 }
465 // Strip out comments
466 if (strpos ($line, '#')) {
467 $line = preg_replace('/\s*#([^"\']+)$/','',$line);
468 }
469 while (++$i < $cnt && self::greedilyNeedNextLine($line)) {
470 $line = rtrim ($line, " \n\t\r") . ' ' . ltrim ($Source[$i], " \t");
471 }
472 $i--;
473 $lineArray = $this->_parseLine($line);
474 if ($literalBlockStyle)
475 $lineArray = $this->revertLiteralPlaceHolder ($lineArray, $literalBlock);
476 $this->addArray($lineArray, $this->indent);
477 foreach ($this->delayedPath as $indent => $delayedPath)
478 $this->path[$indent] = $delayedPath;
479 $this->delayedPath = array();
480 }
481 return $this->result;
482 }
483 private function loadFromSource ($input) {
484 if (!empty($input) && strpos($input, "\n") === false && file_exists($input))
485 $input = file_get_contents($input);
486 return $this->loadFromString($input);
487 }
488 private function loadFromString ($input) {
489 $lines = explode("\n",$input);
490 foreach ($lines as $k => $_) {
491 $lines[$k] = rtrim ($_, "\r");
492 }
493 return $lines;
494 }
495 /**
496 * Parses YAML code and returns an array for a node
497 * @access private
498 * @return array
499 * @param string $line A line from the YAML file
500 */
501 private function _parseLine($line) {
502 if (!$line) return array();
503 $line = trim($line);
504 if (!$line) return array();
505 $array = array();
506 $group = $this->nodeContainsGroup($line);
507 if ($group) {
508 $this->addGroup($line, $group);
509 $line = $this->stripGroup ($line, $group);
510 }
511 if ($this->startsMappedSequence($line))
512 return $this->returnMappedSequence($line);
513 if ($this->startsMappedValue($line))
514 return $this->returnMappedValue($line);
515 if ($this->isArrayElement($line))
516 return $this->returnArrayElement($line);
517 if ($this->isPlainArray($line))
518 return $this->returnPlainArray($line);
519 return $this->returnKeyValuePair($line);
520 }
521 /**
522 * Finds the type of the passed value, returns the value as the new type.
523 * @access private
524 * @param string $value
525 * @return mixed
526 */
527 private function _toType($value) {
528 if ($value === '') return "";
529 $first_character = $value[0];
530 $last_character = substr($value, -1, 1);
531 $is_quoted = false;
532 do {
533 if (!$value) break;
534 if ($first_character != '"' && $first_character != "'") break;
535 if ($last_character != '"' && $last_character != "'") break;
536 $is_quoted = true;
537 } while (0);
538 if ($is_quoted) {
539 $value = str_replace('\n', "\n", $value);
540 if ($first_character == "'")
541 return strtr(substr ($value, 1, -1), array ('\'\'' => '\'', '\\\''=> '\''));
542 return strtr(substr ($value, 1, -1), array ('\\"' => '"', '\\\''=> '\''));
543 }
544 if (strpos($value, ' #') !== false && !$is_quoted)
545 $value = preg_replace('/\s+#(.+)$/','',$value);
546 if ($first_character == '[' && $last_character == ']') {
547 // Take out strings sequences and mappings
548 $innerValue = trim(substr ($value, 1, -1));
549 if ($innerValue === '') return array();
550 $explode = $this->_inlineEscape($innerValue);
551 // Propagate value array
552 $value = array();
553 foreach ($explode as $v) {
554 $value[] = $this->_toType($v);
555 }
556 return $value;
557 }
558 if (strpos($value,': ')!==false && $first_character != '{') {
559 $array = explode(': ',$value);
560 $key = trim($array[0]);
561 array_shift($array);
562 $value = trim(implode(': ',$array));
563 $value = $this->_toType($value);
564 return array($key => $value);
565 }
566 if ($first_character == '{' && $last_character == '}') {
567 $innerValue = trim(substr ($value, 1, -1));
568 if ($innerValue === '') return array();
569 // Inline Mapping
570 // Take out strings sequences and mappings
571 $explode = $this->_inlineEscape($innerValue);
572 // Propagate value array
573 $array = array();
574 foreach ($explode as $v) {
575 $SubArr = $this->_toType($v);
576 if (empty($SubArr)) continue;
577 if (is_array ($SubArr)) {
578 $array[key($SubArr)] = $SubArr[key($SubArr)]; continue;
579 }
580 $array[] = $SubArr;
581 }
582 return $array;
583 }
584 if ($value == 'null' || $value == 'NULL' || $value == 'Null' || $value == '' || $value == '~') {
585 return null;
586 }
587 if ( is_numeric($value) && preg_match ('/^(-|)[1-9]+[0-9]*$/', $value) ){
588 $intvalue = (int)$value;
589 if ($intvalue != PHP_INT_MAX && $intvalue != ~PHP_INT_MAX)
590 $value = $intvalue;
591 return $value;
592 }
593 if ( is_string($value) && preg_match('/^0[xX][0-9a-fA-F]+$/', $value)) {
594 // Hexadecimal value.
595 return hexdec($value);
596 }
597 $this->coerceValue($value);
598 if (is_numeric($value)) {
599 if ($value === '0') return 0;
600 if (rtrim ($value, 0) === $value)
601 $value = (float)$value;
602 return $value;
603 }
604 return $value;
605 }
606 /**
607 * Used in inlines to check for more inlines or quoted strings
608 * @access private
609 * @return array
610 */
611 private function _inlineEscape($inline) {
612 // There's gotta be a cleaner way to do this...
613 // While pure sequences seem to be nesting just fine,
614 // pure mappings and mappings with sequences inside can't go very
615 // deep. This needs to be fixed.
616 $seqs = array();
617 $maps = array();
618 $saved_strings = array();
619 $saved_empties = array();
620 // Check for empty strings
621 $regex = '/("")|(\'\')/';
622 if (preg_match_all($regex,$inline,$strings)) {
623 $saved_empties = $strings[0];
624 $inline = preg_replace($regex,'YAMLEmpty',$inline);
625 }
626 unset($regex);
627 // Check for strings
628 $regex = '/(?:(")|(?:\'))((?(1)[^"]+|[^\']+))(?(1)"|\')/';
629 if (preg_match_all($regex,$inline,$strings)) {
630 $saved_strings = $strings[0];
631 $inline = preg_replace($regex,'YAMLString',$inline);
632 }
633 unset($regex);
634 // echo $inline;
635 $i = 0;
636 do {
637 // Check for sequences
638 while (preg_match('/\[([^{}\[\]]+)\]/U',$inline,$matchseqs)) {
639 $seqs[] = $matchseqs[0];
640 $inline = preg_replace('/\[([^{}\[\]]+)\]/U', ('YAMLSeq' . (count($seqs) - 1) . 's'), $inline, 1);
641 }
642 // Check for mappings
643 while (preg_match('/{([^\[\]{}]+)}/U',$inline,$matchmaps)) {
644 $maps[] = $matchmaps[0];
645 $inline = preg_replace('/{([^\[\]{}]+)}/U', ('YAMLMap' . (count($maps) - 1) . 's'), $inline, 1);
646 }
647 if ($i++ >= 10) break;
648 } while (strpos ($inline, '[') !== false || strpos ($inline, '{') !== false);
649 $explode = explode(',',$inline);
650 $explode = array_map('trim', $explode);
651 $stringi = 0; $i = 0;
652 while (1) {
653 // Re-add the sequences
654 if (!empty($seqs)) {
655 foreach ($explode as $key => $value) {
656 if (strpos($value,'YAMLSeq') !== false) {
657 foreach ($seqs as $seqk => $seq) {
658 $explode[$key] = str_replace(('YAMLSeq'.$seqk.'s'),$seq,$value);
659 $value = $explode[$key];
660 }
661 }
662 }
663 }
664 // Re-add the mappings
665 if (!empty($maps)) {
666 foreach ($explode as $key => $value) {
667 if (strpos($value,'YAMLMap') !== false) {
668 foreach ($maps as $mapk => $map) {
669 $explode[$key] = str_replace(('YAMLMap'.$mapk.'s'), $map, $value);
670 $value = $explode[$key];
671 }
672 }
673 }
674 }
675 // Re-add the strings
676 if (!empty($saved_strings)) {
677 foreach ($explode as $key => $value) {
678 while (strpos($value,'YAMLString') !== false) {
679 $explode[$key] = preg_replace('/YAMLString/',$saved_strings[$stringi],$value, 1);
680 unset($saved_strings[$stringi]);
681 ++$stringi;
682 $value = $explode[$key];
683 }
684 }
685 }
686 // Re-add the empties
687 if (!empty($saved_empties)) {
688 foreach ($explode as $key => $value) {
689 while (strpos($value,'YAMLEmpty') !== false) {
690 $explode[$key] = preg_replace('/YAMLEmpty/', '', $value, 1);
691 $value = $explode[$key];
692 }
693 }
694 }
695 $finished = true;
696 foreach ($explode as $key => $value) {
697 if (strpos($value,'YAMLSeq') !== false) {
698 $finished = false; break;
699 }
700 if (strpos($value,'YAMLMap') !== false) {
701 $finished = false; break;
702 }
703 if (strpos($value,'YAMLString') !== false) {
704 $finished = false; break;
705 }
706 if (strpos($value,'YAMLEmpty') !== false) {
707 $finished = false; break;
708 }
709 }
710 if ($finished) break;
711 $i++;
712 if ($i > 10)
713 break; // Prevent infinite loops.
714 }
715 return $explode;
716 }
717 private function literalBlockContinues ($line, $lineIndent) {
718 if (!trim($line)) return true;
719 if (strlen($line) - strlen(ltrim($line)) > $lineIndent) return true;
720 return false;
721 }
722 private function referenceContentsByAlias ($alias) {
723 do {
724 if (!isset($this->SavedGroups[$alias])) { echo "Bad group name: $alias."; break; }
725 $groupPath = $this->SavedGroups[$alias];
726 $value = $this->result;
727 foreach ($groupPath as $k) {
728 $value = $value[$k];
729 }
730 } while (false);
731 return $value;
732 }
733 private function addArrayInline ($array, $indent) {
734 $CommonGroupPath = $this->path;
735 if (empty ($array)) return false;
736 foreach ($array as $k => $_) {
737 $this->addArray(array($k => $_), $indent);
738 $this->path = $CommonGroupPath;
739 }
740 return true;
741 }
742 private function addArray ($incoming_data, $incoming_indent) {
743 // print_r ($incoming_data);
744 if (count ($incoming_data) > 1)
745 return $this->addArrayInline ($incoming_data, $incoming_indent);
746 $key = key ($incoming_data);
747 $value = isset($incoming_data[$key]) ? $incoming_data[$key] : null;
748 if ($key === '__!YAMLZero') $key = '0';
749 if ($incoming_indent == 0 && !$this->_containsGroupAlias && !$this->_containsGroupAnchor) { // Shortcut for root-level values.
750 if ($key || $key === '' || $key === '0') {
751 $this->result[$key] = $value;
752 } else {
753 $this->result[] = $value; end ($this->result); $key = key ($this->result);
754 }
755 $this->path[$incoming_indent] = $key;
756 return;
757 }
758 $history = array();
759 // Unfolding inner array tree.
760 $history[] = $_arr = $this->result;
761 foreach ($this->path as $k) {
762 $history[] = $_arr = $_arr[$k];
763 }
764 if ($this->_containsGroupAlias) {
765 $value = $this->referenceContentsByAlias($this->_containsGroupAlias);
766 $this->_containsGroupAlias = false;
767 }
768 // Adding string or numeric key to the innermost level or $this->arr.
769 if (is_string($key) && $key == '<<') {
770 if (!is_array ($_arr)) { $_arr = array (); }
771 $_arr = array_merge ($_arr, $value);
772 } else if ($key || $key === '' || $key === '0') {
773 if (!is_array ($_arr))
774 $_arr = array ($key=>$value);
775 else
776 $_arr[$key] = $value;
777 } else {
778 if (!is_array ($_arr)) { $_arr = array ($value); $key = 0; }
779 else { $_arr[] = $value; end ($_arr); $key = key ($_arr); }
780 }
781 $reverse_path = array_reverse($this->path);
782 $reverse_history = array_reverse ($history);
783 $reverse_history[0] = $_arr;
784 $cnt = count($reverse_history) - 1;
785 for ($i = 0; $i < $cnt; $i++) {
786 $reverse_history[$i+1][$reverse_path[$i]] = $reverse_history[$i];
787 }
788 $this->result = $reverse_history[$cnt];
789 $this->path[$incoming_indent] = $key;
790 if ($this->_containsGroupAnchor) {
791 $this->SavedGroups[$this->_containsGroupAnchor] = $this->path;
792 if (is_array ($value)) {
793 $k = key ($value);
794 if (!is_int ($k)) {
795 $this->SavedGroups[$this->_containsGroupAnchor][$incoming_indent + 2] = $k;
796 }
797 }
798 $this->_containsGroupAnchor = false;
799 }
800 }
801 private static function startsLiteralBlock ($line) {
802 $lastChar = substr (trim($line), -1);
803 if ($lastChar != '>' && $lastChar != '|') return false;
804 if ($lastChar == '|') return $lastChar;
805 // HTML tags should not be counted as literal blocks.
806 if (preg_match ('#<.*?>$#', $line)) return false;
807 return $lastChar;
808 }
809 private static function greedilyNeedNextLine($line) {
810 $line = trim ($line);
811 if (!strlen($line)) return false;
812 if (substr ($line, -1, 1) == ']') return false;
813 if ($line[0] == '[') return true;
814 if (preg_match ('#^[^:]+?:\s*\[#', $line)) return true;
815 return false;
816 }
817 private function addLiteralLine ($literalBlock, $line, $literalBlockStyle, $indent = -1) {
818 $line = self::stripIndent($line, $indent);
819 if ($literalBlockStyle !== '|') {
820 $line = self::stripIndent($line);
821 }
822 $line = rtrim ($line, "\r\n\t ") . "\n";
823 if ($literalBlockStyle == '|') {
824 return $literalBlock . $line;
825 }
826 if (strlen($line) == 0)
827 return rtrim($literalBlock, ' ') . "\n";
828 if ($line == "\n" && $literalBlockStyle == '>') {
829 return rtrim ($literalBlock, " \t") . "\n";
830 }
831 if ($line != "\n")
832 $line = trim ($line, "\r\n ") . " ";
833 return $literalBlock . $line;
834 }
835 function revertLiteralPlaceHolder ($lineArray, $literalBlock) {
836 foreach ($lineArray as $k => $_) {
837 if (is_array($_))
838 $lineArray[$k] = $this->revertLiteralPlaceHolder ($_, $literalBlock);
839 else if (substr($_, -1 * strlen ($this->LiteralPlaceHolder)) == $this->LiteralPlaceHolder)
840 $lineArray[$k] = rtrim ($literalBlock, " \r\n");
841 }
842 return $lineArray;
843 }
844 private static function stripIndent ($line, $indent = -1) {
845 if ($indent == -1) $indent = strlen($line) - strlen(ltrim($line));
846 return substr ($line, $indent);
847 }
848 private function getParentPathByIndent ($indent) {
849 if ($indent == 0) return array();
850 $linePath = $this->path;
851 do {
852 end($linePath); $lastIndentInParentPath = key($linePath);
853 if ($indent <= $lastIndentInParentPath) array_pop ($linePath);
854 } while ($indent <= $lastIndentInParentPath);
855 return $linePath;
856 }
857 private function clearBiggerPathValues ($indent) {
858 if ($indent == 0) $this->path = array();
859 if (empty ($this->path)) return true;
860 foreach ($this->path as $k => $_) {
861 if ($k > $indent) unset ($this->path[$k]);
862 }
863 return true;
864 }
865 private static function isComment ($line) {
866 if (!$line) return false;
867 if ($line[0] == '#') return true;
868 if (trim($line, " \r\n\t") == '---') return true;
869 return false;
870 }
871 private static function isEmpty ($line) {
872 return (trim ($line) === '');
873 }
874 private function isArrayElement ($line) {
875 if (!$line || !is_scalar($line)) return false;
876 if (substr($line, 0, 2) != '- ') return false;
877 if (strlen ($line) > 3)
878 if (substr($line,0,3) == '---') return false;
879 return true;
880 }
881 private function isHashElement ($line) {
882 return strpos($line, ':');
883 }
884 private function isLiteral ($line) {
885 if ($this->isArrayElement($line)) return false;
886 if ($this->isHashElement($line)) return false;
887 return true;
888 }
889 private static function unquote ($value) {
890 if (!$value) return $value;
891 if (!is_string($value)) return $value;
892 if ($value[0] == '\'') return trim ($value, '\'');
893 if ($value[0] == '"') return trim ($value, '"');
894 return $value;
895 }
896 private function startsMappedSequence ($line) {
897 return (substr($line, 0, 2) == '- ' && substr ($line, -1, 1) == ':');
898 }
899 private function returnMappedSequence ($line) {
900 $array = array();
901 $key = self::unquote(trim(substr($line,1,-1)));
902 $array[$key] = array();
903 $this->delayedPath = array(strpos ($line, $key) + $this->indent => $key);
904 return array($array);
905 }
906 private function checkKeysInValue($value) {
907 if (strchr('[{"\'', $value[0]) === false) {
908 if (strchr($value, ': ') !== false) {
909 throw new Exception('Too many keys: '.$value);
910 }
911 }
912 }
913 private function returnMappedValue ($line) {
914 $this->checkKeysInValue($line);
915 $array = array();
916 $key = self::unquote (trim(substr($line,0,-1)));
917 $array[$key] = '';
918 return $array;
919 }
920 private function startsMappedValue ($line) {
921 return (substr ($line, -1, 1) == ':');
922 }
923 private function isPlainArray ($line) {
924 return ($line[0] == '[' && substr ($line, -1, 1) == ']');
925 }
926 private function returnPlainArray ($line) {
927 return $this->_toType($line);
928 }
929 private function returnKeyValuePair ($line) {
930 $array = array();
931 $key = '';
932 if (strpos ($line, ': ')) {
933 // It's a key/value pair most likely
934 // If the key is in double quotes pull it out
935 if (($line[0] == '"' || $line[0] == "'") && preg_match('/^(["\'](.*)["\'](\s)*:)/',$line,$matches)) {
936 $value = trim(str_replace($matches[1],'',$line));
937 $key = $matches[2];
938 } else {
939 // Do some guesswork as to the key and the value
940 $explode = explode(': ', $line);
941 $key = trim(array_shift($explode));
942 $value = trim(implode(': ', $explode));
943 $this->checkKeysInValue($value);
944 }
945 // Set the type of the value. Int, string, etc
946 $value = $this->_toType($value);
947 if ($key === '0') $key = '__!YAMLZero';
948 $array[$key] = $value;
949 } else {
950 $array = array ($line);
951 }
952 return $array;
953 }
954 private function returnArrayElement ($line) {
955 if (strlen($line) <= 1) return array(array()); // Weird %)
956 $array = array();
957 $value = trim(substr($line,1));
958 $value = $this->_toType($value);
959 if ($this->isArrayElement($value)) {
960 $value = $this->returnArrayElement($value);
961 }
962 $array[] = $value;
963 return $array;
964 }
965 private function nodeContainsGroup ($line) {
966 $symbolsForReference = 'A-z0-9_\-';
967 if (strpos($line, '&') === false && strpos($line, '*') === false) return false; // Please die fast ;-)
968 if ($line[0] == '&' && preg_match('/^(&['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1];
969 if ($line[0] == '*' && preg_match('/^(\*['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1];
970 if (preg_match('/(&['.$symbolsForReference.']+)$/', $line, $matches)) return $matches[1];
971 if (preg_match('/(\*['.$symbolsForReference.']+$)/', $line, $matches)) return $matches[1];
972 if (preg_match ('#^\s*<<\s*:\s*(\*[^\s]+).*$#', $line, $matches)) return $matches[1];
973 return false;
974 }
975 private function addGroup ($line, $group) {
976 if ($group[0] == '&') $this->_containsGroupAnchor = substr ($group, 1);
977 if ($group[0] == '*') $this->_containsGroupAlias = substr ($group, 1);
978 //print_r ($this->path);
979 }
980 private function stripGroup ($line, $group) {
981 $line = trim(str_replace($group, '', $line));
982 return $line;
983 }
984 }
985 }
986 // Enable use of Spyc from command line
987 // The syntax is the following: php Spyc.php spyc.yaml
988 do {
989 if (PHP_SAPI != 'cli') break;
990 if (empty ($_SERVER['argc']) || $_SERVER['argc'] < 2) break;
991 if (empty ($_SERVER['PHP_SELF']) || FALSE === strpos ($_SERVER['PHP_SELF'], 'Spyc.php') ) break;
992 $file = $argv[1];
993 echo json_encode (spyc_load_file ($file));
994 } while (0);