1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25:
26:
27: 28: 29: 30: 31:
32: class Mage_Core_Helper_Data extends Mage_Core_Helper_Abstract
33: {
34: const XML_PATH_DEFAULT_COUNTRY = 'general/country/default';
35: const XML_PATH_PROTECTED_FILE_EXTENSIONS = 'general/file/protected_extensions';
36: const XML_PATH_PUBLIC_FILES_VALID_PATHS = 'general/file/public_files_valid_paths';
37: const XML_PATH_ENCRYPTION_MODEL = 'global/helpers/core/encryption_model';
38: const XML_PATH_DEV_ALLOW_IPS = 'dev/restrict/allow_ips';
39: const XML_PATH_CACHE_BETA_TYPES = 'global/cache/betatypes';
40: const XML_PATH_CONNECTION_TYPE = 'global/resources/default_setup/connection/type';
41:
42: const CHARS_LOWERS = 'abcdefghijklmnopqrstuvwxyz';
43: const CHARS_UPPERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
44: const CHARS_DIGITS = '0123456789';
45: const CHARS_SPECIALS = '!$*+-.=?@^_|~';
46: const CHARS_PASSWORD_LOWERS = 'abcdefghjkmnpqrstuvwxyz';
47: const CHARS_PASSWORD_UPPERS = 'ABCDEFGHJKLMNPQRSTUVWXYZ';
48: const CHARS_PASSWORD_DIGITS = '23456789';
49: const CHARS_PASSWORD_SPECIALS = '!$*-.=?@_';
50:
51: 52: 53:
54: const XML_PATH_MERCHANT_COUNTRY_CODE = 'general/store_information/merchant_country';
55: const XML_PATH_MERCHANT_VAT_NUMBER = 'general/store_information/merchant_vat_number';
56: const XML_PATH_EU_COUNTRIES_LIST = 'general/country/eu_countries';
57:
58: 59: 60:
61: const DIVIDE_EPSILON = 10000;
62:
63: 64: 65:
66: protected $_encryptor = null;
67:
68: protected $_allowedFormats = array(
69: Mage_Core_Model_Locale::FORMAT_TYPE_FULL,
70: Mage_Core_Model_Locale::FORMAT_TYPE_LONG,
71: Mage_Core_Model_Locale::FORMAT_TYPE_MEDIUM,
72: Mage_Core_Model_Locale::FORMAT_TYPE_SHORT
73: );
74:
75:
76: 77: 78:
79: public function getEncryptor()
80: {
81: if ($this->_encryptor === null) {
82: $encryptionModel = (string)Mage::getConfig()->getNode(self::XML_PATH_ENCRYPTION_MODEL);
83: if ($encryptionModel) {
84: $this->_encryptor = new $encryptionModel;
85: } else {
86: $this->_encryptor = Mage::getModel('core/encryption');
87: }
88:
89: $this->_encryptor->setHelper($this);
90: }
91: return $this->_encryptor;
92: }
93:
94: 95: 96: 97: 98: 99: 100: 101:
102: public static function currency($value, $format = true, $includeContainer = true)
103: {
104: return self::currencyByStore($value, null, $format, $includeContainer);
105: }
106:
107: 108: 109: 110: 111: 112: 113: 114: 115:
116: public static function currencyByStore($value, $store = null, $format = true, $includeContainer = true)
117: {
118: try {
119: if (!($store instanceof Mage_Core_Model_Store)) {
120: $store = Mage::app()->getStore($store);
121: }
122:
123: $value = $store->convertPrice($value, $format, $includeContainer);
124: }
125: catch (Exception $e){
126: $value = $e->getMessage();
127: }
128:
129: return $value;
130: }
131:
132: 133: 134: 135: 136: 137: 138:
139: public function formatCurrency($value, $includeContainer = true)
140: {
141: return $this->currency($value, true, $includeContainer);
142: }
143:
144: 145: 146: 147: 148: 149: 150:
151: public function formatPrice($price, $includeContainer = true)
152: {
153: return Mage::app()->getStore()->formatPrice($price, $includeContainer);
154: }
155:
156: 157: 158: 159: 160: 161: 162: 163:
164: public function formatDate($date = null, $format = Mage_Core_Model_Locale::FORMAT_TYPE_SHORT, $showTime = false)
165: {
166: if (!in_array($format, $this->_allowedFormats, true)) {
167: return $date;
168: }
169: if (!($date instanceof Zend_Date) && $date && !strtotime($date)) {
170: return '';
171: }
172: if (is_null($date)) {
173: $date = Mage::app()->getLocale()->date(Mage::getSingleton('core/date')->gmtTimestamp(), null, null);
174: } else if (!$date instanceof Zend_Date) {
175: $date = Mage::app()->getLocale()->date(strtotime($date), null, null);
176: }
177:
178: if ($showTime) {
179: $format = Mage::app()->getLocale()->getDateTimeFormat($format);
180: } else {
181: $format = Mage::app()->getLocale()->getDateFormat($format);
182: }
183:
184: return $date->toString($format);
185: }
186:
187: 188: 189: 190: 191: 192: 193: 194:
195: public function formatTime($time = null, $format = Mage_Core_Model_Locale::FORMAT_TYPE_SHORT, $showDate = false)
196: {
197: if (!in_array($format, $this->_allowedFormats, true)) {
198: return $time;
199: }
200:
201: if (is_null($time)) {
202: $date = Mage::app()->getLocale()->date(time());
203: } else if ($time instanceof Zend_Date) {
204: $date = $time;
205: } else {
206: $date = Mage::app()->getLocale()->date(strtotime($time));
207: }
208:
209: if ($showDate) {
210: $format = Mage::app()->getLocale()->getDateTimeFormat($format);
211: } else {
212: $format = Mage::app()->getLocale()->getTimeFormat($format);
213: }
214:
215: return $date->toString($format);
216: }
217:
218: 219: 220: 221: 222: 223:
224: public function encrypt($data)
225: {
226: if (!Mage::isInstalled()) {
227: return $data;
228: }
229: return $this->getEncryptor()->encrypt($data);
230: }
231:
232: 233: 234: 235: 236: 237:
238: public function decrypt($data)
239: {
240: if (!Mage::isInstalled()) {
241: return $data;
242: }
243: return $this->getEncryptor()->decrypt($data);
244: }
245:
246: public function validateKey($key)
247: {
248: return $this->getEncryptor()->validateKey($key);
249: }
250:
251: public function getRandomString($len, $chars = null)
252: {
253: if (is_null($chars)) {
254: $chars = self::CHARS_LOWERS . self::CHARS_UPPERS . self::CHARS_DIGITS;
255: }
256: mt_srand(10000000*(double)microtime());
257: for ($i = 0, $str = '', $lc = strlen($chars)-1; $i < $len; $i++) {
258: $str .= $chars[mt_rand(0, $lc)];
259: }
260: return $str;
261: }
262:
263: 264: 265: 266: 267: 268:
269: public function getHash($password, $salt = false)
270: {
271: return $this->getEncryptor()->getHash($password, $salt);
272: }
273:
274: public function validateHash($password, $hash)
275: {
276: return $this->getEncryptor()->validateHash($password, $hash);
277: }
278:
279: 280: 281: 282: 283: 284:
285: public function getStoreId($store=null)
286: {
287: return Mage::app()->getStore($store)->getId();
288: }
289:
290: public function removeAccents($string, $german=false)
291: {
292: static $replacements;
293:
294: if (empty($replacements[$german])) {
295: $subst = array(
296:
297: 192=>'A', 193=>'A', 194=>'A', 195=>'A', 196=>'A', 197=>'A', 199=>'C',
298: 208=>'D', 200=>'E', 201=>'E', 202=>'E', 203=>'E', 204=>'I', 205=>'I',
299: 206=>'I', 207=>'I', 209=>'N', 210=>'O', 211=>'O', 212=>'O', 213=>'O',
300: 214=>'O', 216=>'O', 138=>'S', 217=>'U', 218=>'U', 219=>'U', 220=>'U',
301: 221=>'Y', 142=>'Z', 224=>'a', 225=>'a', 226=>'a', 227=>'a', 228=>'a',
302: 229=>'a', 231=>'c', 232=>'e', 233=>'e', 234=>'e', 235=>'e', 236=>'i',
303: 237=>'i', 238=>'i', 239=>'i', 241=>'n', 240=>'o', 242=>'o', 243=>'o',
304: 244=>'o', 245=>'o', 246=>'o', 248=>'o', 154=>'s', 249=>'u', 250=>'u',
305: 251=>'u', 252=>'u', 253=>'y', 255=>'y', 158=>'z',
306:
307: 258=>'A', 260=>'A', 262=>'C', 268=>'C', 270=>'D', 272=>'D', 280=>'E',
308: 282=>'E', 286=>'G', 304=>'I', 313=>'L', 317=>'L', 321=>'L', 323=>'N',
309: 327=>'N', 336=>'O', 340=>'R', 344=>'R', 346=>'S', 350=>'S', 354=>'T',
310: 356=>'T', 366=>'U', 368=>'U', 377=>'Z', 379=>'Z', 259=>'a', 261=>'a',
311: 263=>'c', 269=>'c', 271=>'d', 273=>'d', 281=>'e', 283=>'e', 287=>'g',
312: 305=>'i', 322=>'l', 314=>'l', 318=>'l', 324=>'n', 328=>'n', 337=>'o',
313: 341=>'r', 345=>'r', 347=>'s', 351=>'s', 357=>'t', 355=>'t', 367=>'u',
314: 369=>'u', 378=>'z', 380=>'z',
315:
316: 198=>'Ae', 230=>'ae', 140=>'Oe', 156=>'oe', 223=>'ss',
317: );
318:
319: if ($german) {
320:
321: $subst = array_merge($subst, array(
322: 196=>'Ae', 228=>'ae', 214=>'Oe', 246=>'oe', 220=>'Ue', 252=>'ue'
323: ));
324: }
325:
326: $replacements[$german] = array();
327: foreach ($subst as $k=>$v) {
328: $replacements[$german][$k<256 ? chr($k) : '&#'.$k.';'] = $v;
329: }
330: }
331:
332:
333:
334: if ($s = @iconv('UTF-8', 'ISO-8859-1', $string)) {
335: $string = $s;
336: }
337:
338:
339: $string = strtr($string, $replacements[$german]);
340:
341: return $string;
342: }
343:
344: public function isDevAllowed($storeId=null)
345: {
346: $allow = true;
347:
348: $allowedIps = Mage::getStoreConfig(self::XML_PATH_DEV_ALLOW_IPS, $storeId);
349: $remoteAddr = Mage::helper('core/http')->getRemoteAddr();
350: if (!empty($allowedIps) && !empty($remoteAddr)) {
351: $allowedIps = preg_split('#\s*,\s*#', $allowedIps, null, PREG_SPLIT_NO_EMPTY);
352: if (array_search($remoteAddr, $allowedIps) === false
353: && array_search(Mage::helper('core/http')->getHttpHost(), $allowedIps) === false) {
354: $allow = false;
355: }
356: }
357:
358: return $allow;
359: }
360:
361: 362: 363: 364: 365:
366: public function getCacheTypes()
367: {
368: $types = array();
369: $config = Mage::getConfig()->getNode(Mage_Core_Model_Cache::XML_PATH_TYPES);
370: foreach ($config->children() as $type=>$node) {
371: $types[$type] = (string)$node->label;
372: }
373: return $types;
374: }
375:
376: 377: 378: 379: 380:
381: public function getCacheBetaTypes()
382: {
383: $types = array();
384: $config = Mage::getConfig()->getNode(self::XML_PATH_CACHE_BETA_TYPES);
385: if ($config) {
386: foreach ($config->children() as $type=>$node) {
387: $types[$type] = (string)$node->label;
388: }
389: }
390: return $types;
391: }
392:
393: 394: 395: 396: 397: 398: 399: 400: 401: 402: 403: 404: 405: 406:
407: public function copyFieldset($fieldset, $aspect, $source, $target, $root='global')
408: {
409: if (!(is_array($source) || $source instanceof Varien_Object)
410: || !(is_array($target) || $target instanceof Varien_Object)) {
411:
412: return false;
413: }
414: $fields = Mage::getConfig()->getFieldset($fieldset, $root);
415: if (!$fields) {
416: return false;
417: }
418:
419: $sourceIsArray = is_array($source);
420: $targetIsArray = is_array($target);
421:
422: $result = false;
423: foreach ($fields as $code=>$node) {
424: if (empty($node->$aspect)) {
425: continue;
426: }
427:
428: if ($sourceIsArray) {
429: $value = isset($source[$code]) ? $source[$code] : null;
430: } else {
431: $value = $source->getDataUsingMethod($code);
432: }
433:
434: $targetCode = (string)$node->$aspect;
435: $targetCode = $targetCode == '*' ? $code : $targetCode;
436:
437: if ($targetIsArray) {
438: $target[$targetCode] = $value;
439: } else {
440: $target->setDataUsingMethod($targetCode, $value);
441: }
442:
443: $result = true;
444: }
445:
446: $eventName = sprintf('core_copy_fieldset_%s_%s', $fieldset, $aspect);
447: Mage::dispatchEvent($eventName, array(
448: 'target' => $target,
449: 'source' => $source,
450: 'root' => $root
451: ));
452:
453: return $result;
454: }
455:
456: 457: 458: 459: 460: 461: 462: 463: 464: 465: 466: 467: 468: 469: 470: 471: 472: 473: 474: 475:
476: public function decorateArray($array, $prefix = 'decorated_', $forceSetAll = false)
477: {
478:
479: if (!(is_array($array) || is_object($array))) {
480: return $array;
481: }
482:
483: $keyIsFirst = "{$prefix}is_first";
484: $keyIsOdd = "{$prefix}is_odd";
485: $keyIsEven = "{$prefix}is_even";
486: $keyIsLast = "{$prefix}is_last";
487:
488: $count = count($array);
489: $i = 0;
490: $isEven = false;
491: foreach ($array as $key => $element) {
492: if (is_object($element)) {
493: $this->_decorateArrayObject($element, $keyIsFirst, (0 === $i), $forceSetAll || (0 === $i));
494: $this->_decorateArrayObject($element, $keyIsOdd, !$isEven, $forceSetAll || !$isEven);
495: $this->_decorateArrayObject($element, $keyIsEven, $isEven, $forceSetAll || $isEven);
496: $isEven = !$isEven;
497: $i++;
498: $this->_decorateArrayObject($element, $keyIsLast, ($i === $count), $forceSetAll || ($i === $count));
499: }
500: elseif (is_array($element)) {
501: if ($forceSetAll || (0 === $i)) {
502: $array[$key][$keyIsFirst] = (0 === $i);
503: }
504: if ($forceSetAll || !$isEven) {
505: $array[$key][$keyIsOdd] = !$isEven;
506: }
507: if ($forceSetAll || $isEven) {
508: $array[$key][$keyIsEven] = $isEven;
509: }
510: $isEven = !$isEven;
511: $i++;
512: if ($forceSetAll || ($i === $count)) {
513: $array[$key][$keyIsLast] = ($i === $count);
514: }
515: }
516: }
517:
518: return $array;
519: }
520:
521: private function _decorateArrayObject($element, $key, $value, $dontSkip) {
522: if ($dontSkip) {
523: if ($element instanceof Varien_Object) {
524: $element->setData($key, $value);
525: }
526: else {
527: $element->$key = $value;
528: }
529: }
530: }
531:
532: 533: 534: 535: 536: 537: 538: 539: 540:
541: public function assocToXml(array $array, $rootName = '_')
542: {
543: if (empty($rootName) || is_numeric($rootName)) {
544: throw new Exception('Root element must not be empty or numeric');
545: }
546:
547: $xmlstr = <<<XML
548: <?xml version='1.0' encoding='UTF-8' standalone='yes'?>
549: <$rootName></$rootName>
550: XML;
551: $xml = new SimpleXMLElement($xmlstr);
552: foreach ($array as $key => $value) {
553: if (is_numeric($key)) {
554: throw new Exception('Array root keys must not be numeric.');
555: }
556: }
557: return self::_assocToXml($array, $rootName, $xml);
558: }
559:
560: 561: 562: 563: 564: 565: 566: 567: 568:
569: private function _assocToXml(array $array, $rootName, SimpleXMLElement &$xml)
570: {
571: $hasNumericKey = false;
572: $hasStringKey = false;
573: foreach ($array as $key => $value) {
574: if (!is_array($value)) {
575: if (is_string($key)) {
576: if ($key === $rootName) {
577: throw new Exception('Associative key must not be the same as its parent associative key.');
578: }
579: $hasStringKey = true;
580: $xml->$key = $value;
581: }
582: elseif (is_int($key)) {
583: $hasNumericKey = true;
584: $xml->{$rootName}[$key] = $value;
585: }
586: }
587: else {
588: self::_assocToXml($value, $key, $xml->$key);
589: }
590: }
591: if ($hasNumericKey && $hasStringKey) {
592: throw new Exception('Associative and numeric keys must not be mixed at one level.');
593: }
594: return $xml;
595: }
596:
597: 598: 599: 600: 601: 602: 603:
604: public function xmlToAssoc(SimpleXMLElement $xml)
605: {
606: $array = array();
607: foreach ($xml as $key => $value) {
608: if (isset($value->$key)) {
609: $i = 0;
610: foreach ($value->$key as $v) {
611: $array[$key][$i++] = (string)$v;
612: }
613: }
614: else {
615:
616: $array[$key] = trim((string)$value);
617: if (empty($array[$key]) && !empty($value)) {
618: $array[$key] = self::xmlToAssoc($value);
619: }
620:
621: else {
622: $array[$key] = (string)$value;
623: }
624: }
625: }
626: return $array;
627: }
628:
629: 630: 631: 632: 633: 634: 635: 636:
637: public function jsonEncode($valueToEncode, $cycleCheck = false, $options = array())
638: {
639: $json = Zend_Json::encode($valueToEncode, $cycleCheck, $options);
640:
641: $inline = Mage::getSingleton('core/translate_inline');
642: if ($inline->isAllowed()) {
643: $inline->setIsJson(true);
644: $inline->processResponseBody($json);
645: $inline->setIsJson(false);
646: }
647:
648: return $json;
649: }
650:
651: 652: 653: 654: 655: 656: 657:
658: public function jsonDecode($encodedValue, $objectDecodeType = Zend_Json::TYPE_ARRAY)
659: {
660: return Zend_Json::decode($encodedValue, $objectDecodeType);
661: }
662:
663: 664: 665: 666: 667:
668: public function uniqHash($prefix = '')
669: {
670: return $prefix . md5(uniqid(microtime().mt_rand(), true));
671: }
672:
673: 674: 675: 676: 677: 678: 679: 680: 681: 682: 683: 684: 685: 686: 687: 688: 689: 690: 691:
692: public function mergeFiles(array $srcFiles, $targetFile = false, $mustMerge = false,
693: $beforeMergeCallback = null, $extensionsFilter = array())
694: {
695: try {
696:
697: $shouldMerge = $mustMerge || !$targetFile;
698: if (!$shouldMerge) {
699: if (!file_exists($targetFile)) {
700: $shouldMerge = true;
701: } else {
702: $targetMtime = filemtime($targetFile);
703: foreach ($srcFiles as $file) {
704: if (!file_exists($file) || @filemtime($file) > $targetMtime) {
705: $shouldMerge = true;
706: break;
707: }
708: }
709: }
710: }
711:
712:
713: if ($shouldMerge) {
714: if ($targetFile && !is_writeable(dirname($targetFile))) {
715:
716: throw new Exception(sprintf('Path %s is not writeable.', dirname($targetFile)));
717: }
718:
719:
720: if ($extensionsFilter) {
721: if (!is_array($extensionsFilter)) {
722: $extensionsFilter = array($extensionsFilter);
723: }
724: if (!empty($srcFiles)){
725: foreach ($srcFiles as $key => $file) {
726: $fileExt = strtolower(pathinfo($file, PATHINFO_EXTENSION));
727: if (!in_array($fileExt, $extensionsFilter)) {
728: unset($srcFiles[$key]);
729: }
730: }
731: }
732: }
733: if (empty($srcFiles)) {
734:
735: throw new Exception('No files to compile.');
736: }
737:
738: $data = '';
739: foreach ($srcFiles as $file) {
740: if (!file_exists($file)) {
741: continue;
742: }
743: $contents = file_get_contents($file) . "\n";
744: if ($beforeMergeCallback && is_callable($beforeMergeCallback)) {
745: $contents = call_user_func($beforeMergeCallback, $file, $contents);
746: }
747: $data .= $contents;
748: }
749: if (!$data) {
750:
751: throw new Exception(sprintf("No content found in files:\n%s", implode("\n", $srcFiles)));
752: }
753: if ($targetFile) {
754: file_put_contents($targetFile, $data, LOCK_EX);
755: } else {
756: return $data;
757: }
758: }
759:
760: return true;
761: } catch (Exception $e) {
762: Mage::logException($e);
763: }
764: return false;
765: }
766:
767: 768: 769: 770: 771: 772:
773: public function getDefaultCountry($store = null)
774: {
775: return Mage::getStoreConfig(self::XML_PATH_DEFAULT_COUNTRY, $store);
776: }
777:
778: 779: 780: 781: 782: 783:
784: public function getProtectedFileExtensions($store = null)
785: {
786: return Mage::getStoreConfig(self::XML_PATH_PROTECTED_FILE_EXTENSIONS, $store);
787: }
788:
789: 790: 791: 792: 793:
794: public function getPublicFilesValidPath()
795: {
796: return Mage::getStoreConfig(self::XML_PATH_PUBLIC_FILES_VALID_PATHS);
797: }
798:
799: 800: 801: 802: 803: 804: 805:
806: public function checkLfiProtection($name)
807: {
808: if (preg_match('#\.\.[\\\/]#', $name)) {
809: throw new Mage_Core_Exception($this->__('Requested file may not include parent directory traversal ("../", "..\\" notation)'));
810: }
811: return true;
812: }
813:
814: 815: 816: 817: 818:
819: public function useDbCompatibleMode()
820: {
821: $connType = (string) Mage::getConfig()->getNode(self::XML_PATH_CONNECTION_TYPE);
822: $path = 'global/resource/connection/types/' . $connType . '/compatibleMode';
823: $value = (string) Mage::getConfig()->getNode($path);
824: return (bool) $value;
825: }
826:
827: 828: 829: 830: 831: 832:
833: public function getMerchantCountryCode($store = null)
834: {
835: return (string) Mage::getStoreConfig(self::XML_PATH_MERCHANT_COUNTRY_CODE, $store);
836: }
837:
838: 839: 840: 841: 842: 843:
844: public function getMerchantVatNumber($store = null)
845: {
846: return (string) Mage::getStoreConfig(self::XML_PATH_MERCHANT_VAT_NUMBER, $store);
847: }
848:
849: 850: 851: 852: 853: 854: 855:
856: public function isCountryInEU($countryCode, $storeId = null)
857: {
858: $euCountries = explode(',', Mage::getStoreConfig(self::XML_PATH_EU_COUNTRIES_LIST, $storeId));
859: return in_array($countryCode, $euCountries);
860: }
861:
862: 863: 864: 865: 866: 867: 868:
869: public function getExactDivision($dividend, $divisor)
870: {
871: $epsilon = $divisor / self::DIVIDE_EPSILON;
872:
873: $remainder = fmod($dividend, $divisor);
874: if (abs($remainder - $divisor) < $epsilon || abs($remainder) < $epsilon) {
875: $remainder = 0;
876: }
877:
878: return $remainder;
879: }
880: }
881: