1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
21:
22: App::uses('Router', 'Routing');
23:
24: 25: 26: 27: 28: 29:
30: class Helper extends Object {
31:
32: 33: 34: 35: 36:
37: public $helpers = array();
38:
39: 40: 41: 42: 43:
44: protected $_helperMap = array();
45:
46: 47: 48: 49: 50:
51: public $theme = null;
52:
53: 54: 55: 56: 57:
58: public $request = null;
59:
60: 61: 62: 63: 64:
65: public $plugin = null;
66:
67: 68: 69: 70: 71: 72:
73: public $fieldset = array();
74:
75: 76: 77: 78: 79:
80: public $tags = array();
81:
82: 83: 84: 85: 86:
87: protected $_tainted = null;
88:
89: 90: 91: 92: 93:
94: protected $_cleaned = null;
95:
96: 97: 98: 99: 100:
101: protected $_View;
102:
103: 104: 105: 106: 107: 108: 109:
110: protected $_fieldSuffixes = array(
111: 'year', 'month', 'day', 'hour', 'min', 'second', 'meridian'
112: );
113:
114: 115: 116: 117: 118: 119:
120: protected $_modelScope;
121:
122: 123: 124: 125: 126: 127:
128: protected $_association;
129:
130: 131: 132: 133: 134: 135:
136: protected $_entityPath;
137:
138: 139: 140: 141: 142: 143:
144: public function __construct(View $View, $settings = array()) {
145: $this->_View = $View;
146: $this->request = $View->request;
147: if (!empty($this->helpers)) {
148: $this->_helperMap = ObjectCollection::normalizeObjectArray($this->helpers);
149: }
150: }
151:
152: 153: 154: 155: 156: 157: 158:
159: public function __call($method, $params) {
160: trigger_error(__d('cake_dev', 'Method %1$s::%2$s does not exist', get_class($this), $method), E_USER_WARNING);
161: }
162:
163: 164: 165: 166: 167: 168:
169: public function __get($name) {
170: if (isset($this->_helperMap[$name]) && !isset($this->{$name})) {
171: $settings = array_merge((array)$this->_helperMap[$name]['settings'], array('enabled' => false));
172: $this->{$name} = $this->_View->loadHelper($this->_helperMap[$name]['class'], $settings);
173: }
174: if (isset($this->{$name})) {
175: return $this->{$name};
176: }
177: switch ($name) {
178: case 'base':
179: case 'here':
180: case 'webroot':
181: case 'data':
182: return $this->request->{$name};
183: case 'action':
184: return isset($this->request->params['action']) ? $this->request->params['action'] : '';
185: case 'params':
186: return $this->request;
187: }
188: }
189:
190: 191: 192: 193: 194: 195: 196:
197: public function __set($name, $value) {
198: switch ($name) {
199: case 'base':
200: case 'here':
201: case 'webroot':
202: case 'data':
203: return $this->request->{$name} = $value;
204: case 'action':
205: return $this->request->params['action'] = $value;
206: }
207: return $this->{$name} = $value;
208: }
209:
210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221:
222: public function url($url = null, $full = false) {
223: return h(Router::url($url, $full));
224: }
225:
226: 227: 228: 229: 230: 231:
232: public function webroot($file) {
233: $asset = explode('?', $file);
234: $asset[1] = isset($asset[1]) ? '?' . $asset[1] : null;
235: $webPath = "{$this->request->webroot}" . $asset[0];
236: $file = $asset[0];
237:
238: if (!empty($this->theme)) {
239: $file = trim($file, '/');
240: $theme = $this->theme . '/';
241:
242: if (DS === '\\') {
243: $file = str_replace('/', '\\', $file);
244: }
245:
246: if (file_exists(Configure::read('App.www_root') . 'theme' . DS . $this->theme . DS . $file)) {
247: $webPath = "{$this->request->webroot}theme/" . $theme . $asset[0];
248: } else {
249: $themePath = App::themePath($this->theme);
250: $path = $themePath . 'webroot' . DS . $file;
251: if (file_exists($path)) {
252: $webPath = "{$this->request->webroot}theme/" . $theme . $asset[0];
253: }
254: }
255: }
256: if (strpos($webPath, '//') !== false) {
257: return str_replace('//', '/', $webPath . $asset[1]);
258: }
259: return $webPath . $asset[1];
260: }
261:
262: 263: 264: 265: 266: 267: 268: 269:
270: public function assetTimestamp($path) {
271: $stamp = Configure::read('Asset.timestamp');
272: $timestampEnabled = $stamp === 'force' || ($stamp === true && Configure::read('debug') > 0);
273: if ($timestampEnabled && strpos($path, '?') === false) {
274: $filepath = preg_replace('/^' . preg_quote($this->request->webroot, '/') . '/', '', $path);
275: $webrootPath = WWW_ROOT . str_replace('/', DS, $filepath);
276: if (file_exists($webrootPath)) {
277: return $path . '?' . @filemtime($webrootPath);
278: }
279: $segments = explode('/', ltrim($filepath, '/'));
280: if ($segments[0] === 'theme') {
281: $theme = $segments[1];
282: unset($segments[0], $segments[1]);
283: $themePath = App::themePath($theme) . 'webroot' . DS . implode(DS, $segments);
284: return $path . '?' . @filemtime($themePath);
285: } else {
286: $plugin = Inflector::camelize($segments[0]);
287: if (CakePlugin::loaded($plugin)) {
288: unset($segments[0]);
289: $pluginPath = CakePlugin::path($plugin) . 'webroot' . DS . implode(DS, $segments);
290: return $path . '?' . @filemtime($pluginPath);
291: }
292: }
293: }
294: return $path;
295: }
296:
297: 298: 299: 300: 301: 302: 303: 304:
305: public function clean($output) {
306: $this->_reset();
307: if (empty($output)) {
308: return null;
309: }
310: if (is_array($output)) {
311: foreach ($output as $key => $value) {
312: $return[$key] = $this->clean($value);
313: }
314: return $return;
315: }
316: $this->_tainted = $output;
317: $this->_clean();
318: return $this->_cleaned;
319: }
320:
321: 322: 323: 324: 325: 326: 327: 328: 329: 330: 331: 332: 333: 334: 335: 336: 337: 338: 339: 340: 341: 342: 343: 344: 345: 346: 347: 348: 349: 350: 351: 352: 353: 354: 355: 356: 357: 358: 359: 360:
361: protected function _parseAttributes($options, $exclude = null, $insertBefore = ' ', $insertAfter = null) {
362: if (!is_string($options)) {
363: $options = (array) $options + array('escape' => true);
364:
365: if (!is_array($exclude)) {
366: $exclude = array();
367: }
368:
369: $exclude = array('escape' => true) + array_flip($exclude);
370: $escape = $options['escape'];
371: $attributes = array();
372:
373: foreach ($options as $key => $value) {
374: if (!isset($exclude[$key]) && $value !== false && $value !== null) {
375: $attributes[] = $this->_formatAttribute($key, $value, $escape);
376: }
377: }
378: $out = implode(' ', $attributes);
379: } else {
380: $out = $options;
381: }
382: return $out ? $insertBefore . $out . $insertAfter : '';
383: }
384:
385: 386: 387: 388: 389: 390: 391: 392: 393: 394:
395: protected function _formatAttribute($key, $value, $escape = true) {
396: $attribute = '';
397: if (is_array($value)) {
398: $value = implode(' ' , $value);
399: }
400:
401: if (is_numeric($key)) {
402: $attribute = sprintf($this->_minimizedAttributeFormat, $value, $value);
403: } elseif (in_array($key, $this->_minimizedAttributes)) {
404: if ($value === 1 || $value === true || $value === 'true' || $value === '1' || $value == $key) {
405: $attribute = sprintf($this->_minimizedAttributeFormat, $key, $key);
406: }
407: } else {
408: $attribute = sprintf($this->_attributeFormat, $key, ($escape ? h($value) : $value));
409: }
410: return $attribute;
411: }
412:
413: 414: 415: 416: 417: 418: 419:
420: public function setEntity($entity, $setScope = false) {
421: if ($entity === null) {
422: $this->_modelScope = false;
423: }
424: if ($setScope === true) {
425: $this->_modelScope = $entity;
426: }
427: $parts = array_values(Set::filter(explode('.', $entity), true));
428: if (empty($parts)) {
429: return;
430: }
431: $count = count($parts);
432: $lastPart = isset($parts[$count - 1]) ? $parts[$count - 1] : null;
433:
434:
435: if (
436: ($count === 1 && $this->_modelScope && $setScope == false) ||
437: (
438: $count === 2 &&
439: in_array($lastPart, $this->_fieldSuffixes) &&
440: $this->_modelScope &&
441: $parts[0] !== $this->_modelScope
442: )
443: ) {
444: $entity = $this->_modelScope . '.' . $entity;
445: }
446:
447:
448: if (
449: $count >= 2 &&
450: is_numeric($parts[0]) &&
451: !is_numeric($parts[1]) &&
452: $this->_modelScope &&
453: strpos($entity, $this->_modelScope) === false
454: ) {
455: $entity = $this->_modelScope . '.' . $entity;
456: }
457:
458: $this->_association = null;
459:
460: $isHabtm = (
461: isset($this->fieldset[$this->_modelScope]['fields'][$parts[0]]['type']) &&
462: $this->fieldset[$this->_modelScope]['fields'][$parts[0]]['type'] === 'multiple' &&
463: $count == 1
464: );
465:
466:
467: if ($count == 1 && $isHabtm) {
468: $this->_association = $parts[0];
469: $entity = $parts[0] . '.' . $parts[0];
470: } else {
471:
472: $reversed = array_reverse($parts);
473: foreach ($reversed as $i => $part) {
474: if ($i > 0 && preg_match('/^[A-Z]/', $part)) {
475: $this->_association = $part;
476: break;
477: }
478: }
479: }
480: $this->_entityPath = $entity;
481: return;
482: }
483:
484: 485: 486: 487: 488:
489: public function entity() {
490: return explode('.', $this->_entityPath);
491: }
492:
493: 494: 495: 496: 497:
498: public function model() {
499: if ($this->_association) {
500: return $this->_association;
501: }
502: return $this->_modelScope;
503: }
504:
505: 506: 507: 508: 509: 510: 511:
512: public function field() {
513: $entity = $this->entity();
514: $count = count($entity);
515: $last = $entity[$count - 1];
516: if ($count > 2 && in_array($last, $this->_fieldSuffixes)) {
517: $last = isset($entity[$count - 2]) ? $entity[$count - 2] : null;
518: }
519: return $last;
520: }
521:
522: 523: 524: 525: 526: 527: 528: 529: 530: 531: 532:
533: public function domId($options = null, $id = 'id') {
534: if (is_array($options) && array_key_exists($id, $options) && $options[$id] === null) {
535: unset($options[$id]);
536: return $options;
537: } elseif (!is_array($options) && $options !== null) {
538: $this->setEntity($options);
539: return $this->domId();
540: }
541:
542: $entity = $this->entity();
543: $model = array_shift($entity);
544: $dom = $model . join('', array_map(array('Inflector', 'camelize'), $entity));
545:
546: if (is_array($options) && !array_key_exists($id, $options)) {
547: $options[$id] = $dom;
548: } elseif ($options === null) {
549: return $dom;
550: }
551: return $options;
552: }
553:
554: 555: 556: 557: 558: 559: 560: 561: 562: 563: 564: 565:
566: protected function _name($options = array(), $field = null, $key = 'name') {
567: if ($options === null) {
568: $options = array();
569: } elseif (is_string($options)) {
570: $field = $options;
571: $options = 0;
572: }
573:
574: if (!empty($field)) {
575: $this->setEntity($field);
576: }
577:
578: if (is_array($options) && array_key_exists($key, $options)) {
579: return $options;
580: }
581:
582: switch ($field) {
583: case '_method':
584: $name = $field;
585: break;
586: default:
587: $name = 'data[' . implode('][', $this->entity()) . ']';
588: break;
589: }
590:
591: if (is_array($options)) {
592: $options[$key] = $name;
593: return $options;
594: } else {
595: return $name;
596: }
597: }
598:
599: 600: 601: 602: 603: 604: 605: 606: 607: 608: 609:
610: public function value($options = array(), $field = null, $key = 'value') {
611: if ($options === null) {
612: $options = array();
613: } elseif (is_string($options)) {
614: $field = $options;
615: $options = 0;
616: }
617:
618: if (is_array($options) && isset($options[$key])) {
619: return $options;
620: }
621:
622: if (!empty($field)) {
623: $this->setEntity($field);
624: }
625: $result = null;
626: $data = $this->request->data;
627:
628: $entity = $this->entity();
629: if (!empty($data) && !empty($entity)) {
630: $result = Set::extract(implode('.', $entity), $data);
631: }
632:
633: $habtmKey = $this->field();
634: if (empty($result) && isset($data[$habtmKey][$habtmKey]) && is_array($data[$habtmKey])) {
635: $result = $data[$habtmKey][$habtmKey];
636: } elseif (empty($result) && isset($data[$habtmKey]) && is_array($data[$habtmKey])) {
637: if (ClassRegistry::isKeySet($habtmKey)) {
638: $model = ClassRegistry::getObject($habtmKey);
639: $result = $this->_selectedArray($data[$habtmKey], $model->primaryKey);
640: }
641: }
642:
643: if (is_array($options)) {
644: if ($result === null && isset($options['default'])) {
645: $result = $options['default'];
646: }
647: unset($options['default']);
648: }
649:
650: if (is_array($options)) {
651: $options[$key] = $result;
652: return $options;
653: } else {
654: return $result;
655: }
656: }
657:
658: 659: 660: 661: 662: 663: 664: 665: 666:
667: protected function _initInputField($field, $options = array()) {
668: if ($field !== null) {
669: $this->setEntity($field);
670: }
671: $options = (array)$options;
672: $options = $this->_name($options);
673: $options = $this->value($options);
674: $options = $this->domId($options);
675: return $options;
676: }
677:
678: 679: 680: 681: 682: 683: 684: 685:
686: public function addClass($options = array(), $class = null, $key = 'class') {
687: if (isset($options[$key]) && trim($options[$key]) != '') {
688: $options[$key] .= ' ' . $class;
689: } else {
690: $options[$key] = $class;
691: }
692: return $options;
693: }
694:
695: 696: 697: 698: 699: 700: 701: 702: 703:
704: public function output($str) {
705: return $str;
706: }
707:
708: 709: 710: 711: 712: 713: 714: 715:
716: public function beforeRender($viewFile) {
717: }
718:
719: 720: 721: 722: 723: 724: 725: 726: 727:
728: public function afterRender($viewFile) {
729: }
730:
731: 732: 733: 734: 735: 736: 737: 738:
739: public function beforeLayout($layoutFile) {
740: }
741:
742: 743: 744: 745: 746: 747: 748: 749:
750: public function afterLayout($layoutFile) {
751: }
752:
753: 754: 755: 756: 757: 758: 759: 760:
761: protected function _selectedArray($data, $key = 'id') {
762: if (!is_array($data)) {
763: $model = $data;
764: if (!empty($this->request->data[$model][$model])) {
765: return $this->request->data[$model][$model];
766: }
767: if (!empty($this->request->data[$model])) {
768: $data = $this->request->data[$model];
769: }
770: }
771: $array = array();
772: if (!empty($data)) {
773: foreach ($data as $row) {
774: if (isset($row[$key])) {
775: $array[$row[$key]] = $row[$key];
776: }
777: }
778: }
779: return empty($array) ? null : $array;
780: }
781:
782: 783: 784: 785: 786:
787: protected function _reset() {
788: $this->_tainted = null;
789: $this->_cleaned = null;
790: }
791:
792: 793: 794: 795: 796:
797: protected function _clean() {
798: if (get_magic_quotes_gpc()) {
799: $this->_cleaned = stripslashes($this->_tainted);
800: } else {
801: $this->_cleaned = $this->_tainted;
802: }
803:
804: $this->_cleaned = str_replace(array("&", "<", ">"), array("&amp;", "&lt;", "&gt;"), $this->_cleaned);
805: $this->_cleaned = preg_replace('#(&\#*\w+)[\x00-\x20]+;#u', "$1;", $this->_cleaned);
806: $this->_cleaned = preg_replace('#(&\#x*)([0-9A-F]+);*#iu', "$1$2;", $this->_cleaned);
807: $this->_cleaned = html_entity_decode($this->_cleaned, ENT_COMPAT, "UTF-8");
808: $this->_cleaned = preg_replace('#(<[^>]+[\x00-\x20\"\'\/])(on|xmlns)[^>]*>#iUu', "$1>", $this->_cleaned);
809: $this->_cleaned = preg_replace('#([a-z]*)[\x00-\x20]*=[\x00-\x20]*([\`\'\"]*)[\\x00-\x20]*j[\x00-\x20]*a[\x00-\x20]*v[\x00-\x20]*a[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iUu', '$1=$2nojavascript...', $this->_cleaned);
810: $this->_cleaned = preg_replace('#([a-z]*)[\x00-\x20]*=([\'\"]*)[\x00-\x20]*v[\x00-\x20]*b[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iUu', '$1=$2novbscript...', $this->_cleaned);
811: $this->_cleaned = preg_replace('#([a-z]*)[\x00-\x20]*=*([\'\"]*)[\x00-\x20]*-moz-binding[\x00-\x20]*:#iUu', '$1=$2nomozbinding...', $this->_cleaned);
812: $this->_cleaned = preg_replace('#([a-z]*)[\x00-\x20]*=([\'\"]*)[\x00-\x20]*data[\x00-\x20]*:#Uu', '$1=$2nodata...', $this->_cleaned);
813: $this->_cleaned = preg_replace('#(<[^>]+)style[\x00-\x20]*=[\x00-\x20]*([\`\'\"]*).*expression[\x00-\x20]*\([^>]*>#iU', "$1>", $this->_cleaned);
814: $this->_cleaned = preg_replace('#(<[^>]+)style[\x00-\x20]*=[\x00-\x20]*([\`\'\"]*).*behaviour[\x00-\x20]*\([^>]*>#iU', "$1>", $this->_cleaned);
815: $this->_cleaned = preg_replace('#(<[^>]+)style[\x00-\x20]*=[\x00-\x20]*([\`\'\"]*).*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:*[^>]*>#iUu', "$1>", $this->_cleaned);
816: $this->_cleaned = preg_replace('#</*\w+:\w[^>]*>#i', "", $this->_cleaned);
817: do {
818: $oldstring = $this->_cleaned;
819: $this->_cleaned = preg_replace('#</*(applet|meta|xml|blink|link|style|script|embed|object|iframe|frame|frameset|ilayer|layer|bgsound|title|base)[^>]*>#i', "", $this->_cleaned);
820: } while ($oldstring != $this->_cleaned);
821: $this->_cleaned = str_replace(array("&", "<", ">"), array("&amp;", "&lt;", "&gt;"), $this->_cleaned);
822: }
823: }
824: