PageRenderTime 57ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/blog/wp-content/plugins/shopp/core/functions.php

https://github.com/kennethreitz-archive/wordpress-skeleton
PHP | 1193 lines | 915 code | 154 blank | 124 comment | 240 complexity | cbea2831920931aba91d527daee5375c MD5 | raw file
  1. <?php
  2. /* functions.php
  3. * Library of global utility functions */
  4. /**
  5. * Calculate the time based on a repeating interval in a given
  6. * month and year. Ex: Fourth Thursday in November (Thanksgiving). */
  7. function datecalc($week=-1,$dayOfWeek=-1,$month=-1,$year=-1) {
  8. $weekdays = array("sunday" => 0, "monday" => 1, "tuesday" => 2, "wednesday" => 3, "thursday" => 4, "friday" => 5, "saturday" => 6);
  9. $weeks = array("first" => 1, "second" => 2, "third" => 3, "fourth" => 4, "last" => -1);
  10. if ($month == -1) $month = date ("n"); // No month provided, use current month
  11. if ($year == -1) $year = date("Y"); // No year provided, use current year
  12. // Day of week is a string, look it up in the weekdays list
  13. if (!is_numeric($dayOfWeek)) {
  14. foreach ($weekdays as $dayName => $dayNum) {
  15. if (strtolower($dayOfWeek) == substr($dayName,0,strlen($dayOfWeek))) {
  16. $dayOfWeek = $dayNum;
  17. break;
  18. }
  19. }
  20. }
  21. if ($dayOfWeek < 0 || $dayOfWeek > 6) return false;
  22. if (!is_numeric($week)) $week = $weeks[$week];
  23. if ($week == -1) {
  24. $lastday = date("t", mktime(0,0,0,$month,1,$year));
  25. $tmp = (date("w",mktime(0,0,0,$month,$lastday,$year)) - $dayOfWeek) % 7;
  26. if ($tmp < 0) $tmp += 7;
  27. $day = $lastday - $tmp;
  28. } else {
  29. $tmp = ($dayOfWeek - date("w",mktime(0,0,0,$month,1,$year))) % 7;
  30. if ($tmp < 0) $tmp += 7;
  31. $day = (7 * $week) - 6 + $tmp;
  32. }
  33. return mktime(0,0,0,$month,$day,$year);
  34. }
  35. /**
  36. * Converts a datetime value from a MySQL datetime format to a Unix timestamp. */
  37. function mktimestamp ($datetime) {
  38. $h = $mn = $s = 0;
  39. list($Y, $M, $D, $h, $mn, $s) = sscanf($datetime,"%d-%d-%d %d:%d:%d");
  40. return mktime($h, $mn, $s, $M, $D, $Y);
  41. }
  42. /**
  43. * Converts a Unix timestamp value to a datetime format suitable for entry in a
  44. * MySQL record. */
  45. function mkdatetime ($timestamp) {
  46. return date("Y-m-d H:i:s",$timestamp);
  47. }
  48. /**
  49. * Returns the corresponding 24-hour $hour based on a 12-hour based $hour
  50. * and the AM (Ante Meridiem) / PM (Post Meridiem) $meridiem. */
  51. function mk24hour ($hour, $meridiem) {
  52. if ($hour < 12 && $meridiem == "PM") return $hour + 12;
  53. if ($hour == 12 && $meridiem == "AM") return 0;
  54. return $hour;
  55. }
  56. /**
  57. * Returns a string of the number of years, months, days, hours,
  58. * minutes and even seconds from a specified date ($date). */
  59. function readableTime($date, $long = false) {
  60. $secs = time() - $date;
  61. if (!$secs) return false;
  62. $i = 0; $j = 1;
  63. $desc = array(1 => 'second',
  64. 60 => 'minute',
  65. 3600 => 'hour',
  66. 86400 => 'day',
  67. 604800 => 'week',
  68. 2628000 => 'month',
  69. 31536000 => 'year');
  70. while (list($k,) = each($desc)) $breaks[] = $k;
  71. sort($breaks);
  72. while ($i < count($breaks) && $secs >= $breaks[$i]) $i++;
  73. $i--;
  74. $break = $breaks[$i];
  75. $val = intval($secs / $break);
  76. $retval = $val . ' ' . $desc[$break] . ($val>1?'s':'');
  77. if ($long && $i > 0) {
  78. $rest = $secs % $break;
  79. $break = $breaks[--$i];
  80. $rest = intval($rest/$break);
  81. if ($rest > 0) {
  82. $resttime = $rest.' '.$desc[$break].($rest > 1?'s':'');
  83. $retval .= ", $resttime";
  84. }
  85. }
  86. return $retval;
  87. }
  88. function duration ($start,$end) {
  89. return ceil(($end - $start) / 86400);
  90. }
  91. /**
  92. * Sends an e-mail message in the format of a specified e-mail
  93. * template ($template) file providing variable substitution
  94. * for variables appearing in the template as a bracketed
  95. * [variable] with data from the coinciding $data['variable']
  96. * or $_POST['variable'] */
  97. function shopp_email ($template,$data=array()) {
  98. if (strpos($template,"\r\n") !== false) $f = explode("\r\n",$template);
  99. else {
  100. if (file_exists($template)) $f = file($template);
  101. else new ShoppError(__("Could not open the email template because the file does not exist or is not readable.","Shopp"),'email_template',SHOPP_ADMIN_ERR,array('template'=>$template));
  102. }
  103. $replacements = array(
  104. "$" => "\\\$", // Treat $ signs as literals
  105. "€" => "&euro;", // Fix euro symbols
  106. "¥" => "&yen;", // Fix yen symbols
  107. "£" => "&pound;", // Fix pound symbols
  108. "¤" => "&curren;" // Fix generic currency symbols
  109. );
  110. $debug = false;
  111. $in_body = false;
  112. $headers = "";
  113. $message = "";
  114. $protected = array("from","to","subject","cc","bcc");
  115. while ( list($linenum,$line) = each($f) ) {
  116. $line = rtrim($line);
  117. // Data parse
  118. if ( preg_match_all("/\[(.+?)\]/",$line,$labels,PREG_SET_ORDER) ) {
  119. while ( list($i,$label) = each($labels) ) {
  120. $code = $label[1];
  121. if (empty($data)) $string = $_POST[$code];
  122. else $string = $data[$code];
  123. $string = str_replace(array_keys($replacements),array_values($replacements),$string);
  124. if (isset($string) && !is_array($string)) $line = preg_replace("/\[".$code."\]/",$string,$line);
  125. }
  126. }
  127. // Header parse
  128. if ( preg_match("/^(.+?):\s(.+)$/",$line,$found) && !$in_body ) {
  129. $header = $found[1];
  130. $string = $found[2];
  131. if (in_array(strtolower($header),$protected)) // Protect against header injection
  132. $string = str_replace(array("\r","\n"),"",urldecode($string));
  133. if ( strtolower($header) == "to" ) $to = $string;
  134. else if ( strtolower($header) == "subject" ) $subject = $string;
  135. else $headers .= $line."\n";
  136. }
  137. // Catches the first blank line to begin capturing message body
  138. if ( empty($line) ) $in_body = true;
  139. if ( $in_body ) $message .= $line."\n";
  140. }
  141. if (!$debug) return mail($to,$subject,$message,$headers);
  142. else {
  143. echo "<pre>";
  144. echo "To: $to\n";
  145. echo "Subject: $subject\n\n";
  146. echo "Message:\n$message\n";
  147. echo "Headers:\n";
  148. print_r($headers);
  149. echo "<pre>";
  150. exit();
  151. }
  152. }
  153. /**
  154. * Generates an RSS-compliant string from an associative
  155. * array ($data) with a specific RSS-structure. */
  156. function shopp_rss ($data) {
  157. $xmlns = '';
  158. if (is_array($data['xmlns']))
  159. foreach ($data['xmlns'] as $key => $value)
  160. $xmlns .= ' xmlns:'.$key.'="'.$value.'"';
  161. $xml = "<?xml version=\"1.0\""." encoding=\"utf-8\"?>\n";
  162. $xml .= "<rss version=\"2.0\" xmlns:content=\"http://purl.org/rss/1.0/modules/content/\" xmlns:atom=\"http://www.w3.org/2005/Atom\" xmlns:g=\"http://base.google.com/ns/1.0\"$xmlns>\n";
  163. $xml .= "<channel>\n";
  164. $xml .= '<atom:link href="'.htmlentities($data['link']).'" rel="self" type="application/rss+xml" />'."\n";
  165. $xml .= "<title>".$data['title']."</title>\n";
  166. $xml .= "<description>".$data['description']."</description>\n";
  167. $xml .= "<link>".htmlentities($data['link'])."</link>\n";
  168. $xml .= "<language>en-us</language>\n";
  169. $xml .= "<copyright>Copyright ".date('Y').", ".$data['sitename']."</copyright>\n";
  170. if (is_array($data['items'])) {
  171. foreach($data['items'] as $item) {
  172. $xml .= "<item>\n";
  173. foreach ($item as $key => $value) {
  174. $attrs = '';
  175. if (is_array($value)) {
  176. $data = $value;
  177. $value = '';
  178. foreach ($data as $name => $content) {
  179. if (empty($name)) $value = $content;
  180. else $attrs .= ' '.$name.'="'.$content.'"';
  181. }
  182. }
  183. if (!empty($value)) $xml .= "<$key$attrs>$value</$key>\n";
  184. else $xml .= "<$key$attrs />\n";
  185. }
  186. $xml .= "</item>\n";
  187. }
  188. }
  189. $xml .= "</channel>\n";
  190. $xml .= "</rss>\n";
  191. return $xml;
  192. }
  193. function shopp_image () {
  194. $db =& DB::get();
  195. require("model/Asset.php");
  196. $table = DatabaseObject::tablename(Settings::$table);
  197. $settings = $db->query("SELECT name,value FROM $table WHERE name='image_storage' OR name='image_path'",AS_ARRAY);
  198. foreach ($settings as $setting) ${$setting->name} = $setting->value;
  199. if (isset($_GET['shopp_image'])) $image = $_GET['shopp_image'];
  200. elseif (preg_match('/\/images\/(\d+).*$/',$_SERVER['REQUEST_URI'],$matches))
  201. $image = $matches[1];
  202. if (empty($image)) die();
  203. $Asset = new Asset($image);
  204. header('Last-Modified: '.date('D, d M Y H:i:s', $Asset->created).' GMT');
  205. header("Content-type: ".$Asset->properties['mimetype']);
  206. header("Content-Disposition: inline; filename=".$Asset->name."");
  207. header("Content-Description: Delivered by WordPress/Shopp ".SHOPP_VERSION);
  208. if ($image_storage == "fs") {
  209. header ("Content-length: ".@filesize(trailingslashit($image_path).$Asset->name));
  210. readfile(trailingslashit($image_path).$Asset->name);
  211. } else {
  212. header ("Content-length: ".strlen($Asset->data));
  213. echo $Asset->data;
  214. }
  215. exit();
  216. }
  217. function shopp_catalog_css () {
  218. $db =& DB::get();
  219. $table = DatabaseObject::tablename(Settings::$table);
  220. $settings = $db->query("SELECT name,value FROM $table WHERE name='gallery_thumbnail_width' OR name='row_products' OR name='row_products' OR name='gallery_small_width' OR name='gallery_small_height'",AS_ARRAY);
  221. foreach ($settings as $setting) ${$setting->name} = $setting->value;
  222. $pluginuri = WP_PLUGIN_URL."/".basename(dirname(dirname(__FILE__)))."/";
  223. $pluginuri = force_ssl($pluginuri);
  224. if (!isset($row_products)) $row_products = 3;
  225. $products_per_row = floor((100/$row_products));
  226. ob_start();
  227. include("ui/styles/catalog.css");
  228. $file = ob_get_contents();
  229. ob_end_clean();
  230. header ("Content-type: text/css");
  231. header ("Content-Disposition: inline; filename=catalog.css");
  232. header ("Content-Description: Delivered by WordPress/Shopp ".SHOPP_VERSION);
  233. header ("Content-length: ".strlen($file));
  234. echo $file;
  235. exit();
  236. }
  237. function shopp_settings_js ($dir="shopp") {
  238. $db =& DB::get();
  239. $table = DatabaseObject::tablename(Settings::$table);
  240. $settings = $db->query("SELECT name,value FROM $table WHERE name='base_operations'",AS_ARRAY);
  241. foreach ($settings as $setting) ${$setting->name} = $setting->value;
  242. $base_operations = unserialize($base_operations);
  243. $path = array(PLUGINDIR,$dir,'lang');
  244. load_plugin_textdomain('Shopp', join(DIRECTORY_SEPARATOR,$path));
  245. ob_start();
  246. include("ui/behaviors/settings.js");
  247. $file = ob_get_contents();
  248. ob_end_clean();
  249. header ("Content-type: text/javascript");
  250. header ("Content-Disposition: inline; filename=settings.js");
  251. header ("Content-Description: Delivered by WordPress/Shopp ".SHOPP_VERSION);
  252. header ("Content-length: ".strlen($file));
  253. echo $file;
  254. exit();
  255. }
  256. /**
  257. * Formats a number into a standardized telephone number format */
  258. function phone ($num) {
  259. if (empty($num)) return "";
  260. $num = preg_replace("/[A-Za-z\-\s\(\)]/","",$num);
  261. if (strlen($num) == 7) sscanf($num, "%3s%4s", $prefix, $exchange);
  262. if (strlen($num) == 10) sscanf($num, "%3s%3s%4s", $area, $prefix, $exchange);
  263. if (strlen($num) == 11) sscanf($num, "%1s%3s%3s%4s",$country, $area, $prefix, $exchange);
  264. //if (strlen($num) > 11) sscanf($num, "%3s%3s%4s%s", $area, $prefix, $exchange, $ext);
  265. $string = "";
  266. $string .= (isset($country))?"$country ":"";
  267. $string .= (isset($area))?"($area) ":"";
  268. $string .= (isset($prefix))?$prefix:"";
  269. $string .= (isset($exchange))?"-$exchange":"";
  270. $string .= (isset($ext))?" x$ext":"";
  271. return $string;
  272. }
  273. /**
  274. * Determines if the current client is a known web crawler bot */
  275. function is_robot() {
  276. $bots = array("Googlebot","TeomaAgent","Zyborg","Gulliver","Architext spider","FAST-WebCrawler","Slurp","Ask Jeeves","ia_archiver","Scooter","Mercator","crawler@fast","Crawler","InfoSeek sidewinder","Lycos_Spider_(T-Rex)","Fluffy the Spider","Ultraseek","MantraAgent","Moget","MuscatFerret","VoilaBot","Sleek Spider","KIT_Fireball","WebCrawler");
  277. foreach($bots as $bot) {
  278. if (strpos(strtolower($_SERVER['HTTP_USER_AGENT']),strtolower($bot))) return true;
  279. }
  280. return false;
  281. }
  282. function shopp_prereqs () {
  283. $errors = array();
  284. // Check PHP version, this won't appear much since syntax errors in earlier
  285. // PHP releases will cause this code to never be executed
  286. if (!version_compare(PHP_VERSION, '5.0','>='))
  287. $errors[] = __("Shopp requires PHP version 5.0+. You are using PHP version ").PHP_VERSION;
  288. if (version_compare(PHP_VERSION, '5.1.3','=='))
  289. $errors[] = __("Shopp will not work with PHP version 5.1.3 because of a critical bug in complex POST data structures. Please upgrade PHP to version 5.1.4 or higher.");
  290. // Check WordPress version
  291. if (!version_compare(get_bloginfo('version'),'2.6','>='))
  292. $errors[] = __("Shopp requires WordPress version 2.6+. You are using WordPress version ").get_bloginfo('version');
  293. // Check for cURL
  294. if( !function_exists("curl_init") &&
  295. !function_exists("curl_setopt") &&
  296. !function_exists("curl_exec") &&
  297. !function_exists("curl_close") ) $errors[] = __("Shopp requires the cURL library for processing transactions securely. Your web hosting environment does not currently have cURL installed (or built into PHP).");
  298. // Check for GD
  299. if (!function_exists("gd_info")) $errors[] = __("Shopp requires the GD image library with JPEG support for generating gallery and thumbnail images. Your web hosting environment does not currently have GD installed (or built into PHP).");
  300. else {
  301. $gd = gd_info();
  302. if (!$gd['JPG Support'] && !$gd['JPEG Support']) $errors[] = __("Shopp requires JPEG support in the GD image library. Your web hosting environment does not currently have a version of GD installed that has JPEG support.");
  303. }
  304. if (!empty($errors)) {
  305. $string .= '<style type="text/css">body { font: 13px/1 "Lucida Grande", "Lucida Sans Unicode", Tahoma, Verdana, sans-serif; } p { margin: 10px; }</style>';
  306. foreach ($errors as $error) $string .= "<p>$error</p>";
  307. $string .= '<p>'.__('Sorry! You will not be able to use Shopp. For more information, see the <a href="http://docs.shopplugin.net/Installation" target="_blank">online Shopp documentation.</a>').'</p>';
  308. trigger_error($string,E_USER_ERROR);
  309. exit();
  310. }
  311. return true;
  312. }
  313. if( !function_exists('esc_url') ) {
  314. /**
  315. * Checks and cleans a URL. From WordPress 2.8.0+ Included for WordPress 2.7 Users of Shopp
  316. *
  317. * A number of characters are removed from the URL. If the URL is for displaying
  318. * (the default behaviour) amperstands are also replaced. The 'esc_url' filter
  319. * is applied to the returned cleaned URL.
  320. *
  321. * @since 2.8.0
  322. * @uses esc_url()
  323. * @uses wp_kses_bad_protocol() To only permit protocols in the URL set
  324. * via $protocols or the common ones set in the function.
  325. *
  326. * @param string $url The URL to be cleaned.
  327. * @param array $protocols Optional. An array of acceptable protocols.
  328. * Defaults to 'http', 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet' if not set.
  329. * @return string The cleaned $url after the 'cleaned_url' filter is applied.
  330. */
  331. function esc_url( $url, $protocols = null ) {
  332. return clean_url( $url, $protocols, 'display' );
  333. }
  334. }
  335. function shopp_debug ($object) {
  336. global $Shopp;
  337. ob_start();
  338. print_r($object);
  339. $result = ob_get_contents();
  340. ob_end_clean();
  341. $Shopp->_debug->objects .= "<br/><br/>".str_replace("\n","<br/>",$result);
  342. }
  343. function _object_r ($object) {
  344. global $Shopp;
  345. ob_start();
  346. print_r($object);
  347. $result = ob_get_contents();
  348. ob_end_clean();
  349. return $result;
  350. }
  351. function shopp_pagename ($page) {
  352. global $is_IIS;
  353. $prefix = strpos($page,"index.php/");
  354. if ($prefix !== false) return substr($page,$prefix+10);
  355. else return $page;
  356. }
  357. function shopp_redirect ($uri) {
  358. if (class_exists('ShoppError')) new ShoppError('Redirecting to: '.$uri,'shopp_redirect',SHOPP_DEBUG_ERR);
  359. wp_redirect($uri);
  360. exit();
  361. }
  362. function get_filemeta ($file) {
  363. if (!file_exists($file)) return false;
  364. if (!is_readable($file)) return false;
  365. $meta = false;
  366. $string = "";
  367. $f = @fopen($file, "r");
  368. if (!$f) return false;
  369. while (!feof($f)) {
  370. $buffer = fgets($f,80);
  371. if (preg_match("/\/\*/",$buffer)) $meta = true;
  372. if ($meta) $string .= $buffer;
  373. if (preg_match("/\*\//",$buffer)) break;
  374. }
  375. fclose($f);
  376. return $string;
  377. }
  378. /**
  379. * Recursively searches directories and one-level deep of
  380. * sub-directories for files with a specific extension
  381. * NOTE: Files are saved to the $found parameter,
  382. * an array passed by reference, not a returned value */
  383. function find_files ($extension, $directory, $root, &$found) {
  384. if (is_dir($directory)) {
  385. $Directory = @dir($directory);
  386. if ($Directory) {
  387. while (( $file = $Directory->read() ) !== false) {
  388. if (substr($file,0,1) == "." || substr($file,0,1) == "_") continue; // Ignore .dot files and _directories
  389. if (is_dir($directory.DIRECTORY_SEPARATOR.$file) && $directory == $root) // Scan one deep more than root
  390. find_files($extension,$directory.DIRECTORY_SEPARATOR.$file,$root, $found); // but avoid recursive scans
  391. if (substr($file,strlen($extension)*-1) == $extension)
  392. $found[] = substr($directory,strlen($root)).DIRECTORY_SEPARATOR.$file; // Add the file to the found list
  393. }
  394. return true;
  395. }
  396. }
  397. return false;
  398. }
  399. if (!function_exists('json_encode')) {
  400. function json_encode ($a = false) {
  401. if (is_null($a)) return 'null';
  402. if ($a === false) return 'false';
  403. if ($a === true) return 'true';
  404. if (is_scalar($a)) {
  405. if (is_float($a)) {
  406. // Always use "." for floats.
  407. return floatval(str_replace(",", ".", strval($a)));
  408. }
  409. if (is_string($a)) {
  410. static $jsonReplaces = array(array("\\", "/", "\n", "\t", "\r", "\b", "\f", '"'), array('\\\\', '\\/', '\\n', '\\t', '\\r', '\\b', '\\f', '\"'));
  411. return '"' . str_replace($jsonReplaces[0], $jsonReplaces[1], $a) . '"';
  412. } else return $a;
  413. }
  414. $isList = true;
  415. for ($i = 0, reset($a); $i < count($a); $i++, next($a)) {
  416. if (key($a) !== $i) {
  417. $isList = false;
  418. break;
  419. }
  420. }
  421. $result = array();
  422. if ($isList) {
  423. foreach ($a as $v) $result[] = json_encode($v);
  424. return '[' . join(',', $result) . ']';
  425. } else {
  426. foreach ($a as $k => $v) $result[] = json_encode($k).':'.json_encode($v);
  427. return '{' . join(',', $result) . '}';
  428. }
  429. }
  430. }
  431. /**
  432. * List files and directories inside the specified path */
  433. if(!function_exists('scandir')) {
  434. function scandir($dir, $sortorder = 0) {
  435. if(is_dir($dir) && $dirlist = @opendir($dir)) {
  436. $files = array();
  437. while(($file = readdir($dirlist)) !== false) $files[] = $file;
  438. closedir($dirlist);
  439. ($sortorder == 0) ? asort($files) : rsort($files);
  440. return $files;
  441. } else return false;
  442. }
  443. }
  444. function filter_dotfiles ($name) {
  445. return (substr($name,0,1) != ".");
  446. }
  447. /**
  448. * Checks an object for a declared property
  449. * if() checks to see if the function is already available (as in PHP 5) */
  450. if (!function_exists('property_exists')) {
  451. function property_exists($object, $property) {
  452. return array_key_exists($property, get_object_vars($object));
  453. }
  454. }
  455. if (!function_exists('attribute_escape_deep')) {
  456. function attribute_escape_deep($value) {
  457. $value = is_array($value) ?
  458. array_map('attribute_escape_deep', $value) :
  459. attribute_escape($value);
  460. return $value;
  461. }
  462. }
  463. function auto_ranges ($avg,$max,$min) {
  464. $ranges = array();
  465. if ($avg == 0 || $max == 0) return $ranges;
  466. $power = floor(log10($avg));
  467. $scale = pow(10,$power);
  468. $median = round($avg/$scale)*$scale;
  469. $range = $max-$min;
  470. if ($range == 0) return $ranges;
  471. $steps = floor($range/$scale);
  472. if ($steps > 7) $steps = 7;
  473. elseif ($steps < 2) {
  474. $scale = $scale/2;
  475. $steps = ceil($range/$scale);
  476. if ($steps > 7) $steps = 7;
  477. elseif ($steps < 2) $steps = 2;
  478. }
  479. $base = $median-($scale*floor(($steps-1)/2));
  480. for ($i = 0; $i < $steps; $i++) {
  481. $range = array("min" => 0,"max" => 0);
  482. if ($i == 0) $range['max'] = $base;
  483. else if ($i+1 >= $steps) $range['min'] = $base;
  484. else $range = array("min" => $base, "max" => $base+$scale);
  485. $ranges[] = $range;
  486. if ($i > 0) $base += $scale;
  487. }
  488. return $ranges;
  489. }
  490. function floatvalue($value, $format=true) {
  491. $value = preg_replace("/[^\d,\.]/","",$value); // Remove any non-numeric string data
  492. $value = preg_replace("/,/",".",$value); // Replace commas with periods
  493. $value = preg_replace("/[^0-9\.]/","", $value); // Get rid of everything but numbers and periods
  494. $value = preg_replace("/\.(?=.*\..*$)/s","",$value); // Replace all but the last period
  495. $value = preg_replace('#^([-]*[0-9\.,\' ]+?)((\.|,){1}([0-9-]{1,2}))*$#e', "str_replace(array('.', ',', \"'\", ' '), '', '\\1') . '.' . sprintf('%02d','\\4')", $value);
  496. if($format) return number_format(floatval($value),2);
  497. else return floatval($value);
  498. }
  499. /**
  500. * sort_tree
  501. * Sorts a heirarchical tree of data */
  502. function sort_tree ($items,$parent=0,$key=-1,$depth=-1) {
  503. $depth++;
  504. $result = array();
  505. if ($items) {
  506. foreach ($items as $item) {
  507. if ($item->parent == $parent) {
  508. $item->parentkey = $key;
  509. $item->depth = $depth;
  510. $result[] = $item;
  511. $children = sort_tree($items, $item->id, count($result)-1, $depth);
  512. $result = array_merge($result,$children); // Add children in as they are found
  513. }
  514. }
  515. }
  516. $depth--;
  517. return $result;
  518. }
  519. /**
  520. * file_mimetype
  521. * Tries a variety of methods to determine a file's mimetype */
  522. function file_mimetype ($file,$name=false) {
  523. if (!$name) $name = basename($file);
  524. if (function_exists('finfo_open')) {
  525. // Try using PECL module
  526. $f = finfo_open(FILEINFO_MIME);
  527. list($mime,$charset) = explode(";",finfo_file($f, $file));
  528. finfo_close($f);
  529. new ShoppError('File mimetype detection (finfo_open): '.$mime,false,SHOPP_DEBUG_ERR);
  530. return $mime;
  531. } elseif (class_exists('finfo')) {
  532. // Or class
  533. $f = new finfo(FILEINFO_MIME);
  534. new ShoppError('File mimetype detection (finfo class): '.$f->file($file),false,SHOPP_DEBUG_ERR);
  535. return $f->file($file);
  536. } elseif (strlen($mime=trim(@shell_exec('file -bI "'.escapeshellarg($file).'"')))!=0) {
  537. new ShoppError('File mimetype detection (shell file command): '.$mime,false,SHOPP_DEBUG_ERR);
  538. // Use shell if allowed
  539. return trim($mime);
  540. } elseif (strlen($mime=trim(@shell_exec('file -bi "'.escapeshellarg($file).'"')))!=0) {
  541. new ShoppError('File mimetype detection (shell file command, alt options): '.$mime,false,SHOPP_DEBUG_ERR);
  542. // Use shell if allowed
  543. return trim($mime);
  544. } elseif (function_exists('mime_content_type') && $mime = mime_content_type($file)) {
  545. // Try with magic-mime if available
  546. new ShoppError('File mimetype detection (mime_content_type()): '.$mime,false,SHOPP_DEBUG_ERR);
  547. return $mime;
  548. } else {
  549. if (!preg_match('/\.([a-z0-9]{2,4})$/i', $name, $extension)) return false;
  550. switch (strtolower($extension[1])) {
  551. // misc files
  552. case 'txt': return 'text/plain';
  553. case 'htm': case 'html': case 'php': return 'text/html';
  554. case 'css': return 'text/css';
  555. case 'js': return 'application/javascript';
  556. case 'json': return 'application/json';
  557. case 'xml': return 'application/xml';
  558. case 'swf': return 'application/x-shockwave-flash';
  559. // images
  560. case 'jpg': case 'jpeg': case 'jpe': return 'image/jpg';
  561. case 'png': case 'gif': case 'bmp': case 'tiff': return 'image/'.strtolower($matches[1]);
  562. case 'tif': return 'image/tif';
  563. case 'svg': case 'svgz': return 'image/svg+xml';
  564. // archives
  565. case 'zip': return 'application/zip';
  566. case 'rar': return 'application/x-rar-compressed';
  567. case 'exe': case 'msi': return 'application/x-msdownload';
  568. case 'tar': return 'application/x-tar';
  569. case 'cab': return 'application/vnd.ms-cab-compressed';
  570. // audio/video
  571. case 'flv': return 'video/x-flv';
  572. case 'mpeg': case 'mpg': case 'mpe': return 'video/mpeg';
  573. case 'mp4s': return 'application/mp4';
  574. case 'mp3': return 'audio/mpeg3';
  575. case 'wav': return 'audio/wav';
  576. case 'aiff': case 'aif': return 'audio/aiff';
  577. case 'avi': return 'video/msvideo';
  578. case 'wmv': return 'video/x-ms-wmv';
  579. case 'mov': case 'qt': return 'video/quicktime';
  580. // ms office
  581. case 'doc': case 'docx': return 'application/msword';
  582. case 'xls': case 'xlt': case 'xlm': case 'xld': case 'xla': case 'xlc': case 'xlw': case 'xll': return 'application/vnd.ms-excel';
  583. case 'ppt': case 'pps': return 'application/vnd.ms-powerpoint';
  584. case 'rtf': return 'application/rtf';
  585. // adobe
  586. case 'pdf': return 'application/pdf';
  587. case 'psd': return 'image/vnd.adobe.photoshop';
  588. case 'ai': case 'eps': case 'ps': return 'application/postscript';
  589. // open office
  590. case 'odt': return 'application/vnd.oasis.opendocument.text';
  591. case 'ods': return 'application/vnd.oasis.opendocument.spreadsheet';
  592. }
  593. return false;
  594. }
  595. }
  596. /**
  597. * Returns a list marked-up as drop-down menu options */
  598. function menuoptions ($list,$selected=null,$values=false,$extend=false) {
  599. if (!is_array($list)) return "";
  600. $string = "";
  601. // Extend the options if the selected value doesn't exist
  602. if ((!in_array($selected,$list) && !isset($list[$selected])) && $extend)
  603. $string .= "<option value=\"$selected\">$selected</option>";
  604. foreach ($list as $value => $text) {
  605. if ($values) {
  606. if ($value == $selected) $string .= "<option value=\"$value\" selected=\"selected\">$text</option>";
  607. else $string .= "<option value=\"$value\">$text</option>";
  608. } else {
  609. if ($text == $selected) $string .= "<option selected=\"selected\">$text</option>";
  610. else $string .= "<option>$text</option>";
  611. }
  612. }
  613. return $string;
  614. }
  615. function scan_money_format ($format) {
  616. $f = array(
  617. "cpos" => true,
  618. "currency" => "",
  619. "precision" => 0,
  620. "decimals" => "",
  621. "thousands" => ""
  622. );
  623. $ds = strpos($format,'#'); $de = strrpos($format,'#')+1;
  624. $df = substr($format,$ds,($de-$ds));
  625. if ($df == "#,##,###.##") $f['indian'] = true;
  626. $f['cpos'] = true;
  627. if ($de == strlen($format)) $f['currency'] = substr($format,0,$ds);
  628. else {
  629. $f['currency'] = substr($format,$de);
  630. $f['cpos'] = false;
  631. }
  632. $i = 0; $dd = 0;
  633. $dl = array();
  634. $sdl = "";
  635. $uniform = true;
  636. while($i < strlen($df)) {
  637. $c = substr($df,$i++,1);
  638. if ($c != "#") {
  639. if(empty($sdl)) $sdl = $c;
  640. else if($sdl != $c) $uniform = false;
  641. $dl[] = $c;
  642. $dd = 0;
  643. } else $dd++;
  644. }
  645. if(!$uniform) $f['precision'] = $dd;
  646. if (count($dl) > 1) {
  647. if ($dl[0] == "t") {
  648. $f['thousands'] = $dl[1];
  649. $f['precision'] = 0;
  650. }
  651. else {
  652. $f['decimals'] = $dl[count($dl)-1];
  653. $f['thousands'] = $dl[0];
  654. }
  655. } else $f['decimals'] = $dl[0];
  656. return $f;
  657. }
  658. function money ($amount,$format=false) {
  659. global $Shopp;
  660. $locale = $Shopp->Settings->get('base_operations');
  661. if (!$format) $format = $locale['currency']['format'];
  662. if (empty($format['currency']))
  663. $format = array("cpos"=>true,"currency"=>"$","precision"=>2,"decimals"=>".","thousands" => ",");
  664. if (isset($format['indian'])) $number = indian_number($amount,$format);
  665. else $number = number_format($amount, $format['precision'], $format['decimals'], $format['thousands']);
  666. if ($format['cpos']) return $format['currency'].$number;
  667. else return $number.$format['currency'];
  668. }
  669. function percentage ($amount,$format=false) {
  670. global $Shopp;
  671. $locale = $Shopp->Settings->get('base_operations');
  672. if (!$format) {
  673. $format = $locale['currency']['format'];
  674. $format['precision'] = 0;
  675. }
  676. if (!$format) $format = array("precision"=>1,"decimals"=>".","thousands" => ",");
  677. if (isset($format['indian'])) return indian_number($amount,$format);
  678. return number_format(round($amount), $format['precision'], $format['decimals'], $format['thousands']).'%';
  679. }
  680. function indian_number ($number,$format=false) {
  681. if (!$format) $format = array("precision"=>1,"decimals"=>".","thousands" => ",");
  682. $d = explode(".",$number);
  683. $number = "";
  684. $digits = substr($d[0],0,-3); // Get rid of the last 3
  685. if (strlen($d[0]) > 3) $number = substr($d[0],-3);
  686. else $number = $d[0];
  687. for ($i = 0; $i < (strlen($digits) / 2); $i++)
  688. $number = substr($digits,(-2*($i+1)),2).((strlen($number) > 0)?$format['thousands'].$number:$number);
  689. if ($format['precision'] > 0)
  690. $number = $number.$format['decimals'].substr(number_format('0.'.$d[1],$format['precision']),2);
  691. return $number;
  692. }
  693. function floatnum ($number) {
  694. $number = preg_replace("/,/",".",$number); // Replace commas with periods
  695. $number = preg_replace("/[^0-9\.]/","", $number); // Get rid of everything but numbers and periods
  696. $number = preg_replace("/\.(?=.*\..+$)/s","",$number); // Replace all but the last period
  697. return $number;
  698. }
  699. function value_is_true ($value) {
  700. switch (strtolower($value)) {
  701. case "yes": case "true": case "1": case "on": return true;
  702. default: return false;
  703. }
  704. }
  705. function valid_input ($type) {
  706. $inputs = array("text","hidden","checkbox","radio","button","submit");
  707. if (in_array($type,$inputs) !== false) return true;
  708. return false;
  709. }
  710. function _d($format,$timestamp=false) {
  711. $tokens = array(
  712. 'D' => array('Mon' => __('Mon','Shopp'),'Tue' => __('Tue','Shopp'),
  713. 'Wed' => __('Wed','Shopp'),'Thu' => __('Thu','Shopp'),
  714. 'Fri' => __('Fri','Shopp'),'Sat' => __('Sat','Shopp'),
  715. 'Sun' => __('Sun','Shopp')),
  716. 'l' => array('Monday' => __('Monday','Shopp'),'Tuesday' => __('Tuesday','Shopp'),
  717. 'Wednesday' => __('Wednesday','Shopp'),'Thursday' => __('Thursday','Shopp'),
  718. 'Friday' => __('Friday','Shopp'),'Saturday' => __('Saturday','Shopp'),
  719. 'Sunday' => __('Sunday','Shopp')),
  720. 'F' => array('January' => __('January','Shopp'),'February' => __('February','Shopp'),
  721. 'March' => __('March','Shopp'),'April' => __('April','Shopp'),
  722. 'May' => __('May','Shopp'),'June' => __('June','Shopp'),
  723. 'July' => __('July','Shopp'),'August' => __('August','Shopp'),
  724. 'September' => __('September','Shopp'),'October' => __('October','Shopp'),
  725. 'November' => __('November','Shopp'),'December' => __('December','Shopp')),
  726. 'M' => array('Jan' => __('Jan','Shopp'),'Feb' => __('Feb','Shopp'),
  727. 'Mar' => __('Mar','Shopp'),'Apr' => __('Apr','Shopp'),
  728. 'May' => __('May','Shopp'),'Jun' => __('Jun','Shopp'),
  729. 'Jul' => __('Jul','Shopp'),'Aug' => __('Aug','Shopp'),
  730. 'Sep' => __('Sep','Shopp'),'Oct' => __('Oct','Shopp'),
  731. 'Nov' => __('Nov','Shopp'),'Dec' => __('Dec','Shopp'))
  732. );
  733. if (!$timestamp) $date = date($format);
  734. else $date = date($format,$timestamp);
  735. foreach ($tokens as $token => $strings) {
  736. if ($pos = strpos($format,$token) === false) continue;
  737. $string = (!$timestamp)?date($token):date($token,$timestamp);
  738. $date = str_replace($string,$strings[$string],$date);
  739. }
  740. return $date;
  741. }
  742. function shopp_taxrate ($override=null,$taxprice=true) {
  743. global $Shopp;
  744. $rated = false;
  745. $taxrate = 0;
  746. $base = $Shopp->Settings->get('base_operations');
  747. if ($base['vat']) $rated = true;
  748. if (!is_null($override)) $rated = (value_is_true($override));
  749. if (!value_is_true($taxprice)) $rated = false;
  750. if ($rated) $taxrate = $Shopp->Cart->taxrate();
  751. return $taxrate;
  752. }
  753. function inputattrs ($options,$allowed=array()) {
  754. if (!is_array($options)) return "";
  755. if (empty($allowed)) {
  756. $allowed = array("accesskey","alt","checked","class","disabled","format",
  757. "minlength","maxlength","readonly","required","size","src","tabindex",
  758. "title","value");
  759. }
  760. $string = "";
  761. $classes = "";
  762. if (isset($options['label'])) $options['value'] = $options['label'];
  763. foreach ($options as $key => $value) {
  764. if (!in_array($key,$allowed)) continue;
  765. switch($key) {
  766. case "class": $classes .= " $value"; break;
  767. case "disabled": $classes .= " disabled"; $string .= ' disabled="disabled"'; break;
  768. case "readonly": $classes .= " readonly"; $string .= ' readonly="readonly"'; break;
  769. case "required": $classes .= " required"; break;
  770. case "minlength": $classes .= " min$value"; break;
  771. case "format": $classes .= " $value"; break;
  772. default:
  773. $string .= ' '.$key.'="'.$value.'"';
  774. }
  775. }
  776. $string .= ' class="'.trim($classes).'"';
  777. return $string;
  778. }
  779. function build_query_request ($request=array()) {
  780. $query = "";
  781. foreach ($request as $name => $value) {
  782. if (strlen($query) > 0) $query .= "&";
  783. $query .= "$name=$value";
  784. }
  785. return $query;
  786. }
  787. function readableFileSize($bytes,$precision=1) {
  788. $units = array(__("bytes","Shopp"),"KB","MB","GB","TB","PB");
  789. $sized = $bytes*1;
  790. if ($sized == 0) return $sized;
  791. $unit = 0;
  792. while ($sized > 1024 && ++$unit) $sized = $sized/1024;
  793. return round($sized,$precision)." ".$units[$unit];
  794. }
  795. // From WP 2.7.0 for backwards compatibility
  796. function shopp_print_column_headers( $type, $id = true ) {
  797. global $wp_version;
  798. if (version_compare($wp_version,"2.7.0",">="))
  799. return print_column_headers($type,$id);
  800. $type = str_replace('.php', '', $type);
  801. $columns = shopp_get_column_headers( $type );
  802. $hidden = array();
  803. $styles = array();
  804. foreach ( $columns as $column_key => $column_display_name ) {
  805. $class = ' class="manage-column';
  806. $class .= " column-$column_key";
  807. if ( 'cb' == $column_key ) $class .= ' check-column';
  808. elseif ( in_array($column_key, array('posts', 'comments', 'links')) )
  809. $class .= ' num';
  810. $class .= '"';
  811. $style = '';
  812. if ( in_array($column_key, $hidden) )
  813. $style = 'display:none;';
  814. if ( isset($styles[$type]) && isset($styles[$type][$column_key]) )
  815. $style .= ' ' . $styles[$type][$column_key];
  816. $style = ' style="' . $style . '"';
  817. ?>
  818. <th scope="col" <?php echo $id ? "id=\"$column_key\"" : ""; echo $class; echo $style; ?>><?php echo $column_display_name; ?></th>
  819. <?php }
  820. }
  821. // Adapted from WP 2.7.0 for backwards compatibility
  822. function shopp_register_column_headers($screen, $columns) {
  823. global $wp_version;
  824. if (version_compare($wp_version,"2.7.0",">="))
  825. return register_column_headers($screen,$columns);
  826. global $_wp_column_headers;
  827. if ( !isset($_wp_column_headers) )
  828. $_wp_column_headers = array();
  829. $_wp_column_headers[$screen] = $columns;
  830. }
  831. // Adapted from WP 2.7.0 for backwards compatibility
  832. function shopp_get_column_headers($page) {
  833. global $_wp_column_headers;
  834. if ( !isset($_wp_column_headers) )
  835. $_wp_column_headers = array();
  836. // Store in static to avoid running filters on each call
  837. if ( isset($_wp_column_headers[$page]) )
  838. return $_wp_column_headers[$page];
  839. return array();
  840. }
  841. function copy_shopp_templates ($src,$target) {
  842. $builtin = array_filter(scandir($src),"filter_dotfiles");
  843. foreach ($builtin as $template) {
  844. $target_file = $target.DIRECTORY_SEPARATOR.$template;
  845. if (!file_exists($target_file)) {
  846. $src_file = file_get_contents($src.DIRECTORY_SEPARATOR.$template);
  847. $file = fopen($target_file,'w');
  848. $src_file = preg_replace('/^<\?php\s\/\*\*\s+(.*?\s)*?\*\*\/\s\?>\s/','',$src_file);
  849. fwrite($file,$src_file);
  850. fclose($file);
  851. chmod($target_file,0666);
  852. }
  853. }
  854. }
  855. /**
  856. * Determines if the requested page is a Shopp page or if it matches a given Shopp page
  857. *
  858. * @param string $page (optional) Page name to look for in Shopp's page registry
  859. * @return boolean
  860. * @author Jonathan Davis
  861. **/
  862. function is_shopp_page ($page=false) {
  863. global $Shopp,$wp_query;
  864. if ($wp_query->post->post_type != "page") return false;
  865. $pages = $Shopp->Settings->get('pages');
  866. // Detect if the requested page is a Shopp page
  867. if (!$page) {
  868. foreach ($pages as $page)
  869. if ($page['id'] == $wp_query->post->ID) return true;
  870. return false;
  871. }
  872. // Determine if the visitor's requested page matches the provided page
  873. if (!isset($pages[strtolower($page)])) return false;
  874. $page = $pages[strtolower($page)];
  875. if ($page['id'] == $wp_query->post->ID) return true;
  876. return false;
  877. }
  878. function is_shopp_secure () {
  879. return (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == "on");
  880. }
  881. function template_path ($path) {
  882. if (DIRECTORY_SEPARATOR == "\\") $path = str_replace("/","\\",$path);
  883. return $path;
  884. }
  885. function gateway_path ($file) {
  886. return basename(dirname($file)).DIRECTORY_SEPARATOR.basename($file);
  887. }
  888. function force_ssl ($url) {
  889. if(isset($_SERVER['HTTPS']) && $_SERVER["HTTPS"] == "on")
  890. $url = str_replace('http://', 'https://', $url);
  891. return $url;
  892. }
  893. if ( !function_exists('sys_get_temp_dir')) {
  894. // For PHP 5 (pre-5.2.1)
  895. function sys_get_temp_dir() {
  896. if (!empty($_ENV['TMP'])) return realpath($_ENV['TMP']);
  897. if (!empty($_ENV['TMPDIR'])) return realpath( $_ENV['TMPDIR']);
  898. if (!empty($_ENV['TEMP'])) return realpath( $_ENV['TEMP']);
  899. $tempfile = tempnam(uniqid(rand(),TRUE),'');
  900. if (file_exists($tempfile)) {
  901. unlink($tempfile);
  902. return realpath(dirname($tempfile));
  903. }
  904. }
  905. }
  906. class FTPClient {
  907. var $connected = false;
  908. var $log = array();
  909. var $remapped = false;
  910. function FTPClient ($host, $user, $password) {
  911. $this->connect($host, $user, $password);
  912. if ($this->connected) ftp_pasv($this->connection,true);
  913. else return false;
  914. return true;
  915. }
  916. /**
  917. * Connects to the FTP server */
  918. function connect($host, $user, $password) {
  919. $this->connection = @ftp_connect($host,0,20);
  920. if (!$this->connection) return false;
  921. $this->connected = @ftp_login($this->connection,$user,$password);
  922. if (!$this->connected) return false;
  923. return true;
  924. }
  925. /**
  926. * update()
  927. * Recursively copies files from a src $path to the $remote path */
  928. function update ($path,$remote) {
  929. if (is_dir($path)){
  930. $path = trailingslashit($path);
  931. // $this->log[] = "The source path is $path";
  932. $files = scandir($path);
  933. $remote = trailingslashit($remote);
  934. // $this->log[] = "The destination path is $remote";
  935. } else {
  936. $files = array(basename($path));
  937. $path = trailingslashit(dirname($path));
  938. // $this->log[] = "The source path is $path";
  939. $remote = trailingslashit(dirname($remote));
  940. // $this->log[] = "The destination path is $remote";
  941. }
  942. if (!$this->remapped) $remote = $this->remappath($remote);
  943. // $this->log[] = "The remapped destination path is $remote";
  944. $excludes = array(".","..");
  945. foreach ((array)$files as $file) {
  946. if (in_array($file,$excludes)) continue;
  947. if (is_dir($path.$file)) {
  948. if (!@ftp_chdir($this->connection,$remote.$file))
  949. $this->mkdir($remote.$file);
  950. $this->update($path.$file,$remote.$file);
  951. } else $this->put($path.$file,$remote.$file);
  952. }
  953. return $this->log;
  954. }
  955. /**
  956. * delete()
  957. * Delete the target file, recursively delete directories */
  958. function delete ($file) {
  959. if (empty($file)) return false;
  960. if (!$this->isdir($file)) return @ftp_delete($this->connection, $file);
  961. $files = $this->scan($file);
  962. if (!empty($files)) foreach ($files as $target) $this->delete($target);
  963. return @ftp_rmdir($this->connection, $file);
  964. }
  965. /**
  966. * put()
  967. * Copies the target file to the remote location */
  968. function put ($file,$remote) {
  969. if (@ftp_put($this->connection,$remote,$file,FTP_BINARY))
  970. return @ftp_chmod($this->connection, 0644, $remote);
  971. else $this->log[] = "Could not move the file from $file to $remote";
  972. }
  973. /**
  974. * mkdir()
  975. * Makes a new remote directory with correct permissions */
  976. function mkdir ($path) {
  977. if (@ftp_mkdir($this->connection,$path))
  978. @ftp_chmod($this->connection,0755,$path);
  979. else $this->log[] = "Could not create the directory $path";
  980. }
  981. /**
  982. * mkdir()
  983. * Gets the current directory */
  984. function pwd () {
  985. return ftp_pwd($this->connection);
  986. }
  987. /**
  988. * scan()
  989. * Gets a list of files in a directory/current directory */
  990. function scan ($path=false) {
  991. if (!$path) $path = $this->pwd();
  992. return @ftp_nlist($this->connection,$path);
  993. }
  994. /**
  995. * isdir()
  996. * Determines if the file is a directory or a file */
  997. function isdir ($file=false) {
  998. if (!$file) $file = $this->pwd();
  999. if (@ftp_size($this->connection, $file) == '-1')
  1000. return true; // Directory
  1001. else return false; // File
  1002. }
  1003. /**
  1004. * remappath()
  1005. * Remap a given path to the root path of the FTP server
  1006. * to take into account root jails common in FTP setups */
  1007. function remappath ($path) {
  1008. $files = $this->scan();
  1009. foreach ($files as $file) {
  1010. $filepath = trailingslashit($this->pwd()).basename($file);
  1011. if (!$this->isdir($filepath)) continue;
  1012. $index = strrpos($path,$filepath);
  1013. if ($index !== false) {
  1014. $this->remapped = true;
  1015. return substr($path,$index);
  1016. }
  1017. }
  1018. // No remapping needed
  1019. return $path;
  1020. }
  1021. }
  1022. if (function_exists('date_default_timezone_set'))
  1023. date_default_timezone_set(get_option('timezone_string'));
  1024. shopp_prereqs(); // Run by default at include
  1025. ?>