319 * @return string Formatted string |
319 * @return string Formatted string |
320 */ |
320 */ |
321 |
321 |
322 function enano_date($string, $timestamp = false) |
322 function enano_date($string, $timestamp = false) |
323 { |
323 { |
324 if ( !is_int($timestamp) && !is_double($timestamp) && strval(intval($timestamp)) !== $timestamp ) |
324 if ( !is_int($timestamp) && !is_double($timestamp) && strval(intval($timestamp)) !== $timestamp ) |
325 $timestamp = time(); |
325 $timestamp = time(); |
326 |
326 |
327 if ( is_int($string) ) |
327 if ( is_int($string) ) |
328 { |
328 { |
329 global $session, $lang; |
329 global $session, $lang; |
330 $date_fmt = is_object($session) ? $session->date_format : DATE_4; |
330 $date_fmt = is_object($session) ? $session->date_format : DATE_4; |
331 $time_fmt = is_object($session) ? $session->time_format : TIME_24_NS; |
331 $time_fmt = is_object($session) ? $session->time_format : TIME_24_NS; |
332 |
332 |
333 // within a week? use a relative date |
333 // within a week? use a relative date |
334 if ( $timestamp + ( 86400 * 7 ) >= time() && $string & ED_DATE && is_object($lang) && is_object($session) && !($string & ED_DATE_FULL) ) |
334 if ( $timestamp + ( 86400 * 7 ) >= time() && $string & ED_DATE && is_object($lang) && is_object($session) && !($string & ED_DATE_FULL) ) |
335 { |
335 { |
336 $relative_date = get_relative_date($timestamp); |
336 $relative_date = get_relative_date($timestamp); |
337 if ( $string === ED_DATE ) |
337 if ( $string === ED_DATE ) |
338 // why do more work if we're done? |
338 // why do more work if we're done? |
339 return $relative_date; |
339 return $relative_date; |
340 } |
340 } |
341 |
341 |
342 $flags = $string; |
342 $flags = $string; |
343 $string = array(); |
343 $string = array(); |
344 if ( $flags & ED_DATE && !isset($relative_date) ) |
344 if ( $flags & ED_DATE && !isset($relative_date) ) |
345 $string[] = $date_fmt; |
345 $string[] = $date_fmt; |
346 if ( $flags & ED_TIME ) |
346 if ( $flags & ED_TIME ) |
347 $string[] = $time_fmt; |
347 $string[] = $time_fmt; |
348 |
348 |
349 $string = implode(' ', $string); |
349 $string = implode(' ', $string); |
350 } |
350 } |
351 |
351 |
352 // perform timestamp offset |
352 // perform timestamp offset |
353 global $timezone; |
353 global $timezone; |
354 // it's gonna be in minutes, so multiply by 60 to offset the unix timestamp |
354 // it's gonna be in minutes, so multiply by 60 to offset the unix timestamp |
355 $timestamp = $timestamp + ( $timezone * 60 ); |
355 $timestamp = $timestamp + ( $timezone * 60 ); |
356 |
356 |
357 // are we in DST? |
357 // are we in DST? |
358 global $dst_params; |
358 global $dst_params; |
359 $dst_offset = 0; |
359 $dst_offset = 0; |
360 if ( check_timestamp_dst($timestamp, $dst_params[0], $dst_params[1], $dst_params[2], $dst_params[3]) ) |
360 if ( check_timestamp_dst($timestamp, $dst_params[0], $dst_params[1], $dst_params[2], $dst_params[3]) ) |
361 { |
361 { |
362 // offset for DST |
362 // offset for DST |
363 $timestamp += ( $dst_params[4] * 60 ); |
363 $timestamp += ( $dst_params[4] * 60 ); |
364 $dst_offset = $dst_params[4]; |
364 $dst_offset = $dst_params[4]; |
365 } |
365 } |
366 |
366 |
367 // Does this date string include a timezone? If so, gmdate() will report UTC, which is wrong |
367 // Does this date string include a timezone? If so, gmdate() will report UTC, which is wrong |
368 // FIXME This is kind of a halfass replacement... |
368 // FIXME This is kind of a halfass replacement... |
369 foreach ( array('e', 'T', 'O', 'P') as $char ) |
369 foreach ( array('e', 'T', 'O', 'P') as $char ) |
370 { |
370 { |
371 if ( ($pos = strpos($string, $char)) !== false ) |
371 if ( ($pos = strpos($string, $char)) !== false ) |
372 { |
372 { |
373 if ( $string{ $pos - 1 } != '\\' ) |
373 if ( $string{ $pos - 1 } != '\\' ) |
374 { |
374 { |
375 // add in our own timezone string |
375 // add in our own timezone string |
376 // FIXME: l10n? (do we need to? does anyone really not know what "GMT" means? even uglier escaping?) |
376 // FIXME: l10n? (do we need to? does anyone really not know what "GMT" means? even uglier escaping?) |
377 $tzi = '\\G\\M\\T'; |
377 $tzi = '\\G\\M\\T'; |
378 $tzo = $timezone + $dst_offset; |
378 $tzo = $timezone + $dst_offset; |
379 $sign = $tzo > 0 ? '+' : '-'; |
379 $sign = $tzo > 0 ? '+' : '-'; |
380 $tzi .= $sign . (intval(abs($tzo / 60))); |
380 $tzi .= $sign . (intval(abs($tzo / 60))); |
381 if ( $tzo % 60 ) |
381 if ( $tzo % 60 ) |
382 $tzi .= sprintf(":%02d", abs($tzo) % 60); |
382 $tzi .= sprintf(":%02d", abs($tzo) % 60); |
383 |
383 |
384 $string = substr($string, 0, $pos) . $tzi . substr($string, $pos + 1); |
384 $string = substr($string, 0, $pos) . $tzi . substr($string, $pos + 1); |
385 } |
385 } |
386 } |
386 } |
387 } |
387 } |
388 |
388 |
389 // Let PHP do the work for us =) |
389 // Let PHP do the work for us =) |
390 $result = gmdate($string, $timestamp); |
390 $result = gmdate($string, $timestamp); |
391 if ( isset($relative_date) ) |
391 if ( isset($relative_date) ) |
392 { |
392 { |
393 $result = "$relative_date, $result"; |
393 $result = "$relative_date, $result"; |
394 } |
394 } |
395 return $result; |
395 return $result; |
396 } |
396 } |
397 |
397 |
398 /** |
398 /** |
399 * Get a relative date ("Today"/"Yesterday"/"N days ago") |
399 * Get a relative date ("Today"/"Yesterday"/"N days ago") |
400 * @param int Timestamp |
400 * @param int Timestamp |
401 * @return string |
401 * @return string |
402 */ |
402 */ |
403 |
403 |
404 function get_relative_date($time) |
404 function get_relative_date($time) |
405 { |
405 { |
406 global $lang, $session; |
406 global $lang, $session; |
407 // Our formatting string to pass to enano_date() |
407 // Our formatting string to pass to enano_date() |
408 // This should not include minute/second info, only today's date in whatever format suits your fancy |
408 // This should not include minute/second info, only today's date in whatever format suits your fancy |
409 $formatstring = $session->date_format; |
409 $formatstring = $session->date_format; |
410 // Today's date |
410 // Today's date |
411 $today = enano_date($formatstring); |
411 $today = enano_date($formatstring); |
412 // Yesterday's date |
412 // Yesterday's date |
413 $yesterday = enano_date($formatstring, (time() - (24*60*60))); |
413 $yesterday = enano_date($formatstring, (time() - (24*60*60))); |
414 // Date on the input |
414 // Date on the input |
415 $then = enano_date($formatstring, $time); |
415 $then = enano_date($formatstring, $time); |
416 // "X days ago" logic |
416 // "X days ago" logic |
417 for ( $i = 2; $i <= 6; $i++ ) |
417 for ( $i = 2; $i <= 6; $i++ ) |
418 { |
418 { |
419 // hours_in_day * minutes_in_hour * seconds_in_minute * num_days |
419 // hours_in_day * minutes_in_hour * seconds_in_minute * num_days |
420 $offset = 24 * 60 * 60 * $i; |
420 $offset = 24 * 60 * 60 * $i; |
421 $days_ago = enano_date($formatstring, (time() - $offset)); |
421 $days_ago = enano_date($formatstring, (time() - $offset)); |
422 // so does the input timestamp match the date from $i days ago? |
422 // so does the input timestamp match the date from $i days ago? |
423 if ( $then == $days_ago ) |
423 if ( $then == $days_ago ) |
424 { |
424 { |
425 // yes, return $i |
425 // yes, return $i |
426 return $lang->get('userfuncs_ml_date_daysago', array('days_ago' => $i)); |
426 return $lang->get('userfuncs_ml_date_daysago', array('days_ago' => $i)); |
427 } |
427 } |
428 } |
428 } |
429 // either yesterday, today, or before 6 days ago |
429 // either yesterday, today, or before 6 days ago |
430 switch($then) |
430 switch($then) |
431 { |
431 { |
432 case $today: |
432 case $today: |
433 return $lang->get('userfuncs_ml_date_today'); |
433 return $lang->get('userfuncs_ml_date_today'); |
434 case $yesterday: |
434 case $yesterday: |
435 return $lang->get('userfuncs_ml_date_yesterday'); |
435 return $lang->get('userfuncs_ml_date_yesterday'); |
436 default: |
436 default: |
437 return $then; |
437 return $then; |
438 } |
438 } |
439 // .--. |
439 // .--. |
440 // |o_o | |
440 // |o_o | |
441 // |!_/ | |
441 // |!_/ | |
442 // // \ \ |
442 // // \ \ |
443 // (| | ) |
443 // (| | ) |
444 // /'\_ _/`\ |
444 // /'\_ _/`\ |
445 // \___)=(___/ |
445 // \___)=(___/ |
446 return 'Linux rocks!'; |
446 return 'Linux rocks!'; |
447 } |
447 } |
448 |
448 |
449 /** |
449 /** |
450 * Determine if a timestamp is within DST. |
450 * Determine if a timestamp is within DST. |
451 * @param int Timestamp |
451 * @param int Timestamp |
577 * @param string $timeout Timeout, in seconds, to delay the redirect. Defaults to 3. If 0, sends a 307 Temporary Redirect. |
577 * @param string $timeout Timeout, in seconds, to delay the redirect. Defaults to 3. If 0, sends a 307 Temporary Redirect. |
578 */ |
578 */ |
579 |
579 |
580 function redirect($url, $title = 'etc_redirect_title', $message = 'etc_redirect_body', $timeout = 3) |
580 function redirect($url, $title = 'etc_redirect_title', $message = 'etc_redirect_body', $timeout = 3) |
581 { |
581 { |
582 global $db, $session, $paths, $template, $plugins; // Common objects |
582 global $db, $session, $paths, $template, $plugins; // Common objects |
583 global $lang; |
583 global $lang; |
584 |
584 |
585 // POST check added in 1.1.x because Firefox 3.0 asks us if we want to "resend the form |
585 // POST check added in 1.1.x because Firefox 3.0 asks us if we want to "resend the form |
586 // data to the new location", which can be confusing for some users. |
586 // data to the new location", which can be confusing for some users. |
587 $is_firefox_3 = ( strstr(@$_SERVER['HTTP_USER_AGENT'], 'Firefox/3.') ) ? true : false; |
587 $is_firefox_3 = ( strstr(@$_SERVER['HTTP_USER_AGENT'], 'Firefox/3.') ) ? true : false; |
588 if ( $timeout == 0 && ( empty($_POST) || !$is_firefox_3 ) ) |
588 if ( $timeout == 0 && ( empty($_POST) || !$is_firefox_3 ) ) |
589 { |
589 { |
590 header('Location: ' . $url); |
590 header('Location: ' . $url); |
591 header('Content-length: 0'); |
591 header('Content-length: 0'); |
592 header('HTTP/1.1 307 Temporary Redirect'); |
592 header('HTTP/1.1 307 Temporary Redirect'); |
593 |
593 |
594 // with 3xx codes HTTP clients expect a response of 0 bytes, so just die here |
594 // with 3xx codes HTTP clients expect a response of 0 bytes, so just die here |
595 exit(); |
595 exit(); |
596 } |
596 } |
597 |
597 |
598 if ( !is_object($template) ) |
598 if ( !is_object($template) ) |
599 { |
599 { |
600 $template = new template_nodb(); |
600 $template = new template_nodb(); |
601 $template->load_theme('oxygen', 'bleu', false); |
601 $template->load_theme('oxygen', 'bleu', false); |
602 $template->assign_vars(array( |
602 $template->assign_vars(array( |
603 'SITE_NAME' => 'Enano', |
603 'SITE_NAME' => 'Enano', |
604 'SITE_DESC' => 'This site is experiencing a critical error and cannot load.', |
604 'SITE_DESC' => 'This site is experiencing a critical error and cannot load.', |
605 'COPYRIGHT' => 'Powered by Enano CMS - © 2006-2008 Dan Fuhry. This program is Free Software; see the <a href="' . scriptPath . '/install.php?mode=license">GPL file</a> included with this package for details.', |
605 'COPYRIGHT' => 'Powered by Enano CMS - © 2006-2008 Dan Fuhry. This program is Free Software; see the <a href="' . scriptPath . '/install.php?mode=license">GPL file</a> included with this package for details.', |
606 'PAGE_NAME' => htmlspecialchars($title) |
606 'PAGE_NAME' => htmlspecialchars($title) |
607 )); |
607 )); |
608 } |
608 } |
609 |
609 |
610 $template->add_header('<meta http-equiv="refresh" content="' . $timeout . '; url=' . str_replace('"', '\\"', $url) . '" />'); |
610 $template->add_header('<meta http-equiv="refresh" content="' . $timeout . '; url=' . str_replace('"', '\\"', $url) . '" />'); |
611 $template->add_header('<script type="text/javascript"> |
611 $template->add_header('<script type="text/javascript"> |
612 function __r() { |
612 function __r() { |
613 // FUNCTION AUTOMATICALLY GENERATED |
613 // FUNCTION AUTOMATICALLY GENERATED |
614 window.location="' . str_replace('"', '\\"', $url) . '"; |
614 window.location="' . str_replace('"', '\\"', $url) . '"; |
615 } |
615 } |
616 setTimeout(\'__r();\', ' . $timeout . '000); |
616 setTimeout(\'__r();\', ' . $timeout . '000); |
617 </script> |
617 </script> |
618 '); |
618 '); |
619 |
619 |
620 if ( get_class($template) == 'template_nodb' ) |
620 if ( get_class($template) == 'template_nodb' ) |
621 $template->init_vars(); |
621 $template->init_vars(); |
622 |
622 |
623 $template->assign_vars(array('PAGE_NAME' => $title)); |
623 $template->assign_vars(array('PAGE_NAME' => $title)); |
624 $template->header(true); |
624 $template->header(true); |
625 echo '<p>' . $message . '</p>'; |
625 echo '<p>' . $message . '</p>'; |
626 $subst = array( |
626 $subst = array( |
627 'timeout' => $timeout, |
627 'timeout' => $timeout, |
628 'redirect_url' => str_replace('"', '\\"', $url) |
628 'redirect_url' => str_replace('"', '\\"', $url) |
629 ); |
629 ); |
630 echo '<p>' . $lang->get('etc_redirect_timeout', $subst) . '</p>'; |
630 echo '<p>' . $lang->get('etc_redirect_timeout', $subst) . '</p>'; |
631 $template->footer(true); |
631 $template->footer(true); |
632 |
632 |
633 $db->close(); |
633 $db->close(); |
634 exit(0); |
634 exit(0); |
635 |
635 |
636 } |
636 } |
637 |
637 |
638 /** |
638 /** |
639 * Generates a confirmation form if a CSRF check fails. Will terminate execution. |
639 * Generates a confirmation form if a CSRF check fails. Will terminate execution. |
640 */ |
640 */ |
641 |
641 |
642 function csrf_request_confirm() |
642 function csrf_request_confirm() |
643 { |
643 { |
644 global $db, $session, $paths, $template, $plugins; // Common objects |
644 global $db, $session, $paths, $template, $plugins; // Common objects |
645 global $lang, $output; |
645 global $lang, $output; |
646 |
646 |
647 // If the token was overridden with the correct one, the user confirmed the action using this form. Continue exec. |
647 // If the token was overridden with the correct one, the user confirmed the action using this form. Continue exec. |
648 if ( isset($_POST['cstok']) || isset($_GET['cstok']) ) |
648 if ( isset($_POST['cstok']) || isset($_GET['cstok']) ) |
649 { |
649 { |
650 // using the if() check makes sure that the token isn't in a cookie, since $_REQUEST includes $_COOKIE. |
650 // using the if() check makes sure that the token isn't in a cookie, since $_REQUEST includes $_COOKIE. |
651 $token_check =& $_REQUEST['cstok']; |
651 $token_check =& $_REQUEST['cstok']; |
652 if ( $token_check === $session->csrf_token ) |
652 if ( $token_check === $session->csrf_token ) |
653 { |
653 { |
654 // overridden token matches, continue exec |
654 // overridden token matches, continue exec |
655 return true; |
655 return true; |
656 } |
656 } |
657 } |
657 } |
658 |
658 |
659 @ob_end_clean(); |
659 @ob_end_clean(); |
660 |
660 |
661 $output->set_title($lang->get('user_csrf_confirm_title')); |
661 $output->set_title($lang->get('user_csrf_confirm_title')); |
662 $output->header(); |
662 $output->header(); |
663 |
663 |
664 // initial info |
664 // initial info |
665 echo '<p>' . $lang->get('user_csrf_confirm_body') . '</p>'; |
665 echo '<p>' . $lang->get('user_csrf_confirm_body') . '</p>'; |
666 |
666 |
667 // start form |
667 // start form |
668 $form_method = ( empty($_POST) ) ? 'get' : 'post'; |
668 $form_method = ( empty($_POST) ) ? 'get' : 'post'; |
669 echo '<form action="' . htmlspecialchars($_SERVER['REQUEST_URI']) . '" method="' . $form_method . '" enctype="multipart/form-data">'; |
669 echo '<form action="' . htmlspecialchars($_SERVER['REQUEST_URI']) . '" method="' . $form_method . '" enctype="multipart/form-data">'; |
670 |
670 |
671 echo '<fieldset enano:expand="closed">'; |
671 echo '<fieldset enano:expand="closed">'; |
672 echo '<legend>' . $lang->get('user_csrf_confirm_btn_viewrequest') . '</legend><div>'; |
672 echo '<legend>' . $lang->get('user_csrf_confirm_btn_viewrequest') . '</legend><div>'; |
673 |
673 |
674 if ( empty($_POST) ) |
674 if ( empty($_POST) ) |
675 { |
675 { |
676 // GET request |
676 // GET request |
677 echo csrf_confirm_get_recursive(); |
677 echo csrf_confirm_get_recursive(); |
678 } |
678 } |
679 else |
679 else |
680 { |
680 { |
681 // POST request |
681 // POST request |
682 echo csrf_confirm_post_recursive(); |
682 echo csrf_confirm_post_recursive(); |
683 } |
683 } |
684 echo '</div></fieldset>'; |
684 echo '</div></fieldset>'; |
685 // insert the right CSRF token |
685 // insert the right CSRF token |
686 echo '<input type="hidden" name="cstok" value="' . $session->csrf_token . '" />'; |
686 echo '<input type="hidden" name="cstok" value="' . $session->csrf_token . '" />'; |
687 echo '<p><input type="submit" value="' . $lang->get('user_csrf_confirm_btn_continue') . '" /></p>'; |
687 echo '<p><input type="submit" value="' . $lang->get('user_csrf_confirm_btn_continue') . '" /></p>'; |
688 echo '</form><script type="text/javascript">addOnloadHook(function(){load_component(\'expander\');});</script>'; |
688 echo '</form><script type="text/javascript">addOnloadHook(function(){load_component(\'expander\');});</script>'; |
689 |
689 |
690 $output->footer(); |
690 $output->footer(); |
691 |
691 |
692 exit; |
692 exit; |
693 } |
693 } |
694 |
694 |
695 function csrf_confirm_get_recursive($_inner = false, $pfx = false, $data = false) |
695 function csrf_confirm_get_recursive($_inner = false, $pfx = false, $data = false) |
696 { |
696 { |
697 // make posted arrays work right |
697 // make posted arrays work right |
698 if ( !$data ) |
698 if ( !$data ) |
699 ( $_inner == 'post' ) ? $data =& $_POST : $data =& $_GET; |
699 ( $_inner == 'post' ) ? $data =& $_POST : $data =& $_GET; |
700 foreach ( $data as $key => $value ) |
700 foreach ( $data as $key => $value ) |
701 { |
701 { |
702 $pfx_this = ( empty($pfx) ) ? $key : "{$pfx}[{$key}]"; |
702 $pfx_this = ( empty($pfx) ) ? $key : "{$pfx}[{$key}]"; |
703 if ( is_array($value) ) |
703 if ( is_array($value) ) |
704 { |
704 { |
705 csrf_confirm_get_recursive(true, $pfx_this, $value); |
705 csrf_confirm_get_recursive(true, $pfx_this, $value); |
706 } |
706 } |
707 else if ( empty($value) ) |
707 else if ( empty($value) ) |
708 { |
708 { |
709 echo htmlspecialchars($pfx_this . " = <nil>") . "<br />\n"; |
709 echo htmlspecialchars($pfx_this . " = <nil>") . "<br />\n"; |
710 echo '<input type="hidden" name="' . htmlspecialchars($pfx_this) . '" value="" />'; |
710 echo '<input type="hidden" name="' . htmlspecialchars($pfx_this) . '" value="" />'; |
711 } |
711 } |
712 else |
712 else |
713 { |
713 { |
714 echo htmlspecialchars($pfx_this . " = " . $value) . "<br />\n"; |
714 echo htmlspecialchars($pfx_this . " = " . $value) . "<br />\n"; |
715 echo '<input type="hidden" name="' . htmlspecialchars($pfx_this) . '" value="' . htmlspecialchars($value) . '" />'; |
715 echo '<input type="hidden" name="' . htmlspecialchars($pfx_this) . '" value="' . htmlspecialchars($value) . '" />'; |
716 } |
716 } |
717 } |
717 } |
718 } |
718 } |
719 |
719 |
720 function csrf_confirm_post_recursive() |
720 function csrf_confirm_post_recursive() |
721 { |
721 { |
722 csrf_confirm_get_recursive('post'); |
722 csrf_confirm_get_recursive('post'); |
723 } |
723 } |
724 |
724 |
725 // Removed wikiFormat() from here, replaced with RenderMan::render |
725 // Removed wikiFormat() from here, replaced with RenderMan::render |
726 |
726 |
727 /** |
727 /** |
757 * @param int Revision ID |
757 * @param int Revision ID |
758 */ |
758 */ |
759 |
759 |
760 function namespace_factory($page_id, $namespace, $revision_id = 0) |
760 function namespace_factory($page_id, $namespace, $revision_id = 0) |
761 { |
761 { |
762 global $db, $session, $paths, $template, $plugins; // Common objects |
762 global $db, $session, $paths, $template, $plugins; // Common objects |
763 |
763 |
764 static $objcache = array(); |
764 static $objcache = array(); |
765 $pathskey = $paths->get_pathskey($page_id, $namespace) . ":$revision_id"; |
765 $pathskey = $paths->get_pathskey($page_id, $namespace) . ":$revision_id"; |
766 if ( isset($objcache[$pathskey]) ) |
766 if ( isset($objcache[$pathskey]) ) |
767 return $objcache[$pathskey]; |
767 return $objcache[$pathskey]; |
768 |
768 |
769 if ( !class_exists("Namespace_$namespace") ) |
769 if ( !class_exists("Namespace_$namespace") ) |
770 { |
770 { |
771 if ( file_exists(ENANO_ROOT . "/includes/namespaces/" . strtolower($namespace) . ".php") ) |
771 if ( file_exists(ENANO_ROOT . "/includes/namespaces/" . strtolower($namespace) . ".php") ) |
772 { |
772 { |
773 require(ENANO_ROOT . "/includes/namespaces/" . strtolower($namespace) . ".php"); |
773 require(ENANO_ROOT . "/includes/namespaces/" . strtolower($namespace) . ".php"); |
774 } |
774 } |
775 } |
775 } |
776 if ( class_exists("Namespace_$namespace") ) |
776 if ( class_exists("Namespace_$namespace") ) |
777 { |
777 { |
778 $class = "Namespace_$namespace"; |
778 $class = "Namespace_$namespace"; |
779 $ns = new $class($page_id, $namespace, $revision_id); |
779 $ns = new $class($page_id, $namespace, $revision_id); |
780 $objcache[$pathskey] = $ns; |
780 $objcache[$pathskey] = $ns; |
781 return $ns; |
781 return $ns; |
782 } |
782 } |
783 else |
783 else |
784 { |
784 { |
785 $ns = new Namespace_Default($page_id, $namespace, $revision_id); |
785 $ns = new Namespace_Default($page_id, $namespace, $revision_id); |
786 $objcache[$pathskey] = $ns; |
786 $objcache[$pathskey] = $ns; |
787 return $ns; |
787 return $ns; |
788 } |
788 } |
789 } |
789 } |
790 |
790 |
791 /** |
791 /** |
792 * These are some old functions that were used with the Midget codebase. They are deprecated and should not be used any more. |
792 * These are some old functions that were used with the Midget codebase. They are deprecated and should not be used any more. |
793 */ |
793 */ |
794 |
794 |
795 function arrayItemUp($arr, $keyname) { |
795 function arrayItemUp($arr, $keyname) { |
796 $keylist = array_keys($arr); |
796 $keylist = array_keys($arr); |
797 $keyflop = array_flip($keylist); |
797 $keyflop = array_flip($keylist); |
798 $idx = $keyflop[$keyname]; |
798 $idx = $keyflop[$keyname]; |
799 $idxm = $idx - 1; |
799 $idxm = $idx - 1; |
800 $temp = $arr[$keylist[$idxm]]; |
800 $temp = $arr[$keylist[$idxm]]; |
801 if($arr[$keylist[0]] == $arr[$keyname]) return $arr; |
801 if($arr[$keylist[0]] == $arr[$keyname]) return $arr; |
802 $arr[$keylist[$idxm]] = $arr[$keylist[$idx]]; |
802 $arr[$keylist[$idxm]] = $arr[$keylist[$idx]]; |
803 $arr[$keylist[$idx]] = $temp; |
803 $arr[$keylist[$idx]] = $temp; |
804 return $arr; |
804 return $arr; |
805 } |
805 } |
806 |
806 |
807 function arrayItemDown($arr, $keyname) { |
807 function arrayItemDown($arr, $keyname) { |
808 $keylist = array_keys($arr); |
808 $keylist = array_keys($arr); |
809 $keyflop = array_flip($keylist); |
809 $keyflop = array_flip($keylist); |
810 $idx = $keyflop[$keyname]; |
810 $idx = $keyflop[$keyname]; |
811 $idxm = $idx + 1; |
811 $idxm = $idx + 1; |
812 $temp = $arr[$keylist[$idxm]]; |
812 $temp = $arr[$keylist[$idxm]]; |
813 $sz = sizeof($arr); $sz--; |
813 $sz = sizeof($arr); $sz--; |
814 if($arr[$keylist[$sz]] == $arr[$keyname]) return $arr; |
814 if($arr[$keylist[$sz]] == $arr[$keyname]) return $arr; |
815 $arr[$keylist[$idxm]] = $arr[$keylist[$idx]]; |
815 $arr[$keylist[$idxm]] = $arr[$keylist[$idx]]; |
816 $arr[$keylist[$idx]] = $temp; |
816 $arr[$keylist[$idx]] = $temp; |
817 return $arr; |
817 return $arr; |
818 } |
818 } |
819 |
819 |
820 function arrayItemTop($arr, $keyname) { |
820 function arrayItemTop($arr, $keyname) { |
821 $keylist = array_keys($arr); |
821 $keylist = array_keys($arr); |
822 $keyflop = array_flip($keylist); |
822 $keyflop = array_flip($keylist); |
823 $idx = $keyflop[$keyname]; |
823 $idx = $keyflop[$keyname]; |
824 while( $orig != $arr[$keylist[0]] ) { |
824 while( $orig != $arr[$keylist[0]] ) { |
825 // echo 'Keyname: '.$keylist[$idx] . '<br />'; flush(); ob_flush(); // Debugger |
825 // echo 'Keyname: '.$keylist[$idx] . '<br />'; flush(); ob_flush(); // Debugger |
826 if($idx < 0) return $arr; |
826 if($idx < 0) return $arr; |
827 if($keylist[$idx] == '' || $keylist[$idx] < 0 || !$keylist[$idx]) { |
827 if($keylist[$idx] == '' || $keylist[$idx] < 0 || !$keylist[$idx]) { |
828 return $arr; |
828 return $arr; |
829 } |
829 } |
830 $arr = arrayItemUp($arr, $keylist[$idx]); |
830 $arr = arrayItemUp($arr, $keylist[$idx]); |
831 $idx--; |
831 $idx--; |
832 } |
832 } |
833 return $arr; |
833 return $arr; |
834 } |
834 } |
835 |
835 |
836 function arrayItemBottom($arr, $keyname) { |
836 function arrayItemBottom($arr, $keyname) { |
837 $b = $arr[$keyname]; |
837 $b = $arr[$keyname]; |
838 unset($arr[$keyname]); |
838 unset($arr[$keyname]); |
839 $arr[$keyname] = $b; |
839 $arr[$keyname] = $b; |
840 unset($b); |
840 unset($b); |
841 return $arr; |
841 return $arr; |
842 } |
842 } |
843 |
843 |
844 /** |
844 /** |
845 * Implementation of array_merge() that preserves key names. $arr2 takes precedence over $arr1. |
845 * Implementation of array_merge() that preserves key names. $arr2 takes precedence over $arr1. |
846 * @param array $arr1 |
846 * @param array $arr1 |
934 * @param bool Added in 1.1.3. If true, only the error is output. Defaults to false. |
934 * @param bool Added in 1.1.3. If true, only the error is output. Defaults to false. |
935 */ |
935 */ |
936 |
936 |
937 function die_semicritical($t, $p, $no_wrapper = false) |
937 function die_semicritical($t, $p, $no_wrapper = false) |
938 { |
938 { |
939 global $db, $session, $paths, $template, $plugins; // Common objects |
939 global $db, $session, $paths, $template, $plugins; // Common objects |
940 $db->close(); |
940 $db->close(); |
941 |
941 |
942 if ( @ob_get_status() ) |
942 if ( @ob_get_status() ) |
943 ob_end_clean(); |
943 ob_end_clean(); |
944 |
944 |
945 // If the config hasn't been fetched yet, call grinding_halt. |
945 // If the config hasn't been fetched yet, call grinding_halt. |
946 if ( !defined('ENANO_CONFIG_FETCHED') ) |
946 if ( !defined('ENANO_CONFIG_FETCHED') ) |
947 { |
947 { |
948 grinding_halt($t, $p); |
948 grinding_halt($t, $p); |
949 } |
949 } |
950 |
950 |
951 // also do grinding_halt() if we're in CLI mode |
951 // also do grinding_halt() if we're in CLI mode |
952 if ( defined('ENANO_CLI') ) |
952 if ( defined('ENANO_CLI') ) |
953 { |
953 { |
954 grinding_halt($t, $p); |
954 grinding_halt($t, $p); |
955 } |
955 } |
956 |
956 |
957 if ( $no_wrapper ) |
957 if ( $no_wrapper ) |
958 { |
958 { |
959 echo '<h2>' . htmlspecialchars($t) . '</h2>'; |
959 echo '<h2>' . htmlspecialchars($t) . '</h2>'; |
960 echo "<p>$p</p>"; |
960 echo "<p>$p</p>"; |
961 exit; |
961 exit; |
962 } |
962 } |
963 |
963 |
964 $output = new Output_Safe(); |
964 $output = new Output_Safe(); |
965 $output->set_title($t); |
965 $output->set_title($t); |
966 $output->header(); |
966 $output->header(); |
967 echo $p; |
967 echo $p; |
968 $output->footer(); |
968 $output->footer(); |
969 |
969 |
970 exit; |
970 exit; |
971 } |
971 } |
972 |
972 |
973 /** |
973 /** |
974 * Halts Enano execution with a message. This doesn't have to be an error message, it's sometimes used to indicate success at an operation. |
974 * Halts Enano execution with a message. This doesn't have to be an error message, it's sometimes used to indicate success at an operation. |
975 * @param string The title of the message |
975 * @param string The title of the message |
976 * @param string The body of the message, this can be HTML, and should be separated into paragraphs using the <p> tag |
976 * @param string The body of the message, this can be HTML, and should be separated into paragraphs using the <p> tag |
977 */ |
977 */ |
978 |
978 |
979 function die_friendly($t, $p) |
979 function die_friendly($t, $p) |
980 { |
980 { |
981 global $db, $session, $paths, $template, $plugins; // Common objects |
981 global $db, $session, $paths, $template, $plugins; // Common objects |
982 |
982 |
983 if ( @ob_get_status() ) |
983 if ( @ob_get_status() ) |
984 ob_end_clean(); |
984 ob_end_clean(); |
985 |
985 |
986 global $output; |
986 global $output; |
987 |
987 |
988 $output->set_title($t); |
988 $output->set_title($t); |
989 $template->header(); |
989 $template->header(); |
990 echo $p; |
990 echo $p; |
991 $template->footer(); |
991 $template->footer(); |
992 $db->close(); |
992 $db->close(); |
993 |
993 |
994 exit; |
994 exit; |
995 } |
995 } |
996 |
996 |
997 /** |
997 /** |
998 * Immediately brings the site to a halt with an error message, and focuses on immediately closing the database connection and shutting down Enano in the event that an attack may happen. This should only be used very early on to indicate very severe errors, or if the site may be under attack (like if the DBAL detects a malicious query). In the vast majority of cases, die_semicritical() is more appropriate. |
998 * Immediately brings the site to a halt with an error message, and focuses on immediately closing the database connection and shutting down Enano in the event that an attack may happen. This should only be used very early on to indicate very severe errors, or if the site may be under attack (like if the DBAL detects a malicious query). In the vast majority of cases, die_semicritical() is more appropriate. |
999 * @param string The title of the error message |
999 * @param string The title of the error message |
1000 * @param string The body of the message, this can be HTML, and should be separated into paragraphs using the <p> tag |
1000 * @param string The body of the message, this can be HTML, and should be separated into paragraphs using the <p> tag |
1001 */ |
1001 */ |
1002 |
1002 |
1003 function grinding_halt($t, $p) |
1003 function grinding_halt($t, $p) |
1004 { |
1004 { |
1005 global $db, $session, $paths, $template, $plugins; // Common objects |
1005 global $db, $session, $paths, $template, $plugins; // Common objects |
1006 |
1006 |
1007 if ( !defined('scriptPath') ) |
1007 if ( !defined('scriptPath') ) |
1008 require( ENANO_ROOT . '/config.php' ); |
1008 require( ENANO_ROOT . '/config.php' ); |
1009 |
1009 |
1010 if ( is_object($db) ) |
1010 if ( is_object($db) ) |
1011 $db->close(); |
1011 $db->close(); |
1012 |
1012 |
1013 if ( @ob_get_status() ) |
1013 if ( @ob_get_status() ) |
1014 ob_end_clean(); |
1014 ob_end_clean(); |
1015 |
1015 |
1016 if ( defined('ENANO_CLI') ) |
1016 if ( defined('ENANO_CLI') ) |
1017 { |
1017 { |
1018 // set console color |
1018 // set console color |
1019 echo "\x1B[31;1m"; |
1019 echo "\x1B[31;1m"; |
1020 // error title |
1020 // error title |
1021 echo "Critical error in Enano runtime: "; |
1021 echo "Critical error in Enano runtime: "; |
1022 // unbold |
1022 // unbold |
1023 echo "$t\n"; |
1023 echo "$t\n"; |
1024 // bold |
1024 // bold |
1025 echo "\x1B[37;1m"; |
1025 echo "\x1B[37;1m"; |
1026 echo "Error: "; |
1026 echo "Error: "; |
1027 // unbold |
1027 // unbold |
1028 echo "\x1B[0m"; |
1028 echo "\x1B[0m"; |
1029 echo "$p\n"; |
1029 echo "$p\n"; |
1030 exit(1); |
1030 exit(1); |
1031 } |
1031 } |
1032 $theme = ( defined('ENANO_CONFIG_FETCHED') ) ? getConfig('theme_default') : 'oxygen'; |
1032 $theme = ( defined('ENANO_CONFIG_FETCHED') ) ? getConfig('theme_default') : 'oxygen'; |
1033 $style = ( defined('ENANO_CONFIG_FETCHED') ) ? '__foo__' : 'bleu'; |
1033 $style = ( defined('ENANO_CONFIG_FETCHED') ) ? '__foo__' : 'bleu'; |
1034 |
1034 |
1035 $tpl = new template_nodb(); |
1035 $tpl = new template_nodb(); |
1036 $tpl->load_theme($theme, $style); |
1036 $tpl->load_theme($theme, $style); |
1037 $tpl->tpl_strings['SITE_NAME'] = 'Critical error'; |
1037 $tpl->tpl_strings['SITE_NAME'] = 'Critical error'; |
1038 $tpl->tpl_strings['SITE_DESC'] = 'This website is experiencing a serious error and cannot load.'; |
1038 $tpl->tpl_strings['SITE_DESC'] = 'This website is experiencing a serious error and cannot load.'; |
1039 $tpl->tpl_strings['COPYRIGHT'] = 'Unable to retrieve copyright information'; |
1039 $tpl->tpl_strings['COPYRIGHT'] = 'Unable to retrieve copyright information'; |
1040 $tpl->tpl_strings['PAGE_NAME'] = $t; |
1040 $tpl->tpl_strings['PAGE_NAME'] = $t; |
1041 $tpl->header(); |
1041 $tpl->header(); |
1042 echo $p; |
1042 echo $p; |
1043 $tpl->footer(); |
1043 $tpl->footer(); |
1044 |
1044 |
1045 exit; |
1045 exit; |
1046 } |
1046 } |
1047 |
1047 |
1048 /** |
1048 /** |
1049 * Prints out the categorization box found on most regular pages. Doesn't take or return anything, but assumes that the page information is already set in $paths. |
1049 * Prints out the categorization box found on most regular pages. Doesn't take or return anything, but assumes that the page information is already set in $paths. |
1050 */ |
1050 */ |
1051 |
1051 |
1052 function show_category_info() |
1052 function show_category_info() |
1053 { |
1053 { |
1054 throw new Exception('show_category_info() is deprecated. Use Namespace_*::display_categories().'); |
1054 throw new Exception('show_category_info() is deprecated. Use Namespace_*::display_categories().'); |
1055 } |
1055 } |
1056 |
1056 |
1057 /** |
1057 /** |
1058 * Prints out the file information box seen on File: pages. Doesn't take or return anything, but assumes that the page information is already set in $paths, and expects $paths->namespace to be File. |
1058 * Prints out the file information box seen on File: pages. Doesn't take or return anything, but assumes that the page information is already set in $paths, and expects $paths->namespace to be File. |
1059 */ |
1059 */ |
1060 |
1060 |
1061 function show_file_info($page = false) |
1061 function show_file_info($page = false) |
1062 { |
1062 { |
1063 throw new Exception('show_file_info() is deprecated. Use Namespace_File::show_info().'); |
1063 throw new Exception('show_file_info() is deprecated. Use Namespace_File::show_info().'); |
1064 } |
1064 } |
1065 |
1065 |
1066 /** |
1066 /** |
1067 * Shows header information on the current page. Currently this is only the delete-vote feature. Doesn't take or return anything, but assumes that the page information is already set in $paths. |
1067 * Shows header information on the current page. Currently this is only the delete-vote feature. Doesn't take or return anything, but assumes that the page information is already set in $paths. |
1068 */ |
1068 */ |
1069 |
1069 |
1070 function display_page_headers() |
1070 function display_page_headers() |
1071 { |
1071 { |
1072 // Deprecated. |
1072 // Deprecated. |
1073 } |
1073 } |
1074 |
1074 |
1075 /** |
1075 /** |
1076 * Displays page footer information including file and category info. This also has the send_page_footers hook. Doesn't take or return anything, but assumes that the page information is already set in $paths. |
1076 * Displays page footer information including file and category info. This also has the send_page_footers hook. Doesn't take or return anything, but assumes that the page information is already set in $paths. |
1077 */ |
1077 */ |
1078 |
1078 |
1079 function display_page_footers() |
1079 function display_page_footers() |
1080 { |
1080 { |
1081 global $db, $session, $paths, $template, $plugins; // Common objects |
1081 global $db, $session, $paths, $template, $plugins; // Common objects |
1082 |
1082 |
1083 if ( isset($_GET['nofooters']) ) |
1083 if ( isset($_GET['nofooters']) ) |
1084 { |
1084 { |
1085 return; |
1085 return; |
1086 } |
1086 } |
1087 |
1087 |
1088 $code = $plugins->setHook('send_page_footers'); |
1088 $code = $plugins->setHook('send_page_footers'); |
1089 foreach ( $code as $cmd ) |
1089 foreach ( $code as $cmd ) |
1090 { |
1090 { |
1091 eval($cmd); |
1091 eval($cmd); |
1092 } |
1092 } |
1093 } |
1093 } |
1094 |
1094 |
1095 /** |
1095 /** |
1096 * Show the "this is a redirector" notice |
1096 * Show the "this is a redirector" notice |
1097 * @param string Target Page ID |
1097 * @param string Target Page ID |
1098 * @param string Target Namespace |
1098 * @param string Target Namespace |
1099 */ |
1099 */ |
1100 |
1100 |
1101 function display_redirect_notice($page_id, $namespace) |
1101 function display_redirect_notice($page_id, $namespace) |
1102 { |
1102 { |
1103 global $db, $session, $paths, $template, $plugins; // Common objects |
1103 global $db, $session, $paths, $template, $plugins; // Common objects |
1104 global $lang, $output; |
1104 global $lang, $output; |
1105 |
1105 |
1106 $url = makeUrlNS($namespace, $page_id, false, true); |
1106 $url = makeUrlNS($namespace, $page_id, false, true); |
1107 $ns = namespace_factory($page_id, $namespace); |
1107 $ns = namespace_factory($page_id, $namespace); |
1108 $page_data = $ns->get_cdata(); |
1108 $page_data = $ns->get_cdata(); |
1109 |
1109 |
1110 $title = $page_data['name']; |
1110 $title = $page_data['name']; |
1111 |
1111 |
1112 $cls = $ns->exists() ? '' : 'class="wikilink-nonexistent" '; |
1112 $cls = $ns->exists() ? '' : 'class="wikilink-nonexistent" '; |
1113 |
1113 |
1114 $a = '<a ' . $cls . 'href="' . $url . '">' . $title . '</a>'; |
1114 $a = '<a ' . $cls . 'href="' . $url . '">' . $title . '</a>'; |
1115 $redir_html = '<br /><div class="mdg-infobox"> |
1115 $redir_html = '<br /><div class="mdg-infobox"> |
1116 <table border="0" width="100%" cellspacing="0" cellpadding="0"> |
1116 <table border="0" width="100%" cellspacing="0" cellpadding="0"> |
1117 <tr> |
1117 <tr> |
1118 <td valign="top"> |
1118 <td valign="top"> |
1119 <img alt="Cute wet-floor icon" src="' . cdnPath . '/images/redirector.png" /> |
1119 <img alt="Cute wet-floor icon" src="' . cdnPath . '/images/redirector.png" /> |
1120 </td> |
1120 </td> |
1121 <td valign="top" style="padding-left: 10px;"> |
1121 <td valign="top" style="padding-left: 10px;"> |
1122 ' . $lang->get('page_msg_this_is_a_redirector', array( 'redirect_target' => $a )) . ' |
1122 ' . $lang->get('page_msg_this_is_a_redirector', array( 'redirect_target' => $a )) . ' |
1123 </td> |
1123 </td> |
1124 </tr> |
1124 </tr> |
1125 </table> |
1125 </table> |
1126 </div> |
1126 </div> |
1127 <br /> |
1127 <br /> |
1128 <hr style="margin-left: 1em; width: 200px;" />'; |
1128 <hr style="margin-left: 1em; width: 200px;" />'; |
1129 |
1129 |
1130 $output->add_after_header($redir_html); |
1130 $output->add_after_header($redir_html); |
1131 } |
1131 } |
1132 |
1132 |
1133 /** |
1133 /** |
1134 * Essentially an return code reader for a socket. Don't use this unless you're writing mail code and smtp_send_email doesn't cut it. Ported from phpBB's smtp.php. |
1134 * Essentially an return code reader for a socket. Don't use this unless you're writing mail code and smtp_send_email doesn't cut it. Ported from phpBB's smtp.php. |
1135 * @param socket A socket resource |
1135 * @param socket A socket resource |
1136 * @param string The expected response from the server, this needs to be exactly three characters. |
1136 * @param string The expected response from the server, this needs to be exactly three characters. |
1137 */ |
1137 */ |
1138 |
1138 |
1139 function smtp_get_response($socket, $response, $line = __LINE__) |
1139 function smtp_get_response($socket, $response, $line = __LINE__) |
1140 { |
1140 { |
1141 $server_response = ''; |
1141 $server_response = ''; |
1142 while (substr($server_response, 3, 1) != ' ') |
1142 while (substr($server_response, 3, 1) != ' ') |
1143 { |
1143 { |
1144 if (!($server_response = fgets($socket, 256))) |
1144 if (!($server_response = fgets($socket, 256))) |
1145 { |
1145 { |
1146 die_friendly('SMTP Error', "<p>Couldn't get mail server response codes</p>"); |
1146 die_friendly('SMTP Error', "<p>Couldn't get mail server response codes</p>"); |
1147 } |
1147 } |
1148 } |
1148 } |
1149 |
1149 |
1150 if (!(substr($server_response, 0, 3) == $response)) |
1150 if (!(substr($server_response, 0, 3) == $response)) |
1151 { |
1151 { |
1152 die_friendly('SMTP Error', "<p>Ran into problems sending mail. Response: $server_response</p>"); |
1152 die_friendly('SMTP Error', "<p>Ran into problems sending mail. Response: $server_response</p>"); |
1153 } |
1153 } |
1154 } |
1154 } |
1155 |
1155 |
1156 /** |
1156 /** |
1157 * Wrapper for smtp_send_email_core that takes the sender as the fourth parameter instead of additional headers. |
1157 * Wrapper for smtp_send_email_core that takes the sender as the fourth parameter instead of additional headers. |
1158 * @param string E-mail address to send to |
1158 * @param string E-mail address to send to |
1176 * @license GPL |
1176 * @license GPL |
1177 */ |
1177 */ |
1178 |
1178 |
1179 function smtp_send_email_core($mail_to, $subject, $message, $headers = '') |
1179 function smtp_send_email_core($mail_to, $subject, $message, $headers = '') |
1180 { |
1180 { |
1181 // Fix any bare linefeeds in the message to make it RFC821 Compliant. |
1181 // Fix any bare linefeeds in the message to make it RFC821 Compliant. |
1182 $message = preg_replace("#(?<!\r)\n#si", "\r\n", $message); |
1182 $message = preg_replace("#(?<!\r)\n#si", "\r\n", $message); |
1183 |
1183 |
1184 if ($headers != '') |
1184 if ($headers != '') |
1185 { |
1185 { |
1186 if (is_array($headers)) |
1186 if (is_array($headers)) |
1187 { |
1187 { |
1188 if (sizeof($headers) > 1) |
1188 if (sizeof($headers) > 1) |
1189 { |
1189 { |
1190 $headers = join("\n", $headers); |
1190 $headers = join("\n", $headers); |
1191 } |
1191 } |
1192 else |
1192 else |
1193 { |
1193 { |
1194 $headers = $headers[0]; |
1194 $headers = $headers[0]; |
1195 } |
1195 } |
1196 } |
1196 } |
1197 $headers = chop($headers); |
1197 $headers = chop($headers); |
1198 |
1198 |
1199 // Make sure there are no bare linefeeds in the headers |
1199 // Make sure there are no bare linefeeds in the headers |
1200 $headers = preg_replace('#(?<!\r)\n#si', "\r\n", $headers); |
1200 $headers = preg_replace('#(?<!\r)\n#si', "\r\n", $headers); |
1201 |
1201 |
1202 // Ok this is rather confusing all things considered, |
1202 // Ok this is rather confusing all things considered, |
1203 // but we have to grab bcc and cc headers and treat them differently |
1203 // but we have to grab bcc and cc headers and treat them differently |
1204 // Something we really didn't take into consideration originally |
1204 // Something we really didn't take into consideration originally |
1205 $header_array = explode("\r\n", $headers); |
1205 $header_array = explode("\r\n", $headers); |
1206 @reset($header_array); |
1206 @reset($header_array); |
1207 |
1207 |
1208 $headers = ''; |
1208 $headers = ''; |
1209 $cc = ''; |
1209 $cc = ''; |
1210 $bcc = ''; |
1210 $bcc = ''; |
1211 while(list(, $header) = each($header_array)) |
1211 while(list(, $header) = each($header_array)) |
1212 { |
1212 { |
1213 if (preg_match('#^cc:#si', $header)) |
1213 if (preg_match('#^cc:#si', $header)) |
1214 { |
1214 { |
1215 $cc = preg_replace('#^cc:(.*)#si', '\1', $header); |
1215 $cc = preg_replace('#^cc:(.*)#si', '\1', $header); |
1216 } |
1216 } |
1217 else if (preg_match('#^bcc:#si', $header)) |
1217 else if (preg_match('#^bcc:#si', $header)) |
1218 { |
1218 { |
1219 $bcc = preg_replace('#^bcc:(.*)#si', '\1', $header); |
1219 $bcc = preg_replace('#^bcc:(.*)#si', '\1', $header); |
1220 $header = ''; |
1220 $header = ''; |
1221 } |
1221 } |
1222 $headers .= ($header != '') ? $header . "\r\n" : ''; |
1222 $headers .= ($header != '') ? $header . "\r\n" : ''; |
1223 } |
1223 } |
1224 |
1224 |
1225 $headers = chop($headers); |
1225 $headers = chop($headers); |
1226 $cc = explode(', ', $cc); |
1226 $cc = explode(', ', $cc); |
1227 $bcc = explode(', ', $bcc); |
1227 $bcc = explode(', ', $bcc); |
1228 } |
1228 } |
1229 |
1229 |
1230 if (trim($subject) == '') |
1230 if (trim($subject) == '') |
1231 { |
1231 { |
1232 die_friendly(GENERAL_ERROR, "No email Subject specified"); |
1232 die_friendly(GENERAL_ERROR, "No email Subject specified"); |
1233 } |
1233 } |
1234 |
1234 |
1235 if (trim($message) == '') |
1235 if (trim($message) == '') |
1236 { |
1236 { |
1237 die_friendly(GENERAL_ERROR, "Email message was blank"); |
1237 die_friendly(GENERAL_ERROR, "Email message was blank"); |
1238 } |
1238 } |
1239 |
1239 |
1240 // setup SMTP |
1240 // setup SMTP |
1241 $host = getConfig('smtp_server'); |
1241 $host = getConfig('smtp_server'); |
1242 if ( empty($host) ) |
1242 if ( empty($host) ) |
1243 return 'No smtp_host in config'; |
1243 return 'No smtp_host in config'; |
1244 if ( strstr($host, ':' ) ) |
1244 if ( strstr($host, ':' ) ) |
1245 { |
1245 { |
1246 $n = explode(':', $host); |
1246 $n = explode(':', $host); |
1247 $smtp_host = $n[0]; |
1247 $smtp_host = $n[0]; |
1248 $port = intval($n[1]); |
1248 $port = intval($n[1]); |
1249 } |
1249 } |
1250 else |
1250 else |
1251 { |
1251 { |
1252 $smtp_host = $host; |
1252 $smtp_host = $host; |
1253 $port = 25; |
1253 $port = 25; |
1254 } |
1254 } |
1255 |
1255 |
1256 $smtp_user = getConfig('smtp_user'); |
1256 $smtp_user = getConfig('smtp_user'); |
1257 $smtp_pass = getConfig('smtp_password'); |
1257 $smtp_pass = getConfig('smtp_password'); |
1258 |
1258 |
1259 // Ok we have error checked as much as we can to this point let's get on |
1259 // Ok we have error checked as much as we can to this point let's get on |
1260 // it already. |
1260 // it already. |
1261 if( !$socket = @fsockopen($smtp_host, $port, $errno, $errstr, 20) ) |
1261 if( !$socket = @fsockopen($smtp_host, $port, $errno, $errstr, 20) ) |
1262 { |
1262 { |
1263 die_friendly(GENERAL_ERROR, "Could not connect to smtp host : $errno : $errstr"); |
1263 die_friendly(GENERAL_ERROR, "Could not connect to smtp host : $errno : $errstr"); |
1264 } |
1264 } |
1265 |
1265 |
1266 // Wait for reply |
1266 // Wait for reply |
1267 smtp_get_response($socket, "220", __LINE__); |
1267 smtp_get_response($socket, "220", __LINE__); |
1268 |
1268 |
1269 // Do we want to use AUTH?, send RFC2554 EHLO, else send RFC821 HELO |
1269 // Do we want to use AUTH?, send RFC2554 EHLO, else send RFC821 HELO |
1270 // This improved as provided by SirSir to accomodate |
1270 // This improved as provided by SirSir to accomodate |
1271 if( !empty($smtp_user) && !empty($smtp_pass) ) |
1271 if( !empty($smtp_user) && !empty($smtp_pass) ) |
1272 { |
1272 { |
1273 enano_fputs($socket, "EHLO " . $smtp_host . "\r\n"); |
1273 enano_fputs($socket, "EHLO " . $smtp_host . "\r\n"); |
1274 smtp_get_response($socket, "250", __LINE__); |
1274 smtp_get_response($socket, "250", __LINE__); |
1275 |
1275 |
1276 enano_fputs($socket, "AUTH LOGIN\r\n"); |
1276 enano_fputs($socket, "AUTH LOGIN\r\n"); |
1277 smtp_get_response($socket, "334", __LINE__); |
1277 smtp_get_response($socket, "334", __LINE__); |
1278 |
1278 |
1279 enano_fputs($socket, base64_encode($smtp_user) . "\r\n"); |
1279 enano_fputs($socket, base64_encode($smtp_user) . "\r\n"); |
1280 smtp_get_response($socket, "334", __LINE__); |
1280 smtp_get_response($socket, "334", __LINE__); |
1281 |
1281 |
1282 enano_fputs($socket, base64_encode($smtp_pass) . "\r\n"); |
1282 enano_fputs($socket, base64_encode($smtp_pass) . "\r\n"); |
1283 smtp_get_response($socket, "235", __LINE__); |
1283 smtp_get_response($socket, "235", __LINE__); |
1284 } |
1284 } |
1285 else |
1285 else |
1286 { |
1286 { |
1287 enano_fputs($socket, "HELO " . $smtp_host . "\r\n"); |
1287 enano_fputs($socket, "HELO " . $smtp_host . "\r\n"); |
1288 smtp_get_response($socket, "250", __LINE__); |
1288 smtp_get_response($socket, "250", __LINE__); |
1289 } |
1289 } |
1290 |
1290 |
1291 // From this point onward most server response codes should be 250 |
1291 // From this point onward most server response codes should be 250 |
1292 // Specify who the mail is from.... |
1292 // Specify who the mail is from.... |
1293 enano_fputs($socket, "MAIL FROM: <" . getConfig('contact_email') . ">\r\n"); |
1293 enano_fputs($socket, "MAIL FROM: <" . getConfig('contact_email') . ">\r\n"); |
1294 smtp_get_response($socket, "250", __LINE__); |
1294 smtp_get_response($socket, "250", __LINE__); |
1295 |
1295 |
1296 // Specify each user to send to and build to header. |
1296 // Specify each user to send to and build to header. |
1297 $to_header = ''; |
1297 $to_header = ''; |
1298 |
1298 |
1299 // Add an additional bit of error checking to the To field. |
1299 // Add an additional bit of error checking to the To field. |
1300 $mail_to = (trim($mail_to) == '') ? 'Undisclosed-recipients:;' : trim($mail_to); |
1300 $mail_to = (trim($mail_to) == '') ? 'Undisclosed-recipients:;' : trim($mail_to); |
1301 if (preg_match('#[^ ]+\@[^ ]+#', $mail_to)) |
1301 if (preg_match('#[^ ]+\@[^ ]+#', $mail_to)) |
1302 { |
1302 { |
1303 enano_fputs($socket, "RCPT TO: <$mail_to>\r\n"); |
1303 enano_fputs($socket, "RCPT TO: <$mail_to>\r\n"); |
1304 smtp_get_response($socket, "250", __LINE__); |
1304 smtp_get_response($socket, "250", __LINE__); |
1305 } |
1305 } |
1306 |
1306 |
1307 // Ok now do the CC and BCC fields... |
1307 // Ok now do the CC and BCC fields... |
1308 @reset($bcc); |
1308 @reset($bcc); |
1309 while(list(, $bcc_address) = each($bcc)) |
1309 while(list(, $bcc_address) = each($bcc)) |
1310 { |
1310 { |
1311 // Add an additional bit of error checking to bcc header... |
1311 // Add an additional bit of error checking to bcc header... |
1312 $bcc_address = trim($bcc_address); |
1312 $bcc_address = trim($bcc_address); |
1313 if (preg_match('#[^ ]+\@[^ ]+#', $bcc_address)) |
1313 if (preg_match('#[^ ]+\@[^ ]+#', $bcc_address)) |
1314 { |
1314 { |
1315 enano_fputs($socket, "RCPT TO: <$bcc_address>\r\n"); |
1315 enano_fputs($socket, "RCPT TO: <$bcc_address>\r\n"); |
1316 smtp_get_response($socket, "250", __LINE__); |
1316 smtp_get_response($socket, "250", __LINE__); |
1317 } |
1317 } |
1318 } |
1318 } |
1319 |
1319 |
1320 @reset($cc); |
1320 @reset($cc); |
1321 while(list(, $cc_address) = each($cc)) |
1321 while(list(, $cc_address) = each($cc)) |
1322 { |
1322 { |
1323 // Add an additional bit of error checking to cc header |
1323 // Add an additional bit of error checking to cc header |
1324 $cc_address = trim($cc_address); |
1324 $cc_address = trim($cc_address); |
1325 if (preg_match('#[^ ]+\@[^ ]+#', $cc_address)) |
1325 if (preg_match('#[^ ]+\@[^ ]+#', $cc_address)) |
1326 { |
1326 { |
1327 enano_fputs($socket, "RCPT TO: <$cc_address>\r\n"); |
1327 enano_fputs($socket, "RCPT TO: <$cc_address>\r\n"); |
1328 smtp_get_response($socket, "250", __LINE__); |
1328 smtp_get_response($socket, "250", __LINE__); |
1329 } |
1329 } |
1330 } |
1330 } |
1331 |
1331 |
1332 // Ok now we tell the server we are ready to start sending data |
1332 // Ok now we tell the server we are ready to start sending data |
1333 enano_fputs($socket, "DATA\r\n"); |
1333 enano_fputs($socket, "DATA\r\n"); |
1334 |
1334 |
1335 // This is the last response code we look for until the end of the message. |
1335 // This is the last response code we look for until the end of the message. |
1336 smtp_get_response($socket, "354", __LINE__); |
1336 smtp_get_response($socket, "354", __LINE__); |
1337 |
1337 |
1338 // Send the Subject Line... |
1338 // Send the Subject Line... |
1339 enano_fputs($socket, "Subject: $subject\r\n"); |
1339 enano_fputs($socket, "Subject: $subject\r\n"); |
1340 |
1340 |
1341 // Now the To Header. |
1341 // Now the To Header. |
1342 enano_fputs($socket, "To: $mail_to\r\n"); |
1342 enano_fputs($socket, "To: $mail_to\r\n"); |
1343 |
1343 |
1344 // Now any custom headers.... |
1344 // Now any custom headers.... |
1345 enano_fputs($socket, "$headers\r\n\r\n"); |
1345 enano_fputs($socket, "$headers\r\n\r\n"); |
1346 |
1346 |
1347 // Ok now we are ready for the message... |
1347 // Ok now we are ready for the message... |
1348 enano_fputs($socket, "$message\r\n"); |
1348 enano_fputs($socket, "$message\r\n"); |
1349 |
1349 |
1350 // Ok the all the ingredients are mixed in let's cook this puppy... |
1350 // Ok the all the ingredients are mixed in let's cook this puppy... |
1351 enano_fputs($socket, ".\r\n"); |
1351 enano_fputs($socket, ".\r\n"); |
1352 smtp_get_response($socket, "250", __LINE__); |
1352 smtp_get_response($socket, "250", __LINE__); |
1353 |
1353 |
1354 // Now tell the server we are done and close the socket... |
1354 // Now tell the server we are done and close the socket... |
1355 enano_fputs($socket, "QUIT\r\n"); |
1355 enano_fputs($socket, "QUIT\r\n"); |
1356 fclose($socket); |
1356 fclose($socket); |
1357 |
1357 |
1358 return TRUE; |
1358 return TRUE; |
1359 } |
1359 } |
1360 |
1360 |
1361 /** |
1361 /** |
1362 * Tell which version of Enano we're running. |
1362 * Tell which version of Enano we're running. |
1363 * @param bool $long if true, uses English version names (e.g. alpha, beta, release candidate). If false (default) uses abbreviations (1.0a1, 1.0b3, 1.0RC2, etc.) |
1363 * @param bool $long if true, uses English version names (e.g. alpha, beta, release candidate). If false (default) uses abbreviations (1.0a1, 1.0b3, 1.0RC2, etc.) |
1365 * @return string |
1365 * @return string |
1366 */ |
1366 */ |
1367 |
1367 |
1368 function enano_version($long = false, $no_nightly = false) |
1368 function enano_version($long = false, $no_nightly = false) |
1369 { |
1369 { |
1370 if ( !defined('ENANO_CONFIG_FETCHED') ) |
1370 if ( !defined('ENANO_CONFIG_FETCHED') ) |
1371 { |
1371 { |
1372 return function_exists('installer_enano_version') ? installer_enano_version() : $GLOBALS['enano_version']; |
1372 return function_exists('installer_enano_version') ? installer_enano_version() : $GLOBALS['enano_version']; |
1373 } |
1373 } |
1374 $r = getConfig('enano_version'); |
1374 $r = getConfig('enano_version'); |
1375 $rc = ( $long ) ? ' release candidate ' : 'RC'; |
1375 $rc = ( $long ) ? ' release candidate ' : 'RC'; |
1376 $b = ( $long ) ? ' beta ' : 'b'; |
1376 $b = ( $long ) ? ' beta ' : 'b'; |
1377 $a = ( $long ) ? ' alpha ' : 'a'; |
1377 $a = ( $long ) ? ' alpha ' : 'a'; |
1378 if($v = getConfig('enano_rc_version')) $r .= $rc.$v; |
1378 if($v = getConfig('enano_rc_version')) $r .= $rc.$v; |
1379 if($v = getConfig('enano_beta_version')) $r .= $b.$v; |
1379 if($v = getConfig('enano_beta_version')) $r .= $b.$v; |
1380 if($v = getConfig('enano_alpha_version')) $r .= $a.$v; |
1380 if($v = getConfig('enano_alpha_version')) $r .= $a.$v; |
1381 if ( defined('ENANO_NIGHTLY') && !$no_nightly ) |
1381 if ( defined('ENANO_NIGHTLY') && !$no_nightly ) |
1382 { |
1382 { |
1383 $nightlytag = ENANO_NIGHTLY_MONTH . '-' . ENANO_NIGHTLY_DAY . '-' . ENANO_NIGHTLY_YEAR; |
1383 $nightlytag = ENANO_NIGHTLY_MONTH . '-' . ENANO_NIGHTLY_DAY . '-' . ENANO_NIGHTLY_YEAR; |
1384 $nightlylong = ' nightly; build date: ' . ENANO_NIGHTLY_MONTH . '-' . ENANO_NIGHTLY_DAY . '-' . ENANO_NIGHTLY_YEAR; |
1384 $nightlylong = ' nightly; build date: ' . ENANO_NIGHTLY_MONTH . '-' . ENANO_NIGHTLY_DAY . '-' . ENANO_NIGHTLY_YEAR; |
1385 $r = ( $long ) ? $r . $nightlylong : $r . '-nightly-' . $nightlytag; |
1385 $r = ( $long ) ? $r . $nightlylong : $r . '-nightly-' . $nightlytag; |
1386 } |
1386 } |
1387 return $r; |
1387 return $r; |
1388 } |
1388 } |
1389 |
1389 |
1390 /** |
1390 /** |
1391 * Give the codename of the release of Enano being run. |
1391 * Give the codename of the release of Enano being run. |
1392 * @return string |
1392 * @return string |
1393 */ |
1393 */ |
1394 |
1394 |
1395 function enano_codename() |
1395 function enano_codename() |
1396 { |
1396 { |
1397 $names = array( |
1397 $names = array( |
1398 '1.0RC1' => 'Leprechaun', |
1398 '1.0RC1' => 'Leprechaun', |
1399 '1.0RC2' => 'Clurichaun', |
1399 '1.0RC2' => 'Clurichaun', |
1400 '1.0RC3' => 'Druid', |
1400 '1.0RC3' => 'Druid', |
1401 '1.0' => 'Banshee', |
1401 '1.0' => 'Banshee', |
1402 '1.0.1' => 'Loch Ness', |
1402 '1.0.1' => 'Loch Ness', |
1403 '1.0.1.1'=> 'Loch Ness internal bugfix build', |
1403 '1.0.1.1'=> 'Loch Ness internal bugfix build', |
1404 '1.0.2b1'=> 'Coblynau unstable', |
1404 '1.0.2b1'=> 'Coblynau unstable', |
1405 '1.0.2' => 'Coblynau', |
1405 '1.0.2' => 'Coblynau', |
1406 '1.0.3' => 'Dyrad', |
1406 '1.0.3' => 'Dyrad', |
1407 '1.1.1' => 'Caoineag alpha 1', |
1407 '1.1.1' => 'Caoineag alpha 1', |
1408 '1.1.2' => 'Caoineag alpha 2', |
1408 '1.1.2' => 'Caoineag alpha 2', |
1409 '1.1.3' => 'Caoineag alpha 3', |
1409 '1.1.3' => 'Caoineag alpha 3', |
1410 '1.1.4' => 'Caoineag alpha 4', |
1410 '1.1.4' => 'Caoineag alpha 4', |
1411 '1.1.5' => 'Caoineag alpha 5', |
1411 '1.1.5' => 'Caoineag alpha 5', |
1412 '1.1.6' => 'Caoineag beta 1', |
1412 '1.1.6' => 'Caoineag beta 1', |
1413 '1.1.7' => 'Caoineag beta 2', |
1413 '1.1.7' => 'Caoineag beta 2', |
1414 '1.1.8' => 'Caoineag beta 3', |
1414 '1.1.8' => 'Caoineag beta 3', |
1415 ); |
1415 ); |
1416 $version = enano_version(); |
1416 $version = enano_version(); |
1417 if ( isset($names[$version]) ) |
1417 if ( isset($names[$version]) ) |
1418 { |
1418 { |
1419 return $names[$version]; |
1419 return $names[$version]; |
1420 } |
1420 } |
1421 return 'Anonymous build'; |
1421 return 'Anonymous build'; |
1422 } |
1422 } |
1423 |
1423 |
1424 /** |
1424 /** |
1425 * Badly named function to send back eval'able Javascript code with an error message. Deprecated, use JSON instead. |
1425 * Badly named function to send back eval'able Javascript code with an error message. Deprecated, use JSON instead. |
1426 * @param string Message to send |
1426 * @param string Message to send |
1427 */ |
1427 */ |
1428 |
1428 |
1429 function _die($t) { |
1429 function _die($t) { |
1430 $_ob = 'document.getElementById("ajaxEditContainer").innerHTML = unescape(\'' . rawurlencode('' . $t . '') . '\')'; |
1430 $_ob = 'document.getElementById("ajaxEditContainer").innerHTML = unescape(\'' . rawurlencode('' . $t . '') . '\')'; |
1431 die($_ob); |
1431 die($_ob); |
1432 } |
1432 } |
1433 |
1433 |
1434 /** |
1434 /** |
1435 * Same as _die(), but sends an SQL backtrace with the error message, and doesn't halt execution. |
1435 * Same as _die(), but sends an SQL backtrace with the error message, and doesn't halt execution. |
1436 * @param string Message to send |
1436 * @param string Message to send |
1437 */ |
1437 */ |
1438 |
1438 |
1439 function jsdie($text) { |
1439 function jsdie($text) { |
1440 global $db, $session, $paths, $template, $plugins; // Common objects |
1440 global $db, $session, $paths, $template, $plugins; // Common objects |
1441 $text = rawurlencode($text . "\n\nSQL Backtrace:\n" . $db->sql_backtrace()); |
1441 $text = rawurlencode($text . "\n\nSQL Backtrace:\n" . $db->sql_backtrace()); |
1442 echo 'document.getElementById("ajaxEditContainer").innerHTML = unescape(\''.$text.'\');'; |
1442 echo 'document.getElementById("ajaxEditContainer").innerHTML = unescape(\''.$text.'\');'; |
1443 } |
1443 } |
1444 |
1444 |
1445 /** |
1445 /** |
1446 * Capitalizes the first letter of a string |
1446 * Capitalizes the first letter of a string |
1447 * @param $text string the text to be transformed |
1447 * @param $text string the text to be transformed |
1448 * @return string |
1448 * @return string |
1449 */ |
1449 */ |
1450 |
1450 |
1451 function capitalize_first_letter($text) |
1451 function capitalize_first_letter($text) |
1452 { |
1452 { |
1453 return strtoupper(substr($text, 0, 1)) . substr($text, 1); |
1453 return strtoupper(substr($text, 0, 1)) . substr($text, 1); |
1454 } |
1454 } |
1455 |
1455 |
1456 /** |
1456 /** |
1457 * Checks if a value in a bitfield is on or off |
1457 * Checks if a value in a bitfield is on or off |
1458 * @param $bitfield int the bit-field value |
1458 * @param $bitfield int the bit-field value |
1563 * @return string |
1563 * @return string |
1564 */ |
1564 */ |
1565 |
1565 |
1566 function hexencode($text, $prefix = '%', $suffix = '') |
1566 function hexencode($text, $prefix = '%', $suffix = '') |
1567 { |
1567 { |
1568 $arr = enano_str_split($text); |
1568 $arr = enano_str_split($text); |
1569 $r = ''; |
1569 $r = ''; |
1570 foreach($arr as $a) |
1570 foreach($arr as $a) |
1571 { |
1571 { |
1572 $nibble = (string)dechex(ord($a)); |
1572 $nibble = (string)dechex(ord($a)); |
1573 if(strlen($nibble) == 1) $nibble = '0' . $nibble; |
1573 if(strlen($nibble) == 1) $nibble = '0' . $nibble; |
1574 $r .= $prefix . $nibble . $suffix; |
1574 $r .= $prefix . $nibble . $suffix; |
1575 } |
1575 } |
1576 return $r; |
1576 return $r; |
1577 } |
1577 } |
1578 |
1578 |
1579 /** |
1579 /** |
1580 * Enano-ese equivalent of get_magic_quotes_gpc() |
1580 * Enano-ese equivalent of get_magic_quotes_gpc() |
1581 * @return bool |
1581 * @return bool |
1582 */ |
1582 */ |
1583 |
1583 |
1584 function enano_get_magic_quotes_gpc() |
1584 function enano_get_magic_quotes_gpc() |
1585 { |
1585 { |
1586 if(function_exists('get_magic_quotes_gpc')) |
1586 if(function_exists('get_magic_quotes_gpc')) |
1587 { |
1587 { |
1588 return ( get_magic_quotes_gpc() == 1 ); |
1588 return ( get_magic_quotes_gpc() == 1 ); |
1589 } |
1589 } |
1590 else |
1590 else |
1591 { |
1591 { |
1592 return ( strtolower(@ini_get('magic_quotes_gpc')) == '1' ); |
1592 return ( strtolower(@ini_get('magic_quotes_gpc')) == '1' ); |
1593 } |
1593 } |
1594 } |
1594 } |
1595 |
1595 |
1596 /** |
1596 /** |
1597 * Recursive stripslashes() |
1597 * Recursive stripslashes() |
1598 * @param array |
1598 * @param array |
1599 * @return array |
1599 * @return array |
1600 */ |
1600 */ |
1601 |
1601 |
1602 function stripslashes_recurse($arr) |
1602 function stripslashes_recurse($arr) |
1603 { |
1603 { |
1604 foreach($arr as $k => $xxxx) |
1604 foreach($arr as $k => $xxxx) |
1605 { |
1605 { |
1606 $val =& $arr[$k]; |
1606 $val =& $arr[$k]; |
1607 if(is_string($val)) |
1607 if(is_string($val)) |
1608 $val = stripslashes($val); |
1608 $val = stripslashes($val); |
1609 elseif(is_array($val)) |
1609 elseif(is_array($val)) |
1610 $val = stripslashes_recurse($val); |
1610 $val = stripslashes_recurse($val); |
1611 } |
1611 } |
1612 return $arr; |
1612 return $arr; |
1613 } |
1613 } |
1614 |
1614 |
1615 /** |
1615 /** |
1616 * Recursive function to remove all NUL bytes from a string |
1616 * Recursive function to remove all NUL bytes from a string |
1617 * @param array |
1617 * @param array |
1618 * @return array |
1618 * @return array |
1619 */ |
1619 */ |
1620 |
1620 |
1621 function strip_nul_chars($arr) |
1621 function strip_nul_chars($arr) |
1622 { |
1622 { |
1623 foreach($arr as $k => $xxxx_unused) |
1623 foreach($arr as $k => $xxxx_unused) |
1624 { |
1624 { |
1625 $val =& $arr[$k]; |
1625 $val =& $arr[$k]; |
1626 if(is_string($val)) |
1626 if(is_string($val)) |
1627 $val = str_replace("\000", '', $val); |
1627 $val = str_replace("\000", '', $val); |
1628 elseif(is_array($val)) |
1628 elseif(is_array($val)) |
1629 $val = strip_nul_chars($val); |
1629 $val = strip_nul_chars($val); |
1630 } |
1630 } |
1631 return $arr; |
1631 return $arr; |
1632 } |
1632 } |
1633 |
1633 |
1634 /** |
1634 /** |
1635 * If magic_quotes_gpc is on, calls stripslashes() on everything in $_GET/$_POST/$_COOKIE. Also strips any NUL characters from incoming requests, as these are typically malicious. |
1635 * If magic_quotes_gpc is on, calls stripslashes() on everything in $_GET/$_POST/$_COOKIE. Also strips any NUL characters from incoming requests, as these are typically malicious. |
1636 * @ignore - this doesn't work too well in my tests |
1636 * @ignore - this doesn't work too well in my tests |
1637 * @todo port version from the PHP manual |
1637 * @todo port version from the PHP manual |
1638 * @return void |
1638 * @return void |
1639 */ |
1639 */ |
1640 function strip_magic_quotes_gpc() |
1640 function strip_magic_quotes_gpc() |
1641 { |
1641 { |
1642 if(enano_get_magic_quotes_gpc()) |
1642 if(enano_get_magic_quotes_gpc()) |
1643 { |
1643 { |
1644 $_POST = stripslashes_recurse($_POST); |
1644 $_POST = stripslashes_recurse($_POST); |
1645 $_GET = stripslashes_recurse($_GET); |
1645 $_GET = stripslashes_recurse($_GET); |
1646 $_COOKIE = stripslashes_recurse($_COOKIE); |
1646 $_COOKIE = stripslashes_recurse($_COOKIE); |
1647 $_REQUEST = stripslashes_recurse($_REQUEST); |
1647 $_REQUEST = stripslashes_recurse($_REQUEST); |
1648 } |
1648 } |
1649 $_POST = strip_nul_chars($_POST); |
1649 $_POST = strip_nul_chars($_POST); |
1650 $_GET = strip_nul_chars($_GET); |
1650 $_GET = strip_nul_chars($_GET); |
1651 $_COOKIE = strip_nul_chars($_COOKIE); |
1651 $_COOKIE = strip_nul_chars($_COOKIE); |
1652 $_REQUEST = strip_nul_chars($_REQUEST); |
1652 $_REQUEST = strip_nul_chars($_REQUEST); |
1653 $_POST = decode_unicode_array($_POST); |
1653 $_POST = decode_unicode_array($_POST); |
1654 $_GET = decode_unicode_array($_GET); |
1654 $_GET = decode_unicode_array($_GET); |
1655 $_COOKIE = decode_unicode_array($_COOKIE); |
1655 $_COOKIE = decode_unicode_array($_COOKIE); |
1656 $_REQUEST = decode_unicode_array($_REQUEST); |
1656 $_REQUEST = decode_unicode_array($_REQUEST); |
1657 } |
1657 } |
1658 |
1658 |
1659 /** |
1659 /** |
1660 * A very basic single-character compression algorithm for binary strings/bitfields |
1660 * A very basic single-character compression algorithm for binary strings/bitfields |
1661 * @param string $bits the text to compress, should be only 1s and 0s |
1661 * @param string $bits the text to compress, should be only 1s and 0s |
1662 * @return string |
1662 * @return string |
1663 */ |
1663 */ |
1664 |
1664 |
1665 function compress_bitfield($bits) |
1665 function compress_bitfield($bits) |
1666 { |
1666 { |
1667 if ( !preg_match('/^[01]+$/', $bits) ) |
1667 if ( !preg_match('/^[01]+$/', $bits) ) |
1668 return false; |
1668 return false; |
1669 |
1669 |
1670 $current = intval($bits{0}); |
1670 $current = intval($bits{0}); |
1671 $clen = 0; |
1671 $clen = 0; |
1672 $out = ''; |
1672 $out = ''; |
1673 for ( $i = 0; $i < strlen($bits); $i++ ) |
1673 for ( $i = 0; $i < strlen($bits); $i++ ) |
1674 { |
1674 { |
1675 $cbit = intval($bits{$i}); |
1675 $cbit = intval($bits{$i}); |
1676 if ( $cbit !== $current || $clen == 127 || $i == strlen($bits) - 1 ) |
1676 if ( $cbit !== $current || $clen == 127 || $i == strlen($bits) - 1 ) |
1677 { |
1677 { |
1678 if ( $i == strlen($bits) - 1 && $cbit === $current ) |
1678 if ( $i == strlen($bits) - 1 && $cbit === $current ) |
1679 { |
1679 { |
1680 $clen++; |
1680 $clen++; |
1681 } |
1681 } |
1682 // write chunk |
1682 // write chunk |
1683 $byte = $clen; |
1683 $byte = $clen; |
1684 if ( $current === 1 ) |
1684 if ( $current === 1 ) |
1685 $byte |= 0x80; |
1685 $byte |= 0x80; |
1686 $out .= chr($byte); |
1686 $out .= chr($byte); |
1687 |
1687 |
1688 if ( $i == strlen($bits) - 1 && $cbit !== $current ) |
1688 if ( $i == strlen($bits) - 1 && $cbit !== $current ) |
1689 { |
1689 { |
1690 $out .= ( $cbit === 1 ) ? chr(0x81) : chr(0x1); |
1690 $out .= ( $cbit === 1 ) ? chr(0x81) : chr(0x1); |
1691 } |
1691 } |
1692 |
1692 |
1693 // reset |
1693 // reset |
1694 $current = intval($cbit); |
1694 $current = intval($cbit); |
1695 $clen = 0; |
1695 $clen = 0; |
1696 } |
1696 } |
1697 $clen++; |
1697 $clen++; |
1698 } |
1698 } |
1699 $crc = dechex(crc32($out)); |
1699 $crc = dechex(crc32($out)); |
1700 while ( strlen($crc) < 8 ) |
1700 while ( strlen($crc) < 8 ) |
1701 $crc = "0$crc"; |
1701 $crc = "0$crc"; |
1702 return "cbf2:{$crc}" . hexencode($out, '', ''); |
1702 return "cbf2:{$crc}" . hexencode($out, '', ''); |
1703 } |
1703 } |
1704 |
1704 |
1705 // test case |
1705 // test case |
1706 // $bf = '0111100010000000000000000000000100000000000000001110000000000000000101100000010100001100010000000000000000000000000000111111111111111111111100100001000000000000000000000000000000000000'; |
1706 // $bf = '0111100010000000000000000000000100000000000000001110000000000000000101100000010100001100010000000000000000000000000000111111111111111111111100100001000000000000000000000000000000000000'; |
1707 // die('<pre>Original: ' . " $bf\nCompressed: " . compress_bitfield($bf) . "\nProcessed: ".uncompress_bitfield(compress_bitfield($bf)).'</pre>'); |
1707 // die('<pre>Original: ' . " $bf\nCompressed: " . compress_bitfield($bf) . "\nProcessed: ".uncompress_bitfield(compress_bitfield($bf)).'</pre>'); |
1794 * @return string |
1794 * @return string |
1795 */ |
1795 */ |
1796 |
1796 |
1797 function export_table($table, $structure = true, $data = true, $compact = false) |
1797 function export_table($table, $structure = true, $data = true, $compact = false) |
1798 { |
1798 { |
1799 global $db, $session, $paths, $template, $plugins; // Common objects |
1799 global $db, $session, $paths, $template, $plugins; // Common objects |
1800 $struct_keys = ''; |
1800 $struct_keys = ''; |
1801 $divider = (!$compact) ? "\n" : "\n"; |
1801 $divider = (!$compact) ? "\n" : "\n"; |
1802 $spacer1 = (!$compact) ? "\n" : " "; |
1802 $spacer1 = (!$compact) ? "\n" : " "; |
1803 $spacer2 = (!$compact) ? " " : " "; |
1803 $spacer2 = (!$compact) ? " " : " "; |
1804 $rowspacer = (!$compact) ? "\n " : " "; |
1804 $rowspacer = (!$compact) ? "\n " : " "; |
1805 $index_list = Array(); |
1805 $index_list = Array(); |
1806 $cols = $db->sql_query('SHOW COLUMNS IN '.$table.';'); |
1806 $cols = $db->sql_query('SHOW COLUMNS IN '.$table.';'); |
1807 if(!$cols) |
1807 if(!$cols) |
1808 { |
1808 { |
1809 echo 'export_table(): Error getting column list: '.$db->get_error_text().'<br />'; |
1809 echo 'export_table(): Error getting column list: '.$db->get_error_text().'<br />'; |
1810 return false; |
1810 return false; |
1811 } |
1811 } |
1812 $col = Array(); |
1812 $col = Array(); |
1813 $sqlcol = Array(); |
1813 $sqlcol = Array(); |
1814 $collist = Array(); |
1814 $collist = Array(); |
1815 $pri_keys = Array(); |
1815 $pri_keys = Array(); |
1816 // Using fetchrow_num() here to compensate for MySQL l10n |
1816 // Using fetchrow_num() here to compensate for MySQL l10n |
1817 while( $row = $db->fetchrow_num() ) |
1817 while( $row = $db->fetchrow_num() ) |
1818 { |
1818 { |
1819 $field =& $row[0]; |
1819 $field =& $row[0]; |
1820 $type =& $row[1]; |
1820 $type =& $row[1]; |
1821 $null =& $row[2]; |
1821 $null =& $row[2]; |
1822 $key =& $row[3]; |
1822 $key =& $row[3]; |
1823 $def =& $row[4]; |
1823 $def =& $row[4]; |
1824 $extra =& $row[5]; |
1824 $extra =& $row[5]; |
1825 $col[] = Array( |
1825 $col[] = Array( |
1826 'name'=>$field, |
1826 'name'=>$field, |
1827 'type'=>$type, |
1827 'type'=>$type, |
1828 'null'=>$null, |
1828 'null'=>$null, |
1829 'key'=>$key, |
1829 'key'=>$key, |
1830 'default'=>$def, |
1830 'default'=>$def, |
1831 'extra'=>$extra, |
1831 'extra'=>$extra, |
1832 ); |
1832 ); |
1833 $collist[] = $field; |
1833 $collist[] = $field; |
1834 } |
1834 } |
1835 |
1835 |
1836 if ( $structure ) |
1836 if ( $structure ) |
1837 { |
1837 { |
1838 $db->sql_query('SET SQL_QUOTE_SHOW_CREATE = 0;'); |
1838 $db->sql_query('SET SQL_QUOTE_SHOW_CREATE = 0;'); |
1839 $struct = $db->sql_query('SHOW CREATE TABLE '.$table.';'); |
1839 $struct = $db->sql_query('SHOW CREATE TABLE '.$table.';'); |
1840 if ( !$struct ) |
1840 if ( !$struct ) |
1841 $db->_die(); |
1841 $db->_die(); |
1842 $row = $db->fetchrow_num(); |
1842 $row = $db->fetchrow_num(); |
1843 $db->free_result(); |
1843 $db->free_result(); |
1844 $struct = $row[1]; |
1844 $struct = $row[1]; |
1845 $struct = preg_replace("/\n\) ENGINE=(.+)$/", "\n);", $struct); |
1845 $struct = preg_replace("/\n\) ENGINE=(.+)$/", "\n);", $struct); |
1846 unset($row); |
1846 unset($row); |
1847 if ( $compact ) |
1847 if ( $compact ) |
1848 { |
1848 { |
1849 $struct_arr = explode("\n", $struct); |
1849 $struct_arr = explode("\n", $struct); |
1850 foreach ( $struct_arr as $i => $leg ) |
1850 foreach ( $struct_arr as $i => $leg ) |
1851 { |
1851 { |
1852 if ( $i == 0 ) |
1852 if ( $i == 0 ) |
1853 continue; |
1853 continue; |
1854 $test = trim($leg); |
1854 $test = trim($leg); |
1855 if ( empty($test) ) |
1855 if ( empty($test) ) |
1856 { |
1856 { |
1857 unset($struct_arr[$i]); |
1857 unset($struct_arr[$i]); |
1858 continue; |
1858 continue; |
1859 } |
1859 } |
1860 $struct_arr[$i] = preg_replace('/^([\s]*)/', ' ', $leg); |
1860 $struct_arr[$i] = preg_replace('/^([\s]*)/', ' ', $leg); |
1861 } |
1861 } |
1862 $struct = implode("", $struct_arr); |
1862 $struct = implode("", $struct_arr); |
1863 } |
1863 } |
1864 } |
1864 } |
1865 |
1865 |
1866 // Structuring complete |
1866 // Structuring complete |
1867 if($data) |
1867 if($data) |
1868 { |
1868 { |
1869 $datq = $db->sql_query('SELECT * FROM '.$table.';'); |
1869 $datq = $db->sql_query('SELECT * FROM '.$table.';'); |
1870 if(!$datq) |
1870 if(!$datq) |
1871 { |
1871 { |
1872 echo 'export_table(): Error getting column list: '.$db->get_error_text().'<br />'; |
1872 echo 'export_table(): Error getting column list: '.$db->get_error_text().'<br />'; |
1873 return false; |
1873 return false; |
1874 } |
1874 } |
1875 if($db->numrows() < 1) |
1875 if($db->numrows() < 1) |
1876 { |
1876 { |
1877 if($structure) return $struct; |
1877 if($structure) return $struct; |
1878 else return ''; |
1878 else return ''; |
1879 } |
1879 } |
1880 $rowdata = Array(); |
1880 $rowdata = Array(); |
1881 $dataqs = Array(); |
1881 $dataqs = Array(); |
1882 $insert_strings = Array(); |
1882 $insert_strings = Array(); |
1883 $z = false; |
1883 $z = false; |
1884 while($row = $db->fetchrow_num()) |
1884 while($row = $db->fetchrow_num()) |
1885 { |
1885 { |
1886 $z = false; |
1886 $z = false; |
1887 foreach($row as $i => $cell) |
1887 foreach($row as $i => $cell) |
1888 { |
1888 { |
1889 $str = mysql_encode_column($cell, $col[$i]['type']); |
1889 $str = mysql_encode_column($cell, $col[$i]['type']); |
1890 $rowdata[] = $str; |
1890 $rowdata[] = $str; |
1891 } |
1891 } |
1892 $dataqs2 = implode(",$rowspacer", $dataqs) . ",$rowspacer" . '( ' . implode(', ', $rowdata) . ' )'; |
1892 $dataqs2 = implode(",$rowspacer", $dataqs) . ",$rowspacer" . '( ' . implode(', ', $rowdata) . ' )'; |
1893 $ins = 'INSERT INTO '.$table.'( '.implode(',', $collist).' ) VALUES' . $dataqs2 . ";"; |
1893 $ins = 'INSERT INTO '.$table.'( '.implode(',', $collist).' ) VALUES' . $dataqs2 . ";"; |
1894 if ( strlen( $ins ) > MYSQL_MAX_PACKET_SIZE ) |
1894 if ( strlen( $ins ) > MYSQL_MAX_PACKET_SIZE ) |
1895 { |
1895 { |
1896 // We've exceeded the maximum allowed packet size for MySQL - separate this into a different query |
1896 // We've exceeded the maximum allowed packet size for MySQL - separate this into a different query |
1897 $insert_strings[] = 'INSERT INTO '.$table.'( '.implode(',', $collist).' ) VALUES' . implode(",$rowspacer", $dataqs) . ";";; |
1897 $insert_strings[] = 'INSERT INTO '.$table.'( '.implode(',', $collist).' ) VALUES' . implode(",$rowspacer", $dataqs) . ";";; |
1898 $dataqs = Array('( ' . implode(', ', $rowdata) . ' )'); |
1898 $dataqs = Array('( ' . implode(', ', $rowdata) . ' )'); |
1899 $z = true; |
1899 $z = true; |
1900 } |
1900 } |
1901 else |
1901 else |
1902 { |
1902 { |
1903 $dataqs[] = '( ' . implode(', ', $rowdata) . ' )'; |
1903 $dataqs[] = '( ' . implode(', ', $rowdata) . ' )'; |
1904 } |
1904 } |
1905 $rowdata = Array(); |
1905 $rowdata = Array(); |
1906 } |
1906 } |
1907 if ( !$z ) |
1907 if ( !$z ) |
1908 { |
1908 { |
1909 $insert_strings[] = 'INSERT INTO '.$table.'( '.implode(',', $collist).' ) VALUES' . implode(",$rowspacer", $dataqs) . ";";; |
1909 $insert_strings[] = 'INSERT INTO '.$table.'( '.implode(',', $collist).' ) VALUES' . implode(",$rowspacer", $dataqs) . ";";; |
1910 $dataqs = Array(); |
1910 $dataqs = Array(); |
1911 } |
1911 } |
1912 $datstring = implode($divider, $insert_strings); |
1912 $datstring = implode($divider, $insert_strings); |
1913 } |
1913 } |
1914 if($structure && !$data) return $struct; |
1914 if($structure && !$data) return $struct; |
1915 elseif(!$structure && $data) return $datstring; |
1915 elseif(!$structure && $data) return $datstring; |
1916 elseif($structure && $data) return $struct . $divider . $datstring; |
1916 elseif($structure && $data) return $struct . $divider . $datstring; |
1917 elseif(!$structure && !$data) return ''; |
1917 elseif(!$structure && !$data) return ''; |
1918 } |
1918 } |
1919 |
1919 |
1920 /** |
1920 /** |
1921 * Encodes a string value for use in an INSERT statement for given column type $type. |
1921 * Encodes a string value for use in an INSERT statement for given column type $type. |
1922 * @access private |
1922 * @access private |
1923 */ |
1923 */ |
1924 |
1924 |
1925 function mysql_encode_column($input, $type) |
1925 function mysql_encode_column($input, $type) |
1926 { |
1926 { |
1927 global $db, $session, $paths, $template, $plugins; // Common objects |
1927 global $db, $session, $paths, $template, $plugins; // Common objects |
1928 // Decide whether to quote the string or not |
1928 // Decide whether to quote the string or not |
1929 if(substr($type, 0, 7) == 'varchar' || $type == 'datetime' || $type == 'text' || $type == 'tinytext' || $type == 'smalltext' || $type == 'longtext' || substr($type, 0, 4) == 'char') |
1929 if(substr($type, 0, 7) == 'varchar' || $type == 'datetime' || $type == 'text' || $type == 'tinytext' || $type == 'smalltext' || $type == 'longtext' || substr($type, 0, 4) == 'char') |
1930 { |
1930 { |
1931 $str = "'" . $db->escape($input) . "'"; |
1931 $str = "'" . $db->escape($input) . "'"; |
1932 } |
1932 } |
1933 elseif(in_array($type, Array('blob', 'longblob', 'mediumblob', 'smallblob')) || substr($type, 0, 6) == 'binary' || substr($type, 0, 9) == 'varbinary') |
1933 elseif(in_array($type, Array('blob', 'longblob', 'mediumblob', 'smallblob')) || substr($type, 0, 6) == 'binary' || substr($type, 0, 9) == 'varbinary') |
1934 { |
1934 { |
1935 $str = '0x' . hexencode($input, '', ''); |
1935 $str = '0x' . hexencode($input, '', ''); |
1936 } |
1936 } |
1937 elseif(is_null($input)) |
1937 elseif(is_null($input)) |
1938 { |
1938 { |
1939 $str = 'NULL'; |
1939 $str = 'NULL'; |
1940 } |
1940 } |
1941 else |
1941 else |
1942 { |
1942 { |
1943 $str = (string)$input; |
1943 $str = (string)$input; |
1944 } |
1944 } |
1945 return $str; |
1945 return $str; |
1946 } |
1946 } |
1947 |
1947 |
1948 /** |
1948 /** |
1949 * Creates an associative array defining which file extensions are allowed and which ones aren't |
1949 * Creates an associative array defining which file extensions are allowed and which ones aren't |
1950 * @return array keyname will be a file extension, value will be true or false |
1950 * @return array keyname will be a file extension, value will be true or false |
1951 */ |
1951 */ |
1952 |
1952 |
1953 function fetch_allowed_extensions() |
1953 function fetch_allowed_extensions() |
1954 { |
1954 { |
1955 global $mime_types; |
1955 global $mime_types; |
1956 $bits = getConfig('allowed_mime_types'); |
1956 $bits = getConfig('allowed_mime_types'); |
1957 if(!$bits) return Array(false); |
1957 if(!$bits) return Array(false); |
1958 $bits = uncompress_bitfield($bits); |
1958 $bits = uncompress_bitfield($bits); |
1959 if(!$bits) return Array(false); |
1959 if(!$bits) return Array(false); |
1960 $bits = enano_str_split($bits, 1); |
1960 $bits = enano_str_split($bits, 1); |
1961 $ret = Array(); |
1961 $ret = Array(); |
1962 $mt = array_keys($mime_types); |
1962 $mt = array_keys($mime_types); |
1963 foreach($bits as $i => $b) |
1963 foreach($bits as $i => $b) |
1964 { |
1964 { |
1965 $ret[$mt[$i]] = ( $b == '1' ) ? true : false; |
1965 $ret[$mt[$i]] = ( $b == '1' ) ? true : false; |
1966 } |
1966 } |
1967 return $ret; |
1967 return $ret; |
1968 } |
1968 } |
1969 |
1969 |
1970 /** |
1970 /** |
1971 * Generates a random key suitable for encryption |
1971 * Generates a random key suitable for encryption |
1972 * @param int $len the length of the key |
1972 * @param int $len the length of the key |
1973 * @return string a BINARY key |
1973 * @return string a BINARY key |
1974 */ |
1974 */ |
1975 |
1975 |
1976 function randkey($len = 32) |
1976 function randkey($len = 32) |
1977 { |
1977 { |
1978 $key = ''; |
1978 $key = ''; |
1979 for($i=0;$i<$len;$i++) |
1979 for($i=0;$i<$len;$i++) |
1980 { |
1980 { |
1981 $key .= chr(mt_rand(0, 255)); |
1981 $key .= chr(mt_rand(0, 255)); |
1982 } |
1982 } |
1983 return $key; |
1983 return $key; |
1984 } |
1984 } |
1985 |
1985 |
1986 /** |
1986 /** |
1987 * Decodes a hex string. |
1987 * Decodes a hex string. |
1988 * @param string $hex The hex code to decode |
1988 * @param string $hex The hex code to decode |
1989 * @return string |
1989 * @return string |
1990 */ |
1990 */ |
1991 |
1991 |
1992 function hexdecode($hex) |
1992 function hexdecode($hex) |
1993 { |
1993 { |
1994 $hex = enano_str_split($hex, 2); |
1994 $hex = enano_str_split($hex, 2); |
1995 $bin_key = ''; |
1995 $bin_key = ''; |
1996 foreach($hex as $nibble) |
1996 foreach($hex as $nibble) |
1997 { |
1997 { |
1998 $byte = chr(hexdec($nibble)); |
1998 $byte = chr(hexdec($nibble)); |
1999 $bin_key .= $byte; |
1999 $bin_key .= $byte; |
2000 } |
2000 } |
2001 return $bin_key; |
2001 return $bin_key; |
2002 } |
2002 } |
2003 |
2003 |
2004 /** |
2004 /** |
2005 * Enano's own (almost) bulletproof HTML sanitizer. |
2005 * Enano's own (almost) bulletproof HTML sanitizer. |
2006 * @param string $html The input HTML |
2006 * @param string $html The input HTML |
2007 * @return string cleaned HTML |
2007 * @return string cleaned HTML |
2008 */ |
2008 */ |
2009 |
2009 |
2010 function sanitize_html($html, $filter_php = true) |
2010 function sanitize_html($html, $filter_php = true) |
2011 { |
2011 { |
2012 // Random seed for substitution |
2012 // Random seed for substitution |
2013 $rand_seed = md5( sha1(microtime()) . mt_rand() ); |
2013 $rand_seed = md5( sha1(microtime()) . mt_rand() ); |
2014 |
2014 |
2015 // We need MediaWiki |
2015 // We need MediaWiki |
2016 require_once(ENANO_ROOT . '/includes/wikiengine/TagSanitizer.php'); |
2016 require_once(ENANO_ROOT . '/includes/wikiengine/TagSanitizer.php'); |
2017 |
2017 |
2018 // Strip out comments that are already escaped |
2018 // Strip out comments that are already escaped |
2019 preg_match_all('/<!--(.*?)-->/', $html, $comment_match); |
2019 preg_match_all('/<!--(.*?)-->/', $html, $comment_match); |
2020 $i = 0; |
2020 $i = 0; |
2021 foreach ( $comment_match[0] as $comment ) |
2021 foreach ( $comment_match[0] as $comment ) |
2022 { |
2022 { |
2023 $html = str_replace_once($comment, "{HTMLCOMMENT:$i:$rand_seed}", $html); |
2023 $html = str_replace_once($comment, "{HTMLCOMMENT:$i:$rand_seed}", $html); |
2024 $i++; |
2024 $i++; |
2025 } |
2025 } |
2026 |
2026 |
2027 // Strip out code sections that will be postprocessed by Text_Wiki |
2027 // Strip out code sections that will be postprocessed by Text_Wiki |
2028 preg_match_all(';^<code(\s[^>]*)?>((?:(?R)|.)*?)</code>(\s|$);msi', $html, $code_match); |
2028 preg_match_all(';^<code(\s[^>]*)?>((?:(?R)|.)*?)</code>(\s|$);msi', $html, $code_match); |
2029 $i = 0; |
2029 $i = 0; |
2030 foreach ( $code_match[0] as $code ) |
2030 foreach ( $code_match[0] as $code ) |
2031 { |
2031 { |
2032 $html = str_replace_once($code, "{TW_CODE:$i:$rand_seed}", $html); |
2032 $html = str_replace_once($code, "{TW_CODE:$i:$rand_seed}", $html); |
2033 $i++; |
2033 $i++; |
2034 } |
2034 } |
2035 |
2035 |
2036 $html = preg_replace('#<([a-z]+)([\s]+)([^>]+?)'.htmlalternatives('javascript:').'(.+?)>(.*?)</\\1>#is', '<\\1\\2\\3javascript:\\59>\\60</\\1>', $html); |
2036 $html = preg_replace('#<([a-z]+)([\s]+)([^>]+?)'.htmlalternatives('javascript:').'(.+?)>(.*?)</\\1>#is', '<\\1\\2\\3javascript:\\59>\\60</\\1>', $html); |
2037 $html = preg_replace('#<([a-z]+)([\s]+)([^>]+?)'.htmlalternatives('javascript:').'(.+?)>#is', '<\\1\\2\\3javascript:\\59>', $html); |
2037 $html = preg_replace('#<([a-z]+)([\s]+)([^>]+?)'.htmlalternatives('javascript:').'(.+?)>#is', '<\\1\\2\\3javascript:\\59>', $html); |
2038 |
2038 |
2039 if($filter_php) |
2039 if($filter_php) |
2040 $html = str_replace( |
2040 $html = str_replace( |
2041 Array('<?php', '<?', '<%', '?>', '%>'), |
2041 Array('<?php', '<?', '<%', '?>', '%>'), |
2042 Array('<?php', '<?', '<%', '?>', '%>'), |
2042 Array('<?php', '<?', '<%', '?>', '%>'), |
2043 $html); |
2043 $html); |
2044 |
2044 |
2045 $tag_whitelist = array_keys ( setupAttributeWhitelist() ); |
2045 $tag_whitelist = array_keys ( setupAttributeWhitelist() ); |
2046 if ( !$filter_php ) |
2046 if ( !$filter_php ) |
2047 $tag_whitelist[] = '?php'; |
2047 $tag_whitelist[] = '?php'; |
2048 // allow HTML comments |
2048 // allow HTML comments |
2049 $tag_whitelist[] = '!--'; |
2049 $tag_whitelist[] = '!--'; |
2050 $len = strlen($html); |
2050 $len = strlen($html); |
2051 $in_quote = false; |
2051 $in_quote = false; |
2052 $quote_char = ''; |
2052 $quote_char = ''; |
2053 $tag_start = 0; |
2053 $tag_start = 0; |
2054 $tag_name = ''; |
2054 $tag_name = ''; |
2055 $in_tag = false; |
2055 $in_tag = false; |
2056 $trk_name = false; |
2056 $trk_name = false; |
2057 for ( $i = 0; $i < $len; $i++ ) |
2057 for ( $i = 0; $i < $len; $i++ ) |
2058 { |
2058 { |
2059 $chr = $html{$i}; |
2059 $chr = $html{$i}; |
2060 $prev = ( $i == 0 ) ? '' : $html{ $i - 1 }; |
2060 $prev = ( $i == 0 ) ? '' : $html{ $i - 1 }; |
2061 $next = ( ( $i + 1 ) == $len ) ? '' : $html { $i + 1 }; |
2061 $next = ( ( $i + 1 ) == $len ) ? '' : $html { $i + 1 }; |
2062 if ( $in_quote && $in_tag ) |
2062 if ( $in_quote && $in_tag ) |
2063 { |
2063 { |
2064 if ( $quote_char == $chr && $prev != '\\' ) |
2064 if ( $quote_char == $chr && $prev != '\\' ) |
2065 $in_quote = false; |
2065 $in_quote = false; |
2066 } |
2066 } |
2067 elseif ( ( $chr == '"' || $chr == "'" ) && $prev != '\\' && $in_tag ) |
2067 elseif ( ( $chr == '"' || $chr == "'" ) && $prev != '\\' && $in_tag ) |
2068 { |
2068 { |
2069 $in_quote = true; |
2069 $in_quote = true; |
2070 $quote_char = $chr; |
2070 $quote_char = $chr; |
2071 } |
2071 } |
2072 if ( $chr == '<' && !$in_tag && $next != '/' ) |
2072 if ( $chr == '<' && !$in_tag && $next != '/' ) |
2073 { |
2073 { |
2074 // start of a tag |
2074 // start of a tag |
2075 $tag_start = $i; |
2075 $tag_start = $i; |
2076 $in_tag = true; |
2076 $in_tag = true; |
2077 $trk_name = true; |
2077 $trk_name = true; |
2078 } |
2078 } |
2079 elseif ( !$in_quote && $in_tag && $chr == '>' ) |
2079 elseif ( !$in_quote && $in_tag && $chr == '>' ) |
2080 { |
2080 { |
2081 $full_tag = substr($html, $tag_start, ( $i - $tag_start ) + 1 ); |
2081 $full_tag = substr($html, $tag_start, ( $i - $tag_start ) + 1 ); |
2082 $l = strlen($tag_name) + 2; |
2082 $l = strlen($tag_name) + 2; |
2083 $attribs_only = trim( substr($full_tag, $l, ( strlen($full_tag) - $l - 1 ) ) ); |
2083 $attribs_only = trim( substr($full_tag, $l, ( strlen($full_tag) - $l - 1 ) ) ); |
2084 |
2084 |
2085 // Debugging message |
2085 // Debugging message |
2086 // echo htmlspecialchars($full_tag) . '<br />'; |
2086 // echo htmlspecialchars($full_tag) . '<br />'; |
2087 |
2087 |
2088 if ( !in_array($tag_name, $tag_whitelist) && substr($tag_name, 0, 3) != '!--' ) |
2088 if ( !in_array($tag_name, $tag_whitelist) && substr($tag_name, 0, 3) != '!--' ) |
2089 { |
2089 { |
2090 // Illegal tag |
2090 // Illegal tag |
2091 //echo $tag_name . ' '; |
2091 //echo $tag_name . ' '; |
2092 |
2092 |
2093 $s = ( empty($attribs_only) ) ? '' : ' '; |
2093 $s = ( empty($attribs_only) ) ? '' : ' '; |
2094 |
2094 |
2095 $sanitized = '<' . $tag_name . $s . $attribs_only . '>'; |
2095 $sanitized = '<' . $tag_name . $s . $attribs_only . '>'; |
2096 |
2096 |
2097 $html = substr($html, 0, $tag_start) . $sanitized . substr($html, $i + 1); |
2097 $html = substr($html, 0, $tag_start) . $sanitized . substr($html, $i + 1); |
2098 $html = str_replace('</' . $tag_name . '>', '</' . $tag_name . '>', $html); |
2098 $html = str_replace('</' . $tag_name . '>', '</' . $tag_name . '>', $html); |
2099 $new_i = $tag_start + strlen($sanitized); |
2099 $new_i = $tag_start + strlen($sanitized); |
2100 |
2100 |
2101 $len = strlen($html); |
2101 $len = strlen($html); |
2102 $i = $new_i; |
2102 $i = $new_i; |
2103 |
2103 |
2104 $in_tag = false; |
2104 $in_tag = false; |
2105 $tag_name = ''; |
2105 $tag_name = ''; |
2106 continue; |
2106 continue; |
2107 } |
2107 } |
2108 else |
2108 else |
2109 { |
2109 { |
2110 // If not filtering PHP, don't bother to strip |
2110 // If not filtering PHP, don't bother to strip |
2111 if ( $tag_name == '?php' && !$filter_php ) |
2111 if ( $tag_name == '?php' && !$filter_php ) |
2112 continue; |
2112 continue; |
2113 // If this is a comment, likewise skip this "tag" |
2113 // If this is a comment, likewise skip this "tag" |
2114 if ( $tag_name == '!--' ) |
2114 if ( $tag_name == '!--' ) |
2115 continue; |
2115 continue; |
2116 $f = fixTagAttributes( $attribs_only, $tag_name ); |
2116 $f = fixTagAttributes( $attribs_only, $tag_name ); |
2117 $s = ( empty($f) ) ? '' : ' '; |
2117 $s = ( empty($f) ) ? '' : ' '; |
2118 |
2118 |
2119 $sanitized = '<' . $tag_name . $f . '>'; |
2119 $sanitized = '<' . $tag_name . $f . '>'; |
2120 $new_i = $tag_start + strlen($sanitized); |
2120 $new_i = $tag_start + strlen($sanitized); |
2121 |
2121 |
2122 $html = substr($html, 0, $tag_start) . $sanitized . substr($html, $i + 1); |
2122 $html = substr($html, 0, $tag_start) . $sanitized . substr($html, $i + 1); |
2123 $len = strlen($html); |
2123 $len = strlen($html); |
2124 $i = $new_i; |
2124 $i = $new_i; |
2125 |
2125 |
2126 $in_tag = false; |
2126 $in_tag = false; |
2127 $tag_name = ''; |
2127 $tag_name = ''; |
2128 continue; |
2128 continue; |
2129 } |
2129 } |
2130 } |
2130 } |
2131 elseif ( $in_tag && $trk_name ) |
2131 elseif ( $in_tag && $trk_name ) |
2132 { |
2132 { |
2133 $is_alphabetical = ( strtolower($chr) != strtoupper($chr) || in_array($chr, array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9')) || $chr == '?' || $chr == '!' || $chr == '-' ); |
2133 $is_alphabetical = ( strtolower($chr) != strtoupper($chr) || in_array($chr, array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9')) || $chr == '?' || $chr == '!' || $chr == '-' ); |
2134 if ( $is_alphabetical ) |
2134 if ( $is_alphabetical ) |
2135 $tag_name .= $chr; |
2135 $tag_name .= $chr; |
2136 else |
2136 else |
2137 { |
2137 { |
2138 $trk_name = false; |
2138 $trk_name = false; |
2139 } |
2139 } |
2140 } |
2140 } |
2141 |
2141 |
2142 } |
2142 } |
2143 |
2143 |
2144 // Vulnerability from ha.ckers.org/xss.html: |
2144 // Vulnerability from ha.ckers.org/xss.html: |
2145 // <script src="http://foo.com/xss.js" |
2145 // <script src="http://foo.com/xss.js" |
2146 // < |
2146 // < |
2147 // The rule is so specific because everything else will have been filtered by now |
2147 // The rule is so specific because everything else will have been filtered by now |
2148 $html = preg_replace('/<(script|iframe)(.+?)src=([^>]*)</i', '<\\1\\2src=\\3<', $html); |
2148 $html = preg_replace('/<(script|iframe)(.+?)src=([^>]*)</i', '<\\1\\2src=\\3<', $html); |
2149 |
2149 |
2150 // Vulnerability reported by fuzion from nukeit.org: |
2150 // Vulnerability reported by fuzion from nukeit.org: |
2151 // XSS in closing HTML tag style attribute |
2151 // XSS in closing HTML tag style attribute |
2152 // Fix: escape all closing tags with non-whitelisted characters |
2152 // Fix: escape all closing tags with non-whitelisted characters |
2153 $html = preg_replace('!</((?:[^>]*)([^a-z0-9_:>-]+)(?:[^>]*))>!i', '</\\1>', $html); |
2153 $html = preg_replace('!</((?:[^>]*)([^a-z0-9_:>-]+)(?:[^>]*))>!i', '</\\1>', $html); |
2154 |
2154 |
2155 // Restore stripped comments |
2155 // Restore stripped comments |
2156 $i = 0; |
2156 $i = 0; |
2157 foreach ( $comment_match[0] as $comment ) |
2157 foreach ( $comment_match[0] as $comment ) |
2158 { |
2158 { |
2159 $html = str_replace_once("{HTMLCOMMENT:$i:$rand_seed}", $comment, $html); |
2159 $html = str_replace_once("{HTMLCOMMENT:$i:$rand_seed}", $comment, $html); |
2160 $i++; |
2160 $i++; |
2161 } |
2161 } |
2162 |
2162 |
2163 // Restore stripped code |
2163 // Restore stripped code |
2164 $i = 0; |
2164 $i = 0; |
2165 foreach ( $code_match[0] as $code ) |
2165 foreach ( $code_match[0] as $code ) |
2166 { |
2166 { |
2167 $html = str_replace_once("{TW_CODE:$i:$rand_seed}", $code, $html); |
2167 $html = str_replace_once("{TW_CODE:$i:$rand_seed}", $code, $html); |
2168 $i++; |
2168 $i++; |
2169 } |
2169 } |
2170 |
2170 |
2171 return $html; |
2171 return $html; |
2172 } |
2172 } |
2173 |
2173 |
2174 /** |
2174 /** |
2175 * Using the same parsing code as sanitize_html(), this function adds <litewiki> tags around certain block-level elements |
2175 * Using the same parsing code as sanitize_html(), this function adds <litewiki> tags around certain block-level elements |
2176 * @param string $html The input HTML |
2176 * @param string $html The input HTML |
2178 */ |
2178 */ |
2179 |
2179 |
2180 function wikiformat_process_block($html) |
2180 function wikiformat_process_block($html) |
2181 { |
2181 { |
2182 |
2182 |
2183 $tok1 = "<litewiki>"; |
2183 $tok1 = "<litewiki>"; |
2184 $tok2 = "</litewiki>"; |
2184 $tok2 = "</litewiki>"; |
2185 |
2185 |
2186 $block_tags = array('div', 'p', 'table', 'blockquote', 'pre'); |
2186 $block_tags = array('div', 'p', 'table', 'blockquote', 'pre'); |
2187 |
2187 |
2188 $len = strlen($html); |
2188 $len = strlen($html); |
2189 $in_quote = false; |
2189 $in_quote = false; |
2190 $quote_char = ''; |
2190 $quote_char = ''; |
2191 $tag_start = 0; |
2191 $tag_start = 0; |
2192 $tag_name = ''; |
2192 $tag_name = ''; |
2193 $in_tag = false; |
2193 $in_tag = false; |
2194 $trk_name = false; |
2194 $trk_name = false; |
2195 |
2195 |
2196 $diag = 0; |
2196 $diag = 0; |
2197 |
2197 |
2198 $block_tagname = ''; |
2198 $block_tagname = ''; |
2199 $in_blocksec = 0; |
2199 $in_blocksec = 0; |
2200 $block_start = 0; |
2200 $block_start = 0; |
2201 |
2201 |
2202 for ( $i = 0; $i < $len; $i++ ) |
2202 for ( $i = 0; $i < $len; $i++ ) |
2203 { |
2203 { |
2204 $chr = $html{$i}; |
2204 $chr = $html{$i}; |
2205 $prev = ( $i == 0 ) ? '' : $html{ $i - 1 }; |
2205 $prev = ( $i == 0 ) ? '' : $html{ $i - 1 }; |
2206 $next = ( ( $i + 1 ) == $len ) ? '' : $html { $i + 1 }; |
2206 $next = ( ( $i + 1 ) == $len ) ? '' : $html { $i + 1 }; |
2207 |
2207 |
2208 // Are we inside of a quoted section? |
2208 // Are we inside of a quoted section? |
2209 if ( $in_quote && $in_tag ) |
2209 if ( $in_quote && $in_tag ) |
2210 { |
2210 { |
2211 if ( $quote_char == $chr && $prev != '\\' ) |
2211 if ( $quote_char == $chr && $prev != '\\' ) |
2212 $in_quote = false; |
2212 $in_quote = false; |
2213 } |
2213 } |
2214 elseif ( ( $chr == '"' || $chr == "'" ) && $prev != '\\' && $in_tag ) |
2214 elseif ( ( $chr == '"' || $chr == "'" ) && $prev != '\\' && $in_tag ) |
2215 { |
2215 { |
2216 $in_quote = true; |
2216 $in_quote = true; |
2217 $quote_char = $chr; |
2217 $quote_char = $chr; |
2218 } |
2218 } |
2219 |
2219 |
2220 if ( $chr == '<' && !$in_tag && $next == '/' ) |
2220 if ( $chr == '<' && !$in_tag && $next == '/' ) |
2221 { |
2221 { |
2222 // Iterate through until we've got a tag name |
2222 // Iterate through until we've got a tag name |
2223 $tag_name = ''; |
2223 $tag_name = ''; |
2224 $i++; |
2224 $i++; |
2225 while(true) |
2225 while(true) |
2226 { |
2226 { |
2227 $i++; |
2227 $i++; |
2228 // echo $i . ' '; |
2228 // echo $i . ' '; |
2229 $chr = $html{$i}; |
2229 $chr = $html{$i}; |
2230 $prev = ( $i == 0 ) ? '' : $html{ $i - 1 }; |
2230 $prev = ( $i == 0 ) ? '' : $html{ $i - 1 }; |
2231 $next = ( ( $i + 1 ) == $len ) ? '' : $html { $i + 1 }; |
2231 $next = ( ( $i + 1 ) == $len ) ? '' : $html { $i + 1 }; |
2232 $tag_name .= $chr; |
2232 $tag_name .= $chr; |
2233 if ( $next == '>' ) |
2233 if ( $next == '>' ) |
2234 break; |
2234 break; |
2235 } |
2235 } |
2236 // echo '<br />'; |
2236 // echo '<br />'; |
2237 if ( in_array($tag_name, $block_tags) ) |
2237 if ( in_array($tag_name, $block_tags) ) |
2238 { |
2238 { |
2239 if ( $block_tagname == $tag_name ) |
2239 if ( $block_tagname == $tag_name ) |
2240 { |
2240 { |
2241 $in_blocksec -= 1; |
2241 $in_blocksec -= 1; |
2242 if ( $in_blocksec == 0 ) |
2242 if ( $in_blocksec == 0 ) |
2243 { |
2243 { |
2244 $block_tagname = ''; |
2244 $block_tagname = ''; |
2245 $i += 2; |
2245 $i += 2; |
2246 // echo 'Finished wiki litewiki wraparound calc at pos: ' . $i; |
2246 // echo 'Finished wiki litewiki wraparound calc at pos: ' . $i; |
2247 $full_litewiki = substr($html, $block_start, ( $i - $block_start )); |
2247 $full_litewiki = substr($html, $block_start, ( $i - $block_start )); |
2248 $new_text = "{$tok1}{$full_litewiki}{$tok2}"; |
2248 $new_text = "{$tok1}{$full_litewiki}{$tok2}"; |
2249 $html = substr($html, 0, $block_start) . $new_text . substr($html, $i); |
2249 $html = substr($html, 0, $block_start) . $new_text . substr($html, $i); |
2250 |
2250 |
2251 $i += ( strlen($tok1) + strlen($tok2) ) - 1; |
2251 $i += ( strlen($tok1) + strlen($tok2) ) - 1; |
2252 $len = strlen($html); |
2252 $len = strlen($html); |
2253 |
2253 |
2254 //die('<pre>' . htmlspecialchars($html) . '</pre>'); |
2254 //die('<pre>' . htmlspecialchars($html) . '</pre>'); |
2255 } |
2255 } |
2256 } |
2256 } |
2257 } |
2257 } |
2258 |
2258 |
2259 $in_tag = false; |
2259 $in_tag = false; |
2260 $in_quote = false; |
2260 $in_quote = false; |
2261 $tag_name = ''; |
2261 $tag_name = ''; |
2262 |
2262 |
2263 continue; |
2263 continue; |
2264 } |
2264 } |
2265 else if ( $chr == '<' && !$in_tag && $next != '/' ) |
2265 else if ( $chr == '<' && !$in_tag && $next != '/' ) |
2266 { |
2266 { |
2267 // start of a tag |
2267 // start of a tag |
2268 $tag_start = $i; |
2268 $tag_start = $i; |
2269 $in_tag = true; |
2269 $in_tag = true; |
2270 $trk_name = true; |
2270 $trk_name = true; |
2271 } |
2271 } |
2272 else if ( !$in_quote && $in_tag && $chr == '>' ) |
2272 else if ( !$in_quote && $in_tag && $chr == '>' ) |
2273 { |
2273 { |
2274 if ( !in_array($tag_name, $block_tags) ) |
2274 if ( !in_array($tag_name, $block_tags) ) |
2275 { |
2275 { |
2276 // Inline tag - reset and go to the next one |
2276 // Inline tag - reset and go to the next one |
2277 // echo '<inline ' . $tag_name . '> '; |
2277 // echo '<inline ' . $tag_name . '> '; |
2278 |
2278 |
2279 $in_tag = false; |
2279 $in_tag = false; |
2280 $tag_name = ''; |
2280 $tag_name = ''; |
2281 continue; |
2281 continue; |
2282 } |
2282 } |
2283 else |
2283 else |
2284 { |
2284 { |
2285 // echo '<block: ' . $tag_name . ' @ ' . $i . '><br/>'; |
2285 // echo '<block: ' . $tag_name . ' @ ' . $i . '><br/>'; |
2286 if ( $in_blocksec == 0 ) |
2286 if ( $in_blocksec == 0 ) |
2287 { |
2287 { |
2288 //die('Found a starting tag for a block element: ' . $tag_name . ' at pos ' . $tag_start); |
2288 //die('Found a starting tag for a block element: ' . $tag_name . ' at pos ' . $tag_start); |
2289 $block_tagname = $tag_name; |
2289 $block_tagname = $tag_name; |
2290 $block_start = $tag_start; |
2290 $block_start = $tag_start; |
2291 $in_blocksec++; |
2291 $in_blocksec++; |
2292 } |
2292 } |
2293 else if ( $block_tagname == $tag_name ) |
2293 else if ( $block_tagname == $tag_name ) |
2294 { |
2294 { |
2295 $in_blocksec++; |
2295 $in_blocksec++; |
2296 } |
2296 } |
2297 |
2297 |
2298 $in_tag = false; |
2298 $in_tag = false; |
2299 $tag_name = ''; |
2299 $tag_name = ''; |
2300 continue; |
2300 continue; |
2301 } |
2301 } |
2302 } |
2302 } |
2303 elseif ( $in_tag && $trk_name ) |
2303 elseif ( $in_tag && $trk_name ) |
2304 { |
2304 { |
2305 $is_alphabetical = ( strtolower($chr) != strtoupper($chr) || in_array($chr, array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9')) || $chr == '?' || $chr == '!' || $chr == '-' ); |
2305 $is_alphabetical = ( strtolower($chr) != strtoupper($chr) || in_array($chr, array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9')) || $chr == '?' || $chr == '!' || $chr == '-' ); |
2306 if ( $is_alphabetical ) |
2306 if ( $is_alphabetical ) |
2307 $tag_name .= $chr; |
2307 $tag_name .= $chr; |
2308 else |
2308 else |
2309 { |
2309 { |
2310 $trk_name = false; |
2310 $trk_name = false; |
2311 } |
2311 } |
2312 } |
2312 } |
2313 |
2313 |
2314 // Tokenization complete |
2314 // Tokenization complete |
2315 |
2315 |
2316 } |
2316 } |
2317 |
2317 |
2318 $regex = '/' . str_replace('/', '\\/', preg_quote($tok2)) . '([\s]*)' . preg_quote($tok1) . '/is'; |
2318 $regex = '/' . str_replace('/', '\\/', preg_quote($tok2)) . '([\s]*)' . preg_quote($tok1) . '/is'; |
2319 // die(htmlspecialchars($regex)); |
2319 // die(htmlspecialchars($regex)); |
2320 $html = preg_replace($regex, '\\1', $html); |
2320 $html = preg_replace($regex, '\\1', $html); |
2321 |
2321 |
2322 return $html; |
2322 return $html; |
2323 |
2323 |
2324 } |
2324 } |
2325 |
2325 |
2326 function htmlalternatives($string) |
2326 function htmlalternatives($string) |
2327 { |
2327 { |
2328 $ret = ''; |
2328 $ret = ''; |
2329 for ( $i = 0; $i < strlen($string); $i++ ) |
2329 for ( $i = 0; $i < strlen($string); $i++ ) |
2330 { |
2330 { |
2331 $chr = $string{$i}; |
2331 $chr = $string{$i}; |
2332 $ch1 = ord($chr); |
2332 $ch1 = ord($chr); |
2333 $ch2 = dechex($ch1); |
2333 $ch2 = dechex($ch1); |
2334 $byte = '(&\\#([0]*){0,7}' . $ch1 . ';|\\\\([0]*){0,7}' . $ch1 . ';|\\\\([0]*){0,7}' . $ch2 . ';|&\\#x([0]*){0,7}' . $ch2 . ';|%([0]*){0,7}' . $ch2 . '|' . preg_quote($chr) . ')'; |
2334 $byte = '(&\\#([0]*){0,7}' . $ch1 . ';|\\\\([0]*){0,7}' . $ch1 . ';|\\\\([0]*){0,7}' . $ch2 . ';|&\\#x([0]*){0,7}' . $ch2 . ';|%([0]*){0,7}' . $ch2 . '|' . preg_quote($chr) . ')'; |
2335 $ret .= $byte; |
2335 $ret .= $byte; |
2336 $ret .= '([\s]){0,2}'; |
2336 $ret .= '([\s]){0,2}'; |
2337 } |
2337 } |
2338 return $ret; |
2338 return $ret; |
2339 } |
2339 } |
2340 |
2340 |
2341 /** |
2341 /** |
2342 * Generate HTML for a sprite image. |
2342 * Generate HTML for a sprite image. |
2343 * @param string Path to sprite image |
2343 * @param string Path to sprite image |
2409 * @return string HTML |
2409 * @return string HTML |
2410 */ |
2410 */ |
2411 |
2411 |
2412 function generate_paginator($current_page, $num_pages, $result_url, $start_mult = 1, $start_add = 1) |
2412 function generate_paginator($current_page, $num_pages, $result_url, $start_mult = 1, $start_add = 1) |
2413 { |
2413 { |
2414 global $db, $session, $paths, $template, $plugins; // Common objects |
2414 global $db, $session, $paths, $template, $plugins; // Common objects |
2415 global $lang; |
2415 global $lang; |
2416 |
2416 |
2417 $out = ''; |
2417 $out = ''; |
2418 $i = 0; |
2418 $i = 0; |
2419 |
2419 |
2420 // Build paginator |
2420 // Build paginator |
2421 $pg_css = ( strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') ) ? |
2421 $pg_css = ( strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') ) ? |
2422 // IE-specific hack |
2422 // IE-specific hack |
2423 'display: block; width: 1px;': |
2423 'display: block; width: 1px;': |
2424 // Other browsers |
2424 // Other browsers |
2425 'display: table; margin: 10px 0 0 auto;'; |
2425 'display: table; margin: 10px 0 0 auto;'; |
2426 |
2426 |
2427 $begin = '<div class="tblholder" style="'. $pg_css . '"> |
2427 $begin = '<div class="tblholder" style="'. $pg_css . '"> |
2428 <table border="0" cellspacing="1" cellpadding="4"> |
2428 <table border="0" cellspacing="1" cellpadding="4"> |
2429 <tr><th>' . $lang->get('paginate_lbl_page') . '</th>'; |
2429 <tr><th>' . $lang->get('paginate_lbl_page') . '</th>'; |
2430 $block = '<td class="row1" style="text-align: center;">{LINK}</td>'; |
2430 $block = '<td class="row1" style="text-align: center;">{LINK}</td>'; |
2431 $end = '</tr></table></div>'; |
2431 $end = '</tr></table></div>'; |
2432 $blk = $template->makeParserText($block); |
2432 $blk = $template->makeParserText($block); |
2433 $inner = ''; |
2433 $inner = ''; |
2434 $cls = 'row2'; |
2434 $cls = 'row2'; |
2435 if ( $num_pages < 5 ) |
2435 if ( $num_pages < 5 ) |
2436 { |
2436 { |
2437 for ( $i = 0; $i < $num_pages; $i++ ) |
2437 for ( $i = 0; $i < $num_pages; $i++ ) |
2438 { |
2438 { |
2439 $cls = ( $cls == 'row1' ) ? 'row2' : 'row1'; |
2439 $cls = ( $cls == 'row1' ) ? 'row2' : 'row1'; |
2440 $offset = strval(($i * $start_mult) + $start_add); |
2440 $offset = strval(($i * $start_mult) + $start_add); |
2441 $url = htmlspecialchars(sprintf($result_url, $offset)); |
2441 $url = htmlspecialchars(sprintf($result_url, $offset)); |
2442 $j = $i + 1; |
2442 $j = $i + 1; |
2443 $link = ( $i == $current_page ) ? "<b>$j</b>" : "<a href=".'"'."$url".'"'." style='text-decoration: none;'>$j</a>"; |
2443 $link = ( $i == $current_page ) ? "<b>$j</b>" : "<a href=".'"'."$url".'"'." style='text-decoration: none;'>$j</a>"; |
2444 $blk->assign_vars(array( |
2444 $blk->assign_vars(array( |
2445 'CLASS'=>$cls, |
2445 'CLASS'=>$cls, |
2446 'LINK'=>$link |
2446 'LINK'=>$link |
2447 )); |
2447 )); |
2448 $inner .= $blk->run(); |
2448 $inner .= $blk->run(); |
2449 } |
2449 } |
2450 } |
2450 } |
2451 else |
2451 else |
2452 { |
2452 { |
2453 if ( $current_page + 5 > $num_pages ) |
2453 if ( $current_page + 5 > $num_pages ) |
2454 { |
2454 { |
2455 $list = Array(); |
2455 $list = Array(); |
2456 $tp = $current_page; |
2456 $tp = $current_page; |
2457 if ( $current_page + 0 == $num_pages ) $tp = $tp - 3; |
2457 if ( $current_page + 0 == $num_pages ) $tp = $tp - 3; |
2458 if ( $current_page + 1 == $num_pages ) $tp = $tp - 2; |
2458 if ( $current_page + 1 == $num_pages ) $tp = $tp - 2; |
2459 if ( $current_page + 2 == $num_pages ) $tp = $tp - 1; |
2459 if ( $current_page + 2 == $num_pages ) $tp = $tp - 1; |
2460 for ( $i = $tp - 1; $i <= $tp + 1; $i++ ) |
2460 for ( $i = $tp - 1; $i <= $tp + 1; $i++ ) |
2461 { |
2461 { |
2462 $list[] = $i; |
2462 $list[] = $i; |
2463 } |
2463 } |
2464 } |
2464 } |
2465 else |
2465 else |
2466 { |
2466 { |
2467 $list = Array(); |
2467 $list = Array(); |
2468 $current = $current_page; |
2468 $current = $current_page; |
2469 $lower = ( $current < 3 ) ? 1 : $current - 1; |
2469 $lower = ( $current < 3 ) ? 1 : $current - 1; |
2470 for ( $i = 0; $i < 3; $i++ ) |
2470 for ( $i = 0; $i < 3; $i++ ) |
2471 { |
2471 { |
2472 $list[] = $lower + $i; |
2472 $list[] = $lower + $i; |
2473 } |
2473 } |
2474 } |
2474 } |
2475 $url = sprintf($result_url, $start_add); |
2475 $url = sprintf($result_url, $start_add); |
2476 $link = ( 0 == $current_page ) ? "<b>" . $lang->get('paginate_btn_first') . "</b>" : "<a href=".'"'."$url".'"'." style='text-decoration: none;'>« " . $lang->get('paginate_btn_first') . "</a>"; |
2476 $link = ( 0 == $current_page ) ? "<b>" . $lang->get('paginate_btn_first') . "</b>" : "<a href=".'"'."$url".'"'." style='text-decoration: none;'>« " . $lang->get('paginate_btn_first') . "</a>"; |
2477 $blk->assign_vars(array( |
2477 $blk->assign_vars(array( |
2478 'CLASS'=>$cls, |
2478 'CLASS'=>$cls, |
2479 'LINK'=>$link |
2479 'LINK'=>$link |
2480 )); |
2480 )); |
2481 $inner .= $blk->run(); |
2481 $inner .= $blk->run(); |
2482 |
2482 |
2483 foreach ( $list as $i ) |
2483 foreach ( $list as $i ) |
2484 { |
2484 { |
2485 if ( $i == $num_pages ) |
2485 if ( $i == $num_pages ) |
2486 break; |
2486 break; |
2487 $cls = ( $cls == 'row1' ) ? 'row2' : 'row1'; |
2487 $cls = ( $cls == 'row1' ) ? 'row2' : 'row1'; |
2488 $offset = strval(($i * $start_mult) + $start_add); |
2488 $offset = strval(($i * $start_mult) + $start_add); |
2489 $url = sprintf($result_url, $offset); |
2489 $url = sprintf($result_url, $offset); |
2490 $j = $i + 1; |
2490 $j = $i + 1; |
2491 $link = ( $i == $current_page ) ? "<b>$j</b>" : "<a href=".'"'."$url".'"'." style='text-decoration: none;'>$j</a>"; |
2491 $link = ( $i == $current_page ) ? "<b>$j</b>" : "<a href=".'"'."$url".'"'." style='text-decoration: none;'>$j</a>"; |
2492 $blk->assign_vars(array( |
2492 $blk->assign_vars(array( |
2493 'CLASS'=>$cls, |
2493 'CLASS'=>$cls, |
2494 'LINK'=>$link |
2494 'LINK'=>$link |
2495 )); |
2495 )); |
2496 $inner .= $blk->run(); |
2496 $inner .= $blk->run(); |
2497 } |
2497 } |
2498 |
2498 |
2499 // "Last" button |
2499 // "Last" button |
2500 $total = (($num_pages - 1) * $start_mult) + $start_add; |
2500 $total = (($num_pages - 1) * $start_mult) + $start_add; |
2501 |
2501 |
2502 if ( $current_page < $num_pages ) |
2502 if ( $current_page < $num_pages ) |
2503 { |
2503 { |
2504 $cls = ( $cls == 'row1' ) ? 'row2' : 'row1'; |
2504 $cls = ( $cls == 'row1' ) ? 'row2' : 'row1'; |
2505 $offset = strval($total); |
2505 $offset = strval($total); |
2506 $url = sprintf($result_url, $offset); |
2506 $url = sprintf($result_url, $offset); |
2507 $link = ( $num_pages - 1 == $current_page ) ? "<b>" . $lang->get('paginate_btn_last') . "</b>" : "<a href=".'"'."$url".'"'." style='text-decoration: none;'>" . $lang->get('paginate_btn_last') . " »</a>"; |
2507 $link = ( $num_pages - 1 == $current_page ) ? "<b>" . $lang->get('paginate_btn_last') . "</b>" : "<a href=".'"'."$url".'"'." style='text-decoration: none;'>" . $lang->get('paginate_btn_last') . " »</a>"; |
2508 $blk->assign_vars(array( |
2508 $blk->assign_vars(array( |
2509 'CLASS'=>$cls, |
2509 'CLASS'=>$cls, |
2510 'LINK'=>$link |
2510 'LINK'=>$link |
2511 )); |
2511 )); |
2512 $inner .= $blk->run(); |
2512 $inner .= $blk->run(); |
2513 } |
2513 } |
2514 |
2514 |
2515 } |
2515 } |
2516 |
2516 |
2517 $inner .= '<td class="row2" style="cursor: pointer;" onclick="paginator_goto(this, '.$current_page.', '.$num_pages.', '.$start_mult.', '.$start_add.', unescape(\'' . rawurlencode($result_url) . '\'));">↓</td>'; |
2517 $inner .= '<td class="row2" style="cursor: pointer;" onclick="paginator_goto(this, '.$current_page.', '.$num_pages.', '.$start_mult.', '.$start_add.', unescape(\'' . rawurlencode($result_url) . '\'));">↓</td>'; |
2518 |
2518 |
2519 $paginator = "\n$begin$inner$end\n"; |
2519 $paginator = "\n$begin$inner$end\n"; |
2520 return $paginator; |
2520 return $paginator; |
2521 } |
2521 } |
2522 |
2522 |
2523 /** |
2523 /** |
2524 * Paginates (breaks into multiple pages) a MySQL result resource, which is treated as unbuffered. |
2524 * Paginates (breaks into multiple pages) a MySQL result resource, which is treated as unbuffered. |
2525 * @param resource The MySQL result resource. This should preferably be an unbuffered query. |
2525 * @param resource The MySQL result resource. This should preferably be an unbuffered query. |
2605 * @return string |
2605 * @return string |
2606 */ |
2606 */ |
2607 |
2607 |
2608 function paginate_array($q, $num_results, $result_url, $start = 0, $perpage = 10, $header = '', $footer = '') |
2608 function paginate_array($q, $num_results, $result_url, $start = 0, $perpage = 10, $header = '', $footer = '') |
2609 { |
2609 { |
2610 global $db, $session, $paths, $template, $plugins; // Common objects |
2610 global $db, $session, $paths, $template, $plugins; // Common objects |
2611 global $lang; |
2611 global $lang; |
2612 |
2612 |
2613 $num_pages = ceil ( $num_results / $perpage ); |
2613 $num_pages = ceil ( $num_results / $perpage ); |
2614 $out = ''; |
2614 $out = ''; |
2615 $i = 0; |
2615 $i = 0; |
2616 $this_page = ceil ( $start / $perpage ); |
2616 $this_page = ceil ( $start / $perpage ); |
2617 |
2617 |
2618 $paginator = generate_paginator($this_page, $num_pages, $result_url, $perpage, 0); |
2618 $paginator = generate_paginator($this_page, $num_pages, $result_url, $perpage, 0); |
2619 |
2619 |
2620 if ( $num_results > 1 ) |
2620 if ( $num_results > 1 ) |
2621 { |
2621 { |
2622 $out .= $paginator; |
2622 $out .= $paginator; |
2623 } |
2623 } |
2624 |
2624 |
2625 $cls = 'row2'; |
2625 $cls = 'row2'; |
2626 |
2626 |
2627 if ( sizeof($q) > 0 ) |
2627 if ( sizeof($q) > 0 ) |
2628 { |
2628 { |
2629 $i = 0; |
2629 $i = 0; |
2630 $out .= $header; |
2630 $out .= $header; |
2631 foreach ( $q as $val ) { |
2631 foreach ( $q as $val ) { |
2632 $i++; |
2632 $i++; |
2633 if ( $i <= $start ) |
2633 if ( $i <= $start ) |
2634 { |
2634 { |
2635 continue; |
2635 continue; |
2636 } |
2636 } |
2637 if ( ( $i - $start ) > $perpage ) |
2637 if ( ( $i - $start ) > $perpage ) |
2638 { |
2638 { |
2639 break; |
2639 break; |
2640 } |
2640 } |
2641 $out .= $val; |
2641 $out .= $val; |
2642 } |
2642 } |
2643 $out .= $footer; |
2643 $out .= $footer; |
2644 } |
2644 } |
2645 |
2645 |
2646 if ( $num_results > 1 ) |
2646 if ( $num_results > 1 ) |
2647 $out .= $paginator; |
2647 $out .= $paginator; |
2648 |
2648 |
2649 return $out; |
2649 return $out; |
2650 } |
2650 } |
2651 |
2651 |
2652 /** |
2652 /** |
2653 * Enano version of fputs for debugging |
2653 * Enano version of fputs for debugging |
2654 */ |
2654 */ |
2655 |
2655 |
2656 function enano_fputs($socket, $data) |
2656 function enano_fputs($socket, $data) |
2657 { |
2657 { |
2658 // echo '<pre>' . htmlspecialchars($data) . '</pre>'; |
2658 // echo '<pre>' . htmlspecialchars($data) . '</pre>'; |
2659 // flush(); |
2659 // flush(); |
2660 // ob_flush(); |
2660 // ob_flush(); |
2661 // ob_end_flush(); |
2661 // ob_end_flush(); |
2662 return fputs($socket, $data); |
2662 return fputs($socket, $data); |
2663 } |
2663 } |
2664 |
2664 |
2665 /** |
2665 /** |
2666 * Sanitizes a page URL string so that it can safely be stored in the database. |
2666 * Sanitizes a page URL string so that it can safely be stored in the database. |
2667 * @param string Page ID to sanitize |
2667 * @param string Page ID to sanitize |
2668 * @return string Cleaned text |
2668 * @return string Cleaned text |
2669 */ |
2669 */ |
2670 |
2670 |
2671 function sanitize_page_id($page_id) |
2671 function sanitize_page_id($page_id) |
2672 { |
2672 { |
2673 global $db, $session, $paths, $template, $plugins; // Common objects |
2673 global $db, $session, $paths, $template, $plugins; // Common objects |
2674 |
2674 |
2675 if ( isset($paths->nslist['User']) ) |
2675 if ( isset($paths->nslist['User']) ) |
2676 { |
2676 { |
2677 if ( preg_match('/^' . str_replace('/', '\\/', preg_quote($paths->nslist['User'])) . '/', $page_id) ) |
2677 if ( preg_match('/^' . str_replace('/', '\\/', preg_quote($paths->nslist['User'])) . '/', $page_id) ) |
2678 { |
2678 { |
2679 $ip = preg_replace('/^' . str_replace('/', '\\/', preg_quote($paths->nslist['User'])) . '/', '', $page_id); |
2679 $ip = preg_replace('/^' . str_replace('/', '\\/', preg_quote($paths->nslist['User'])) . '/', '', $page_id); |
2680 if ( is_valid_ip($ip) ) |
2680 if ( is_valid_ip($ip) ) |
2681 { |
2681 { |
2682 return $page_id; |
2682 return $page_id; |
2683 } |
2683 } |
2684 } |
2684 } |
2685 } |
2685 } |
2686 |
2686 |
2687 if ( empty($page_id) ) |
2687 if ( empty($page_id) ) |
2688 return ''; |
2688 return ''; |
2689 |
2689 |
2690 // Remove character escapes |
2690 // Remove character escapes |
2691 $page_id = dirtify_page_id($page_id); |
2691 $page_id = dirtify_page_id($page_id); |
2692 |
2692 |
2693 $pid_clean = preg_replace('/[\w\.\/:;\(\)@\[\]=_-]/', 'X', $page_id); |
2693 $pid_clean = preg_replace('/[\w\.\/:;\(\)@\[\]=_-]/', 'X', $page_id); |
2694 $pid_dirty = enano_str_split($pid_clean, 1); |
2694 $pid_dirty = enano_str_split($pid_clean, 1); |
2695 |
2695 |
2696 foreach ( $pid_dirty as $id => $char ) |
2696 foreach ( $pid_dirty as $id => $char ) |
2697 { |
2697 { |
2698 if ( $char == 'X' ) |
2698 if ( $char == 'X' ) |
2699 continue; |
2699 continue; |
2700 $cid = ord($char); |
2700 $cid = ord($char); |
2701 $cid = dechex($cid); |
2701 $cid = dechex($cid); |
2702 $cid = strval($cid); |
2702 $cid = strval($cid); |
2703 if ( strlen($cid) < 2 ) |
2703 if ( strlen($cid) < 2 ) |
2704 { |
2704 { |
2705 $cid = strtoupper("0$cid"); |
2705 $cid = strtoupper("0$cid"); |
2706 } |
2706 } |
2707 $pid_dirty[$id] = ".$cid"; |
2707 $pid_dirty[$id] = ".$cid"; |
2708 } |
2708 } |
2709 |
2709 |
2710 $pid_chars = enano_str_split($page_id, 1); |
2710 $pid_chars = enano_str_split($page_id, 1); |
2711 $page_id_cleaned = ''; |
2711 $page_id_cleaned = ''; |
2712 |
2712 |
2713 foreach ( $pid_chars as $id => $char ) |
2713 foreach ( $pid_chars as $id => $char ) |
2714 { |
2714 { |
2715 if ( $pid_dirty[$id] == 'X' ) |
2715 if ( $pid_dirty[$id] == 'X' ) |
2716 $page_id_cleaned .= $char; |
2716 $page_id_cleaned .= $char; |
2717 else |
2717 else |
2718 $page_id_cleaned .= $pid_dirty[$id]; |
2718 $page_id_cleaned .= $pid_dirty[$id]; |
2719 } |
2719 } |
2720 |
2720 |
2721 // global $mime_types; |
2721 // global $mime_types; |
2722 |
2722 |
2723 // $exts = array_keys($mime_types); |
2723 // $exts = array_keys($mime_types); |
2724 // $exts = '(' . implode('|', $exts) . ')'; |
2724 // $exts = '(' . implode('|', $exts) . ')'; |
2725 |
2725 |
2726 // $page_id_cleaned = preg_replace('/\.2e' . $exts . '$/', '.\\1', $page_id_cleaned); |
2726 // $page_id_cleaned = preg_replace('/\.2e' . $exts . '$/', '.\\1', $page_id_cleaned); |
2727 |
2727 |
2728 return $page_id_cleaned; |
2728 return $page_id_cleaned; |
2729 } |
2729 } |
2730 |
2730 |
2731 /** |
2731 /** |
2732 * Removes character escapes in a page ID string |
2732 * Removes character escapes in a page ID string |
2733 * @param string Page ID string to dirty up |
2733 * @param string Page ID string to dirty up |
2734 * @return string |
2734 * @return string |
2735 */ |
2735 */ |
2736 |
2736 |
2737 function dirtify_page_id($page_id) |
2737 function dirtify_page_id($page_id) |
2738 { |
2738 { |
2739 global $db, $session, $paths, $template, $plugins; // Common objects |
2739 global $db, $session, $paths, $template, $plugins; // Common objects |
2740 // First, replace spaces with underscores |
2740 // First, replace spaces with underscores |
2741 $page_id = str_replace(' ', '_', $page_id); |
2741 $page_id = str_replace(' ', '_', $page_id); |
2742 |
2742 |
2743 // Exception for userpages for IP addresses |
2743 // Exception for userpages for IP addresses |
2744 $pid_ip_check = ( is_object($paths) ) ? preg_replace('+^' . preg_quote($paths->nslist['User']) . '+', '', $page_id) : $page_id; |
2744 $pid_ip_check = ( is_object($paths) ) ? preg_replace('+^' . preg_quote($paths->nslist['User']) . '+', '', $page_id) : $page_id; |
2745 if ( is_valid_ip($pid_ip_check) ) |
2745 if ( is_valid_ip($pid_ip_check) ) |
2746 { |
2746 { |
2747 return $page_id; |
2747 return $page_id; |
2748 } |
2748 } |
2749 |
2749 |
2750 preg_match_all('/\.[a-f0-9][a-f0-9]/', $page_id, $matches); |
2750 preg_match_all('/\.[a-f0-9][a-f0-9]/', $page_id, $matches); |
2751 |
2751 |
2752 foreach ( $matches[0] as $id => $char ) |
2752 foreach ( $matches[0] as $id => $char ) |
2753 { |
2753 { |
2754 $char = substr($char, 1); |
2754 $char = substr($char, 1); |
2755 $char = strtolower($char); |
2755 $char = strtolower($char); |
2756 $char = intval(hexdec($char)); |
2756 $char = intval(hexdec($char)); |
2757 $char = chr($char); |
2757 $char = chr($char); |
2758 if ( preg_match('/^[\w\.\/:;\(\)@\[\]=_-]$/', $char) ) |
2758 if ( preg_match('/^[\w\.\/:;\(\)@\[\]=_-]$/', $char) ) |
2759 continue; |
2759 continue; |
2760 $page_id = str_replace($matches[0][$id], $char, $page_id); |
2760 $page_id = str_replace($matches[0][$id], $char, $page_id); |
2761 } |
2761 } |
2762 |
2762 |
2763 return $page_id; |
2763 return $page_id; |
2764 } |
2764 } |
2765 |
2765 |
2766 /** |
2766 /** |
2767 * Inserts commas into a number to make it more human-readable. Floating point-safe and doesn't flirt with the number like number_format() does. |
2767 * Inserts commas into a number to make it more human-readable. Floating point-safe and doesn't flirt with the number like number_format() does. |
2768 * @param int The number to process |
2768 * @param int The number to process |
2769 * @return string Input number with commas added |
2769 * @return string Input number with commas added |
2770 */ |
2770 */ |
2771 |
2771 |
2772 function commatize($num) |
2772 function commatize($num) |
2773 { |
2773 { |
2774 $num = (string)$num; |
2774 $num = (string)$num; |
2775 if ( strpos($num, '.') ) |
2775 if ( strpos($num, '.') ) |
2776 { |
2776 { |
2777 $whole = explode('.', $num); |
2777 $whole = explode('.', $num); |
2778 $num = $whole[0]; |
2778 $num = $whole[0]; |
2779 $dec = $whole[1]; |
2779 $dec = $whole[1]; |
2780 } |
2780 } |
2781 else |
2781 else |
2782 { |
2782 { |
2783 $whole = $num; |
2783 $whole = $num; |
2784 } |
2784 } |
2785 $offset = ( strlen($num) ) % 3; |
2785 $offset = ( strlen($num) ) % 3; |
2786 $len = strlen($num); |
2786 $len = strlen($num); |
2787 $offset = ( $offset == 0 ) |
2787 $offset = ( $offset == 0 ) |
2788 ? 3 |
2788 ? 3 |
2789 : $offset; |
2789 : $offset; |
2790 for ( $i = $offset; $i < $len; $i=$i+3 ) |
2790 for ( $i = $offset; $i < $len; $i=$i+3 ) |
2791 { |
2791 { |
2792 $num = substr($num, 0, $i) . ',' . substr($num, $i, $len); |
2792 $num = substr($num, 0, $i) . ',' . substr($num, $i, $len); |
2793 $len = strlen($num); |
2793 $len = strlen($num); |
2794 $i++; |
2794 $i++; |
2795 } |
2795 } |
2796 if ( isset($dec) ) |
2796 if ( isset($dec) ) |
2797 { |
2797 { |
2798 return $num . '.' . $dec; |
2798 return $num . '.' . $dec; |
2799 } |
2799 } |
2800 else |
2800 else |
2801 { |
2801 { |
2802 return $num; |
2802 return $num; |
2803 } |
2803 } |
2804 } |
2804 } |
2805 |
2805 |
2806 /** |
2806 /** |
2807 * Converts a number to a human file size. |
2807 * Converts a number to a human file size. |
2808 * @param int File size |
2808 * @param int File size |
2809 * @return string |
2809 * @return string |
2810 */ |
2810 */ |
2811 |
2811 |
2812 function humanize_filesize($size) |
2812 function humanize_filesize($size) |
2813 { |
2813 { |
2814 global $lang; |
2814 global $lang; |
2815 |
2815 |
2816 if ( $size > ( 1099511627776 * 0.9 ) ) |
2816 if ( $size > ( 1099511627776 * 0.9 ) ) |
2817 { |
2817 { |
2818 return number_format($size / 1099511627776, 1) . $lang->get('etc_unit_terabytes_short'); |
2818 return number_format($size / 1099511627776, 1) . $lang->get('etc_unit_terabytes_short'); |
2819 } |
2819 } |
2820 if ( $size > ( 1073741824 * 0.9 ) ) |
2820 if ( $size > ( 1073741824 * 0.9 ) ) |
2821 { |
2821 { |
2822 return number_format($size / 1073741824, 1) . $lang->get('etc_unit_gigabytes_short'); |
2822 return number_format($size / 1073741824, 1) . $lang->get('etc_unit_gigabytes_short'); |
2823 } |
2823 } |
2824 if ( $size > ( 1048576 * 0.9 ) ) |
2824 if ( $size > ( 1048576 * 0.9 ) ) |
2825 { |
2825 { |
2826 return number_format($size / 1048576, 1) . $lang->get('etc_unit_megabytes_short'); |
2826 return number_format($size / 1048576, 1) . $lang->get('etc_unit_megabytes_short'); |
2827 } |
2827 } |
2828 if ( $size > ( 1024 * 0.9 ) ) |
2828 if ( $size > ( 1024 * 0.9 ) ) |
2829 { |
2829 { |
2830 return number_format($size / 1024, 1) . $lang->get('etc_unit_kilobytes_short'); |
2830 return number_format($size / 1024, 1) . $lang->get('etc_unit_kilobytes_short'); |
2831 } |
2831 } |
2832 return "$size " . $lang->get('etc_unit_bytes'); |
2832 return "$size " . $lang->get('etc_unit_bytes'); |
2833 } |
2833 } |
2834 |
2834 |
2835 /** |
2835 /** |
2836 * Injects a string into another string at the specified position. |
2836 * Injects a string into another string at the specified position. |
2837 * @param string The haystack |
2837 * @param string The haystack |
2959 * a fully formatted and sanitized blob of HTML. If formatcallback is a TPL string, variables will be named after table |
2959 * a fully formatted and sanitized blob of HTML. If formatcallback is a TPL string, variables will be named after table |
2960 * columns. |
2960 * columns. |
2961 * - additionalwhere: additional SQL to inject into WHERE clause, in the format of "AND foo = bar" |
2961 * - additionalwhere: additional SQL to inject into WHERE clause, in the format of "AND foo = bar" |
2962 * @example Working example of adding users to search results: |
2962 * @example Working example of adding users to search results: |
2963 <code> |
2963 <code> |
2964 register_search_handler(array( |
2964 register_search_handler(array( |
2965 'table' => 'users', |
2965 'table' => 'users', |
2966 'titlecolumn' => 'username', |
2966 'titlecolumn' => 'username', |
2967 'uniqueid' => 'ns=User;cid={username}', |
2967 'uniqueid' => 'ns=User;cid={username}', |
2968 'additionalcolumns' => array('user_id'), |
2968 'additionalcolumns' => array('user_id'), |
2969 'resultnote' => '[Member]', |
2969 'resultnote' => '[Member]', |
2970 'linkformat' => array( |
2970 'linkformat' => array( |
2971 'page_id' => '{username}', |
2971 'page_id' => '{username}', |
2972 'namespace' => 'User' |
2972 'namespace' => 'User' |
2973 ), |
2973 ), |
2974 'formatcallback' => 'format_user_search_result', |
2974 'formatcallback' => 'format_user_search_result', |
2975 )); |
2975 )); |
2976 |
2976 |
2977 function format_user_search_result($row) |
2977 function format_user_search_result($row) |
2978 { |
2978 { |
2979 global $session, $lang; |
2979 global $session, $lang; |
2980 $rankdata = $session->get_user_rank(intval($row['user_id'])); |
2980 $rankdata = $session->get_user_rank(intval($row['user_id'])); |
2981 $rankspan = '<span style="' . $rankdata['rank_style'] . '">' . $lang->get($rankdata['rank_title']) . '</span>'; |
2981 $rankspan = '<span style="' . $rankdata['rank_style'] . '">' . $lang->get($rankdata['rank_title']) . '</span>'; |
2982 if ( empty($rankdata['user_title']) ) |
2982 if ( empty($rankdata['user_title']) ) |
2983 { |
2983 { |
2984 return $rankspan; |
2984 return $rankspan; |
2985 } |
2985 } |
2986 else |
2986 else |
2987 { |
2987 { |
2988 return '"' . htmlspecialchars($rankdata['user_title']) . "\" (<b>$rankspan</b>)"; |
2988 return '"' . htmlspecialchars($rankdata['user_title']) . "\" (<b>$rankspan</b>)"; |
2989 } |
2989 } |
2990 } |
2990 } |
2991 </code> |
2991 </code> |
2992 * @param array Options array - see function documentation |
2992 * @param array Options array - see function documentation |
2993 * @return null |
2993 * @return null |
2994 */ |
2994 */ |
2995 |
2995 |
2996 global $search_handlers; |
2996 global $search_handlers; |
2997 $search_handlers = array(); |
2997 $search_handlers = array(); |
2998 |
2998 |
2999 function register_search_handler($options) |
2999 function register_search_handler($options) |
3000 { |
3000 { |
3001 global $search_handlers; |
3001 global $search_handlers; |
3002 |
3002 |
3003 $required = array('table', 'titlecolumn', 'uniqueid', 'linkformat'); |
3003 $required = array('table', 'titlecolumn', 'uniqueid', 'linkformat'); |
3004 foreach ( $required as $key ) |
3004 foreach ( $required as $key ) |
3005 { |
3005 { |
3006 if ( !isset($options[$key]) ) |
3006 if ( !isset($options[$key]) ) |
3007 { |
3007 { |
3008 throw new Exception("Required search handler option '$key' is missing"); |
3008 throw new Exception("Required search handler option '$key' is missing"); |
3009 } |
3009 } |
3010 } |
3010 } |
3011 $search_handlers[] = $options; |
3011 $search_handlers[] = $options; |
3012 return null; |
3012 return null; |
3013 } |
3013 } |
3014 |
3014 |
3015 /** |
3015 /** |
3016 * From http://us2.php.net/urldecode - decode %uXXXX |
3016 * From http://us2.php.net/urldecode - decode %uXXXX |
3017 * @param string The urlencoded string |
3017 * @param string The urlencoded string |
3018 * @return string |
3018 * @return string |
3019 */ |
3019 */ |
3020 |
3020 |
3021 function decode_unicode_url($str) |
3021 function decode_unicode_url($str) |
3022 { |
3022 { |
3023 $res = ''; |
3023 $res = ''; |
3024 |
3024 |
3025 $i = 0; |
3025 $i = 0; |
3026 $max = strlen($str) - 6; |
3026 $max = strlen($str) - 6; |
3027 while ($i <= $max) |
3027 while ($i <= $max) |
3028 { |
3028 { |
3029 $character = $str[$i]; |
3029 $character = $str[$i]; |
3030 if ($character == '%' && $str[$i + 1] == 'u') |
3030 if ($character == '%' && $str[$i + 1] == 'u') |
3031 { |
3031 { |
3032 if ( !preg_match('/^([a-f0-9]{2})+$/', substr($str, $i + 2, 4)) ) |
3032 if ( !preg_match('/^([a-f0-9]{2})+$/', substr($str, $i + 2, 4)) ) |
3033 { |
3033 { |
3034 $res .= substr($str, $i, 6); |
3034 $res .= substr($str, $i, 6); |
3035 $i += 6; |
3035 $i += 6; |
3036 continue; |
3036 continue; |
3037 } |
3037 } |
3038 |
3038 |
3039 $value = hexdec(substr($str, $i + 2, 4)); |
3039 $value = hexdec(substr($str, $i + 2, 4)); |
3040 $i += 6; |
3040 $i += 6; |
3041 |
3041 |
3042 if ($value < 0x0080) |
3042 if ($value < 0x0080) |
3043 { |
3043 { |
3044 // 1 byte: 0xxxxxxx |
3044 // 1 byte: 0xxxxxxx |
3045 $character = chr($value); |
3045 $character = chr($value); |
3046 } |
3046 } |
3047 else if ($value < 0x0800) |
3047 else if ($value < 0x0800) |
3048 { |
3048 { |
3049 // 2 bytes: 110xxxxx 10xxxxxx |
3049 // 2 bytes: 110xxxxx 10xxxxxx |
3050 $character = |
3050 $character = |
3051 chr((($value & 0x07c0) >> 6) | 0xc0) |
3051 chr((($value & 0x07c0) >> 6) | 0xc0) |
3052 . chr(($value & 0x3f) | 0x80); |
3052 . chr(($value & 0x3f) | 0x80); |
3053 } |
3053 } |
3054 else |
3054 else |
3055 { |
3055 { |
3056 // 3 bytes: 1110xxxx 10xxxxxx 10xxxxxx |
3056 // 3 bytes: 1110xxxx 10xxxxxx 10xxxxxx |
3057 $character = |
3057 $character = |
3058 chr((($value & 0xf000) >> 12) | 0xe0) |
3058 chr((($value & 0xf000) >> 12) | 0xe0) |
3059 . chr((($value & 0x0fc0) >> 6) | 0x80) |
3059 . chr((($value & 0x0fc0) >> 6) | 0x80) |
3060 . chr(($value & 0x3f) | 0x80); |
3060 . chr(($value & 0x3f) | 0x80); |
3061 } |
3061 } |
3062 } |
3062 } |
3063 else |
3063 else |
3064 { |
3064 { |
3065 $i++; |
3065 $i++; |
3066 } |
3066 } |
3067 |
3067 |
3068 $res .= $character; |
3068 $res .= $character; |
3069 } |
3069 } |
3070 |
3070 |
3071 return $res . substr($str, $i); |
3071 return $res . substr($str, $i); |
3072 } |
3072 } |
3073 |
3073 |
3074 /** |
3074 /** |
3075 * Recursively decodes an array with UTF-8 characters in its strings |
3075 * Recursively decodes an array with UTF-8 characters in its strings |
3076 * @param array Can be multi-depth |
3076 * @param array Can be multi-depth |
3077 * @return array |
3077 * @return array |
3078 */ |
3078 */ |
3079 |
3079 |
3080 function decode_unicode_array($array) |
3080 function decode_unicode_array($array) |
3081 { |
3081 { |
3082 foreach ( $array as $i => $val ) |
3082 foreach ( $array as $i => $val ) |
3083 { |
3083 { |
3084 if ( is_string($val) ) |
3084 if ( is_string($val) ) |
3085 { |
3085 { |
3086 $array[$i] = decode_unicode_url($val); |
3086 $array[$i] = decode_unicode_url($val); |
3087 } |
3087 } |
3088 else if ( is_array($val) ) |
3088 else if ( is_array($val) ) |
3089 { |
3089 { |
3090 $array[$i] = decode_unicode_array($val); |
3090 $array[$i] = decode_unicode_array($val); |
3091 } |
3091 } |
3092 } |
3092 } |
3093 return $array; |
3093 return $array; |
3094 } |
3094 } |
3095 |
3095 |
3096 /** |
3096 /** |
3097 * Sanitizes a page tag. |
3097 * Sanitizes a page tag. |
3098 * @param string |
3098 * @param string |
3099 * @return string |
3099 * @return string |
3100 */ |
3100 */ |
3101 |
3101 |
3102 function sanitize_tag($tag) |
3102 function sanitize_tag($tag) |
3103 { |
3103 { |
3104 $tag = strtolower($tag); |
3104 $tag = strtolower($tag); |
3105 $tag = preg_replace('/[^\w @\$%\^&-]+/', '', $tag); |
3105 $tag = preg_replace('/[^\w @\$%\^&-]+/', '', $tag); |
3106 $tag = str_replace('_', ' ', $tag); |
3106 $tag = str_replace('_', ' ', $tag); |
3107 $tag = trim($tag); |
3107 $tag = trim($tag); |
3108 return $tag; |
3108 return $tag; |
3109 } |
3109 } |
3110 |
3110 |
3111 /** |
3111 /** |
3112 * Replacement for gzencode() which doesn't always work. |
3112 * Replacement for gzencode() which doesn't always work. |
3113 * @param string Data to compress |
3113 * @param string Data to compress |
3140 * @access private |
3140 * @access private |
3141 */ |
3141 */ |
3142 |
3142 |
3143 function enano_handle_error($errno, $errstr, $errfile, $errline) |
3143 function enano_handle_error($errno, $errstr, $errfile, $errline) |
3144 { |
3144 { |
3145 global $db, $session, $paths, $template, $plugins; // Common objects |
3145 global $db, $session, $paths, $template, $plugins; // Common objects |
3146 |
3146 |
3147 $er = error_reporting(); |
3147 $er = error_reporting(); |
3148 if ( ! $er & $errno || $er == 0 ) |
3148 if ( ! $er & $errno || $er == 0 ) |
3149 { |
3149 { |
3150 return true; |
3150 return true; |
3151 } |
3151 } |
3152 global $do_gzip, $php_errors; |
3152 global $do_gzip, $php_errors; |
3153 |
3153 |
3154 if ( defined('ENANO_DEBUG') ) |
3154 if ( defined('ENANO_DEBUG') ) |
3155 { |
3155 { |
3156 // turn off gzip and echo out error immediately for debug installs |
3156 // turn off gzip and echo out error immediately for debug installs |
3157 $do_gzip = false; |
3157 $do_gzip = false; |
3158 } |
3158 } |
3159 |
3159 |
3160 $error_type = 'error'; |
3160 $error_type = 'error'; |
3161 if ( in_array($errno, array(E_WARNING, E_USER_WARNING)) ) |
3161 if ( in_array($errno, array(E_WARNING, E_USER_WARNING)) ) |
3162 $error_type = 'warning'; |
3162 $error_type = 'warning'; |
3163 else if ( in_array($errno, array(E_NOTICE, E_USER_NOTICE)) ) |
3163 else if ( in_array($errno, array(E_NOTICE, E_USER_NOTICE)) ) |
3164 $error_type = 'notice'; |
3164 $error_type = 'notice'; |
3165 |
3165 |
3166 if ( @is_object(@$plugins) ) |
3166 if ( @is_object(@$plugins) ) |
3167 { |
3167 { |
3168 $code = $plugins->setHook('php_error'); |
3168 $code = $plugins->setHook('php_error'); |
3169 foreach ( $code as $cmd ) |
3169 foreach ( $code as $cmd ) |
3170 { |
3170 { |
3171 eval($cmd); |
3171 eval($cmd); |
3172 } |
3172 } |
3173 } |
3173 } |
3174 |
3174 |
3175 // bypass errors in date() and mktime() (Enano has its own code for this anyway) |
3175 // bypass errors in date() and mktime() (Enano has its own code for this anyway) |
3176 if ( strstr($errstr, "It is not safe to rely on the system's timezone settings. Please use the date.timezone setting, the TZ environment variable or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier.") ) |
3176 if ( strstr($errstr, "It is not safe to rely on the system's timezone settings. Please use the date.timezone setting, the TZ environment variable or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier.") ) |
3177 { |
3177 { |
3178 return true; |
3178 return true; |
3179 } |
3179 } |
3180 |
3180 |
3181 if ( $do_gzip ) |
3181 if ( $do_gzip ) |
3182 { |
3182 { |
3183 $php_errors[] = array( |
3183 $php_errors[] = array( |
3184 'num' => $errno, |
3184 'num' => $errno, |
3185 'type' => $error_type, |
3185 'type' => $error_type, |
3186 'error' => $errstr, |
3186 'error' => $errstr, |
3187 'file' => $errfile, |
3187 'file' => $errfile, |
3188 'line' => $errline |
3188 'line' => $errline |
3189 ); |
3189 ); |
3190 } |
3190 } |
3191 else |
3191 else |
3192 { |
3192 { |
3193 echo "[ <b>PHP $error_type:</b> $errstr in <b>$errfile</b>:<b>$errline</b> ]<br />"; |
3193 echo "[ <b>PHP $error_type:</b> $errstr in <b>$errfile</b>:<b>$errline</b> ]<br />"; |
3194 } |
3194 } |
3195 } |
3195 } |
3196 |
3196 |
3197 set_error_handler('enano_handle_error'); |
3197 set_error_handler('enano_handle_error'); |
3198 |
3198 |
3199 /** |
3199 /** |
3200 * Gzips the output buffer. |
3200 * Gzips the output buffer. |
3201 */ |
3201 */ |
3202 |
3202 |
3203 function gzip_output() |
3203 function gzip_output() |
3204 { |
3204 { |
3205 global $do_gzip; |
3205 global $do_gzip; |
3206 |
3206 |
3207 $gzip_supported = false; |
3207 $gzip_supported = false; |
3208 if ( isset($_SERVER['HTTP_ACCEPT_ENCODING']) ) |
3208 if ( isset($_SERVER['HTTP_ACCEPT_ENCODING']) ) |
3209 { |
3209 { |
3210 $encodings = explode(',', $_SERVER['HTTP_ACCEPT_ENCODING']); |
3210 $encodings = explode(',', $_SERVER['HTTP_ACCEPT_ENCODING']); |
3211 $gzip_supported = in_array('gzip', $encodings) || in_array('deflate', $encodings); |
3211 $gzip_supported = in_array('gzip', $encodings) || in_array('deflate', $encodings); |
3212 } |
3212 } |
3213 |
3213 |
3214 // |
3214 // |
3215 // Compress buffered output if required and send to browser |
3215 // Compress buffered output if required and send to browser |
3216 // Sorry, doesn't work in IE. What else is new? |
3216 // Sorry, doesn't work in IE. What else is new? |
3217 // |
3217 // |
3218 if ( $do_gzip && getConfig('gzip_output', false) == 1 && function_exists('gzdeflate') && !strstr($_SERVER['HTTP_USER_AGENT'], 'MSIE') && !headers_sent() && $gzip_supported ) |
3218 if ( $do_gzip && getConfig('gzip_output', false) == 1 && function_exists('gzdeflate') && !strstr($_SERVER['HTTP_USER_AGENT'], 'MSIE') && !headers_sent() && $gzip_supported ) |
3219 { |
3219 { |
3220 $gzip_contents = ob_get_contents(); |
3220 $gzip_contents = ob_get_contents(); |
3221 ob_end_clean(); |
3221 ob_end_clean(); |
3222 |
3222 |
3223 global $php_errors; |
3223 global $php_errors; |
3224 if ( !empty($php_errors) ) |
3224 if ( !empty($php_errors) ) |
3225 { |
3225 { |
3226 $errors = ''; |
3226 $errors = ''; |
3227 foreach ( $php_errors as $error ) |
3227 foreach ( $php_errors as $error ) |
3228 { |
3228 { |
3229 $errors .= "[ <b>PHP {$error['type']}:</b> {$error['error']} in <b>{$error['file']}</b>:<b>{$error['line']}</b> ]<br />"; |
3229 $errors .= "[ <b>PHP {$error['type']}:</b> {$error['error']} in <b>{$error['file']}</b>:<b>{$error['line']}</b> ]<br />"; |
3230 } |
3230 } |
3231 $gzip_contents = str_replace("</body>", "$errors</body>", $gzip_contents); |
3231 $gzip_contents = str_replace("</body>", "$errors</body>", $gzip_contents); |
3232 } |
3232 } |
3233 |
3233 |
3234 $return = @enano_gzencode($gzip_contents); |
3234 $return = @enano_gzencode($gzip_contents); |
3235 if ( $return ) |
3235 if ( $return ) |
3236 { |
3236 { |
3237 header('Content-encoding: gzip'); |
3237 header('Content-encoding: gzip'); |
3238 echo $return; |
3238 echo $return; |
3239 } |
3239 } |
3240 else |
3240 else |
3241 { |
3241 { |
3242 echo $gzip_contents; |
3242 echo $gzip_contents; |
3243 } |
3243 } |
3244 } |
3244 } |
3245 } |
3245 } |
3246 |
3246 |
3247 /** |
3247 /** |
3248 * Aggressively and hopefully non-destructively optimizes a blob of HTML. |
3248 * Aggressively and hopefully non-destructively optimizes a blob of HTML. |
3249 * @param string HTML to process |
3249 * @param string HTML to process |
3250 * @return string much smaller HTML |
3250 * @return string much smaller HTML |
3251 */ |
3251 */ |
3252 |
3252 |
3253 function aggressive_optimize_html($html) |
3253 function aggressive_optimize_html($html) |
3254 { |
3254 { |
3255 $size_before = strlen($html); |
3255 $size_before = strlen($html); |
3256 |
3256 |
3257 // kill carriage returns |
3257 // kill carriage returns |
3258 $html = str_replace("\r", "", $html); |
3258 $html = str_replace("\r", "", $html); |
3259 |
3259 |
3260 // Which tags to strip for JAVASCRIPT PROCESSING ONLY - you can change this if needed |
3260 // Which tags to strip for JAVASCRIPT PROCESSING ONLY - you can change this if needed |
3261 $strip_tags = Array('enano:no-opt'); |
3261 $strip_tags = Array('enano:no-opt'); |
3262 $strip_tags = implode('|', $strip_tags); |
3262 $strip_tags = implode('|', $strip_tags); |
3263 |
3263 |
3264 // Strip out the tags and replace with placeholders |
3264 // Strip out the tags and replace with placeholders |
3265 preg_match_all("#<($strip_tags)([ ]+.*?)?>(.*?)</($strip_tags)>#is", $html, $matches); |
3265 preg_match_all("#<($strip_tags)([ ]+.*?)?>(.*?)</($strip_tags)>#is", $html, $matches); |
3266 $seed = md5(microtime() . mt_rand()); // Random value used for placeholders |
3266 $seed = md5(microtime() . mt_rand()); // Random value used for placeholders |
3267 for ($i = 0;$i < sizeof($matches[1]); $i++) |
3267 for ($i = 0;$i < sizeof($matches[1]); $i++) |
3268 { |
3268 { |
3269 $html = str_replace($matches[0][$i], "{DONT_STRIP_ME_NAKED:$seed:$i}", $html); |
3269 $html = str_replace($matches[0][$i], "{DONT_STRIP_ME_NAKED:$seed:$i}", $html); |
3270 } |
3270 } |
3271 |
3271 |
3272 // Optimize (but don't obfuscate) Javascript |
3272 // Optimize (but don't obfuscate) Javascript |
3273 preg_match_all('/<script([ ]+.*?)?>(.*?)(\]\]>)?<\/script>/is', $html, $jscript); |
3273 preg_match_all('/<script([ ]+.*?)?>(.*?)(\]\]>)?<\/script>/is', $html, $jscript); |
3274 require_once(ENANO_ROOT . '/includes/js-compressor.php'); |
3274 require_once(ENANO_ROOT . '/includes/js-compressor.php'); |
3275 $jsc = new JavascriptCompressor(); |
3275 $jsc = new JavascriptCompressor(); |
3276 |
3276 |
3277 // list of Javascript reserved words - from about.com |
3277 // list of Javascript reserved words - from about.com |
3278 $reserved_words = array('abstract', 'as', 'boolean', 'break', 'byte', 'case', 'catch', 'char', 'class', 'continue', 'const', 'debugger', 'default', 'delete', 'do', |
3278 $reserved_words = array('abstract', 'as', 'boolean', 'break', 'byte', 'case', 'catch', 'char', 'class', 'continue', 'const', 'debugger', 'default', 'delete', 'do', |
3279 'double', 'else', 'enum', 'export', 'extends', 'false', 'final', 'finally', 'float', 'for', 'function', 'goto', 'if', 'implements', 'import', |
3279 'double', 'else', 'enum', 'export', 'extends', 'false', 'final', 'finally', 'float', 'for', 'function', 'goto', 'if', 'implements', 'import', |
3280 'in', 'instanceof', 'int', 'interface', 'is', 'long', 'namespace', 'native', 'new', 'null', 'package', 'private', 'protected', 'public', |
3280 'in', 'instanceof', 'int', 'interface', 'is', 'long', 'namespace', 'native', 'new', 'null', 'package', 'private', 'protected', 'public', |
3281 'return', 'short', 'static', 'super', 'switch', 'synchronized', 'this', 'throw', 'throws', 'transient', 'true', 'try', 'typeof', 'use', 'var', |
3281 'return', 'short', 'static', 'super', 'switch', 'synchronized', 'this', 'throw', 'throws', 'transient', 'true', 'try', 'typeof', 'use', 'var', |
3282 'void', 'volatile', 'while', 'with'); |
3282 'void', 'volatile', 'while', 'with'); |
3283 |
3283 |
3284 $reserved_words = '(' . implode('|', $reserved_words) . ')'; |
3284 $reserved_words = '(' . implode('|', $reserved_words) . ')'; |
3285 |
3285 |
3286 for ( $i = 0; $i < count($jscript[0]); $i++ ) |
3286 for ( $i = 0; $i < count($jscript[0]); $i++ ) |
3287 { |
3287 { |
3288 $js =& $jscript[2][$i]; |
3288 $js =& $jscript[2][$i]; |
3289 if ( empty($js) ) |
3289 if ( empty($js) ) |
3290 continue; |
3290 continue; |
3291 |
3291 |
3292 $js = $jsc->getClean($js); |
3292 $js = $jsc->getClean($js); |
3293 |
3293 |
3294 $replacement = "<script{$jscript[1][$i]}>/* <![CDATA[ */ $js /* ]]> */</script>"; |
3294 $replacement = "<script{$jscript[1][$i]}>/* <![CDATA[ */ $js /* ]]> */</script>"; |
3295 // apply changes |
3295 // apply changes |
3296 $html = str_replace($jscript[0][$i], $replacement, $html); |
3296 $html = str_replace($jscript[0][$i], $replacement, $html); |
3297 |
3297 |
3298 } |
3298 } |
3299 |
3299 |
3300 // Re-insert untouchable tags |
3300 // Re-insert untouchable tags |
3301 for ($i = 0;$i < sizeof($matches[1]); $i++) |
3301 for ($i = 0;$i < sizeof($matches[1]); $i++) |
3302 { |
3302 { |
3303 $html = str_replace("{DONT_STRIP_ME_NAKED:$seed:$i}", "<{$matches[1][$i]}{$matches[2][$i]}>{$matches[3][$i]}</{$matches[4][$i]}>", $html); |
3303 $html = str_replace("{DONT_STRIP_ME_NAKED:$seed:$i}", "<{$matches[1][$i]}{$matches[2][$i]}>{$matches[3][$i]}</{$matches[4][$i]}>", $html); |
3304 } |
3304 } |
3305 |
3305 |
3306 // Which tags to strip - you can change this if needed |
3306 // Which tags to strip - you can change this if needed |
3307 $strip_tags = Array('pre', 'script', 'style', 'enano:no-opt', 'textarea'); |
3307 $strip_tags = Array('pre', 'script', 'style', 'enano:no-opt', 'textarea'); |
3308 $strip_tags = implode('|', $strip_tags); |
3308 $strip_tags = implode('|', $strip_tags); |
3309 |
3309 |
3310 // Strip out the tags and replace with placeholders |
3310 // Strip out the tags and replace with placeholders |
3311 preg_match_all("#<($strip_tags)(.*?)>(.*?)</($strip_tags)>#is", $html, $matches); |
3311 preg_match_all("#<($strip_tags)(.*?)>(.*?)</($strip_tags)>#is", $html, $matches); |
3312 $seed = md5(microtime() . mt_rand()); // Random value used for placeholders |
3312 $seed = md5(microtime() . mt_rand()); // Random value used for placeholders |
3313 for ($i = 0;$i < sizeof($matches[1]); $i++) |
3313 for ($i = 0;$i < sizeof($matches[1]); $i++) |
3314 { |
3314 { |
3315 $html = str_replace($matches[0][$i], "{DONT_STRIP_ME_NAKED:$seed:$i}", $html); |
3315 $html = str_replace($matches[0][$i], "{DONT_STRIP_ME_NAKED:$seed:$i}", $html); |
3316 } |
3316 } |
3317 |
3317 |
3318 // Finally, process the HTML |
3318 // Finally, process the HTML |
3319 $html = preg_replace("#\n([ ]*)#", " ", $html); |
3319 $html = preg_replace("#\n([ ]*)#", " ", $html); |
3320 |
3320 |
3321 // Remove annoying spaces between tags |
3321 // Remove annoying spaces between tags |
3322 $html = preg_replace("#>([ ][ ]+)<#", "> <", $html); |
3322 $html = preg_replace("#>([ ][ ]+)<#", "> <", $html); |
3323 |
3323 |
3324 // Re-insert untouchable tags |
3324 // Re-insert untouchable tags |
3325 for ($i = 0;$i < sizeof($matches[1]); $i++) |
3325 for ($i = 0;$i < sizeof($matches[1]); $i++) |
3326 { |
3326 { |
3327 $html = str_replace("{DONT_STRIP_ME_NAKED:$seed:$i}", "<{$matches[1][$i]}{$matches[2][$i]}>{$matches[3][$i]}</{$matches[4][$i]}>", $html); |
3327 $html = str_replace("{DONT_STRIP_ME_NAKED:$seed:$i}", "<{$matches[1][$i]}{$matches[2][$i]}>{$matches[3][$i]}</{$matches[4][$i]}>", $html); |
3328 } |
3328 } |
3329 |
3329 |
3330 // Remove <enano:no-opt> blocks (can be used by themes that don't want their HTML optimized) |
3330 // Remove <enano:no-opt> blocks (can be used by themes that don't want their HTML optimized) |
3331 $html = preg_replace('#<(\/|)enano:no-opt(.*?)>#', '', $html); |
3331 $html = preg_replace('#<(\/|)enano:no-opt(.*?)>#', '', $html); |
3332 |
3332 |
3333 $size_after = strlen($html); |
3333 $size_after = strlen($html); |
3334 |
3334 |
3335 // Tell snoopish users what's going on |
3335 // Tell snoopish users what's going on |
3336 $html = str_replace('<html', "\n".'<!-- NOTE: Enano has performed an HTML optimization routine on the HTML you see here. This is to enhance page loading speeds. |
3336 $html = str_replace('<html', "\n".'<!-- NOTE: Enano has performed an HTML optimization routine on the HTML you see here. This is to enhance page loading speeds. |
3337 To view the uncompressed source of this page, add the "nocompress" parameter to the URI of this page: index.php?title=Main_Page&nocompress or Main_Page?nocompress'." |
3337 To view the uncompressed source of this page, add the "nocompress" parameter to the URI of this page: index.php?title=Main_Page&nocompress or Main_Page?nocompress'." |
3338 Size before compression: $size_before bytes |
3338 Size before compression: $size_before bytes |
3339 Size after compression: $size_after bytes |
3339 Size after compression: $size_after bytes |
3340 -->\n<html", $html); |
3340 -->\n<html", $html); |
3341 return $html; |
3341 return $html; |
3342 } |
3342 } |
3343 |
3343 |
3344 /** |
3344 /** |
3345 * For an input range of numbers (like 25-256) returns an array filled with all numbers in the range, inclusive. |
3345 * For an input range of numbers (like 25-256) returns an array filled with all numbers in the range, inclusive. |
3346 * @param string |
3346 * @param string |
3347 * @return array |
3347 * @return array |
3348 */ |
3348 */ |
3349 |
3349 |
3350 function int_range($range) |
3350 function int_range($range) |
3351 { |
3351 { |
3352 if ( strval(intval($range)) == $range ) |
3352 if ( strval(intval($range)) == $range ) |
3353 return $range; |
3353 return $range; |
3354 if ( !preg_match('/^[0-9]+(-[0-9]+)?$/', $range) ) |
3354 if ( !preg_match('/^[0-9]+(-[0-9]+)?$/', $range) ) |
3355 return false; |
3355 return false; |
3356 $ends = explode('-', $range); |
3356 $ends = explode('-', $range); |
3357 if ( count($ends) != 2 ) |
3357 if ( count($ends) != 2 ) |
3358 return $range; |
3358 return $range; |
3359 $ret = array(); |
3359 $ret = array(); |
3360 if ( $ends[1] < $ends[0] ) |
3360 if ( $ends[1] < $ends[0] ) |
3361 $ends = array($ends[1], $ends[0]); |
3361 $ends = array($ends[1], $ends[0]); |
3362 else if ( $ends[0] == $ends[1] ) |
3362 else if ( $ends[0] == $ends[1] ) |
3363 return array($ends[0]); |
3363 return array($ends[0]); |
3364 for ( $i = $ends[0]; $i <= $ends[1]; $i++ ) |
3364 for ( $i = $ends[0]; $i <= $ends[1]; $i++ ) |
3365 { |
3365 { |
3366 $ret[] = $i; |
3366 $ret[] = $i; |
3367 } |
3367 } |
3368 return $ret; |
3368 return $ret; |
3369 } |
3369 } |
3370 |
3370 |
3371 /** |
3371 /** |
3372 * Parses a range or series of IP addresses, and returns the raw addresses. Only parses ranges in the last two octets to prevent DOSing. |
3372 * Parses a range or series of IP addresses, and returns the raw addresses. Only parses ranges in the last two octets to prevent DOSing. |
3373 * Syntax for ranges: x.x.x.x; x|y.x.x.x; x.x.x-z.x; x.x.x-z|p.q|y |
3373 * Syntax for ranges: x.x.x.x; x|y.x.x.x; x.x.x-z.x; x.x.x-z|p.q|y |
3375 * @return array |
3375 * @return array |
3376 */ |
3376 */ |
3377 |
3377 |
3378 function parse_ip_range($range) |
3378 function parse_ip_range($range) |
3379 { |
3379 { |
3380 $octets = explode('.', $range); |
3380 $octets = explode('.', $range); |
3381 if ( count($octets) != 4 ) |
3381 if ( count($octets) != 4 ) |
3382 // invalid range |
3382 // invalid range |
3383 return $range; |
3383 return $range; |
3384 $i = 0; |
3384 $i = 0; |
3385 $possibilities = array( 0 => array(), 1 => array(), 2 => array(), 3 => array() ); |
3385 $possibilities = array( 0 => array(), 1 => array(), 2 => array(), 3 => array() ); |
3386 foreach ( $octets as $octet ) |
3386 foreach ( $octets as $octet ) |
3387 { |
3387 { |
3388 $existing =& $possibilities[$i]; |
3388 $existing =& $possibilities[$i]; |
3389 $inner = explode('|', $octet); |
3389 $inner = explode('|', $octet); |
3390 foreach ( $inner as $bit ) |
3390 foreach ( $inner as $bit ) |
3391 { |
3391 { |
3392 if ( $i >= 2 ) |
3392 if ( $i >= 2 ) |
3393 { |
3393 { |
3394 $bits = int_range($bit); |
3394 $bits = int_range($bit); |
3395 if ( $bits === false ) |
3395 if ( $bits === false ) |
3396 return false; |
3396 return false; |
3397 else if ( !is_array($bits) ) |
3397 else if ( !is_array($bits) ) |
3398 $existing[] = intval($bits); |
3398 $existing[] = intval($bits); |
3399 else |
3399 else |
3400 $existing = array_merge($existing, $bits); |
3400 $existing = array_merge($existing, $bits); |
3401 } |
3401 } |
3402 else |
3402 else |
3403 { |
3403 { |
3404 $bit = intval($bit); |
3404 $bit = intval($bit); |
3405 $existing[] = $bit; |
3405 $existing[] = $bit; |
3406 } |
3406 } |
3407 } |
3407 } |
3408 $existing = array_unique($existing); |
3408 $existing = array_unique($existing); |
3409 $i++; |
3409 $i++; |
3410 } |
3410 } |
3411 $ips = array(); |
3411 $ips = array(); |
3412 |
3412 |
3413 // The only way to combine all those possibilities. ;-) |
3413 // The only way to combine all those possibilities. ;-) |
3414 foreach ( $possibilities[0] as $oc1 ) |
3414 foreach ( $possibilities[0] as $oc1 ) |
3415 foreach ( $possibilities[1] as $oc2 ) |
3415 foreach ( $possibilities[1] as $oc2 ) |
3416 foreach ( $possibilities[2] as $oc3 ) |
3416 foreach ( $possibilities[2] as $oc3 ) |
3417 foreach ( $possibilities[3] as $oc4 ) |
3417 foreach ( $possibilities[3] as $oc4 ) |
3418 $ips[] = "$oc1.$oc2.$oc3.$oc4"; |
3418 $ips[] = "$oc1.$oc2.$oc3.$oc4"; |
3419 |
3419 |
3420 return $ips; |
3420 return $ips; |
3421 } |
3421 } |
3422 |
3422 |
3423 /** |
3423 /** |
3424 * Parses a valid IP address range into a regular expression. |
3424 * Parses a valid IP address range into a regular expression. |
3425 * @param string IP range string |
3425 * @param string IP range string |
3426 * @return string |
3426 * @return string |
3427 */ |
3427 */ |
3428 |
3428 |
3429 function parse_ip_range_regex($range) |
3429 function parse_ip_range_regex($range) |
3430 { |
3430 { |
3431 if ( strstr($range, ':') ) |
3431 if ( strstr($range, ':') ) |
3432 { |
3432 { |
3433 return parse_ipv6_range_regex($range); |
3433 return parse_ipv6_range_regex($range); |
3434 } |
3434 } |
3435 else |
3435 else |
3436 { |
3436 { |
3437 return parse_ipv4_range_regex($range); |
3437 return parse_ipv4_range_regex($range); |
3438 } |
3438 } |
3439 } |
3439 } |
3440 |
3440 |
3441 /** |
3441 /** |
3442 * Parses a valid IPv4 address range into a regular expression. |
3442 * Parses a valid IPv4 address range into a regular expression. |
3443 * @param string IP range string |
3443 * @param string IP range string |
3444 * @return string |
3444 * @return string |
3445 */ |
3445 */ |
3446 |
3446 |
3447 function parse_ipv4_range_regex($range) |
3447 function parse_ipv4_range_regex($range) |
3448 { |
3448 { |
3449 // Regular expression to test the range string for validity |
3449 // Regular expression to test the range string for validity |
3450 $regex = '/^(([0-9]+(-[0-9]+)?)(\|([0-9]+(-[0-9]+)?))*)\.' |
3450 $regex = '/^(([0-9]+(-[0-9]+)?)(\|([0-9]+(-[0-9]+)?))*)\.' |
3451 . '(([0-9]+(-[0-9]+)?)(\|([0-9]+(-[0-9]+)?))*)\.' |
3451 . '(([0-9]+(-[0-9]+)?)(\|([0-9]+(-[0-9]+)?))*)\.' |
3452 . '(([0-9]+(-[0-9]+)?)(\|([0-9]+(-[0-9]+)?))*)\.' |
3452 . '(([0-9]+(-[0-9]+)?)(\|([0-9]+(-[0-9]+)?))*)\.' |
3453 . '(([0-9]+(-[0-9]+)?)(\|([0-9]+(-[0-9]+)?))*)$/'; |
3453 . '(([0-9]+(-[0-9]+)?)(\|([0-9]+(-[0-9]+)?))*)$/'; |
3454 if ( !preg_match($regex, $range) ) |
3454 if ( !preg_match($regex, $range) ) |
3455 { |
3455 { |
3456 return false; |
3456 return false; |
3457 } |
3457 } |
3458 $octets = array(0 => array(), 1 => array(), 2 => array(), 3 => array()); |
3458 $octets = array(0 => array(), 1 => array(), 2 => array(), 3 => array()); |
3459 list($octets[0], $octets[1], $octets[2], $octets[3]) = explode('.', $range); |
3459 list($octets[0], $octets[1], $octets[2], $octets[3]) = explode('.', $range); |
3460 $return = '^'; |
3460 $return = '^'; |
3461 foreach ( $octets as $octet ) |
3461 foreach ( $octets as $octet ) |
3462 { |
3462 { |
3463 // alternatives array |
3463 // alternatives array |
3464 $alts = array(); |
3464 $alts = array(); |
3465 if ( strpos($octet, '|') ) |
3465 if ( strpos($octet, '|') ) |
3466 { |
3466 { |
3467 $particles = explode('|', $octet); |
3467 $particles = explode('|', $octet); |
3468 } |
3468 } |
3469 else |
3469 else |
3470 { |
3470 { |
3471 $particles = array($octet); |
3471 $particles = array($octet); |
3472 } |
3472 } |
3473 foreach ( $particles as $atom ) |
3473 foreach ( $particles as $atom ) |
3474 { |
3474 { |
3475 // each $atom will be either |
3475 // each $atom will be either |
3476 if ( strval(intval($atom)) == $atom ) |
3476 if ( strval(intval($atom)) == $atom ) |
3477 { |
3477 { |
3478 $alts[] = $atom; |
3478 $alts[] = $atom; |
3479 continue; |
3479 continue; |
3480 } |
3480 } |
3481 else |
3481 else |
3482 { |
3482 { |
3483 // it's a range - parse it out |
3483 // it's a range - parse it out |
3484 $alt2 = int_range($atom); |
3484 $alt2 = int_range($atom); |
3485 if ( !$alt2 ) |
3485 if ( !$alt2 ) |
3486 return false; |
3486 return false; |
3487 foreach ( $alt2 as $neutrino ) |
3487 foreach ( $alt2 as $neutrino ) |
3488 $alts[] = $neutrino; |
3488 $alts[] = $neutrino; |
3489 } |
3489 } |
3490 } |
3490 } |
3491 $alts = array_unique($alts); |
3491 $alts = array_unique($alts); |
3492 $alts = '|' . implode('|', $alts) . '|'; |
3492 $alts = '|' . implode('|', $alts) . '|'; |
3493 // we can further optimize/compress this by weaseling our way into using some character ranges |
3493 // we can further optimize/compress this by weaseling our way into using some character ranges |
3494 for ( $i = 1; $i <= 25; $i++ ) |
3494 for ( $i = 1; $i <= 25; $i++ ) |
3495 { |
3495 { |
3496 $alts = str_replace("|{$i}0|{$i}1|{$i}2|{$i}3|{$i}4|{$i}5|{$i}6|{$i}7|{$i}8|{$i}9|", "|{$i}[0-9]|", $alts); |
3496 $alts = str_replace("|{$i}0|{$i}1|{$i}2|{$i}3|{$i}4|{$i}5|{$i}6|{$i}7|{$i}8|{$i}9|", "|{$i}[0-9]|", $alts); |
3497 } |
3497 } |
3498 $alts = str_replace("|1|2|3|4|5|6|7|8|9|", "|[1-9]|", $alts); |
3498 $alts = str_replace("|1|2|3|4|5|6|7|8|9|", "|[1-9]|", $alts); |
3499 $alts = '(' . substr($alts, 1, -1) . ')'; |
3499 $alts = '(' . substr($alts, 1, -1) . ')'; |
3500 $return .= $alts . '\.'; |
3500 $return .= $alts . '\.'; |
3501 } |
3501 } |
3502 $return = substr($return, 0, -2); |
3502 $return = substr($return, 0, -2); |
3503 $return .= '$'; |
3503 $return .= '$'; |
3504 return $return; |
3504 return $return; |
3505 } |
3505 } |
3506 |
3506 |
3507 /** |
3507 /** |
3508 * Parses a valid IPv6 address range into a regular expression. |
3508 * Parses a valid IPv6 address range into a regular expression. |
3509 * @param string IP range string |
3509 * @param string IP range string |
3510 * @return string |
3510 * @return string |
3511 */ |
3511 */ |
3512 |
3512 |
3513 function parse_ipv6_range_regex($range) |
3513 function parse_ipv6_range_regex($range) |
3514 { |
3514 { |
3515 $range = strtolower(trim($range)); |
3515 $range = strtolower(trim($range)); |
3516 $valid = '/^'; |
3516 $valid = '/^'; |
3517 $valid .= '(?:[0-9a-f]{0,4}|[0-9a-f]{1,4}-[0-9a-f]{1,4}):'; |
3517 $valid .= '(?:[0-9a-f]{0,4}|[0-9a-f]{1,4}-[0-9a-f]{1,4}):'; |
3518 $valid .= '(?:[0-9a-f]{0,4}|[0-9a-f]{1,4}-[0-9a-f]{1,4}):'; |
3518 $valid .= '(?:[0-9a-f]{0,4}|[0-9a-f]{1,4}-[0-9a-f]{1,4}):'; |
3519 $valid .= '(?:[0-9a-f]{0,4}|[0-9a-f]{1,4}-[0-9a-f]{1,4}:|:)?'; |
3519 $valid .= '(?:[0-9a-f]{0,4}|[0-9a-f]{1,4}-[0-9a-f]{1,4}:|:)?'; |
3520 $valid .= '(?:[0-9a-f]{0,4}|[0-9a-f]{1,4}-[0-9a-f]{1,4}:|:)?'; |
3520 $valid .= '(?:[0-9a-f]{0,4}|[0-9a-f]{1,4}-[0-9a-f]{1,4}:|:)?'; |
3521 $valid .= '(?:[0-9a-f]{0,4}|[0-9a-f]{1,4}-[0-9a-f]{1,4}:|:)?'; |
3521 $valid .= '(?:[0-9a-f]{0,4}|[0-9a-f]{1,4}-[0-9a-f]{1,4}:|:)?'; |
3522 $valid .= '(?:[0-9a-f]{0,4}|[0-9a-f]{1,4}-[0-9a-f]{1,4}:|:)?'; |
3522 $valid .= '(?:[0-9a-f]{0,4}|[0-9a-f]{1,4}-[0-9a-f]{1,4}:|:)?'; |
3523 $valid .= '(?:[0-9a-f]{0,4}|[0-9a-f]{1,4}-[0-9a-f]{1,4}:|:)?'; |
3523 $valid .= '(?:[0-9a-f]{0,4}|[0-9a-f]{1,4}-[0-9a-f]{1,4}:|:)?'; |
3524 $valid .= '(?:[0-9a-f]{0,4}|[0-9a-f]{1,4}-[0-9a-f]{1,4})$/'; |
3524 $valid .= '(?:[0-9a-f]{0,4}|[0-9a-f]{1,4}-[0-9a-f]{1,4})$/'; |
3525 if ( !preg_match($valid, $range) ) |
3525 if ( !preg_match($valid, $range) ) |
3526 return false; |
3526 return false; |
3527 |
3527 |
3528 // expand address range. |
3528 // expand address range. |
3529 // this takes short ranges like: |
3529 // this takes short ranges like: |
3530 // 2001:470-471:054-b02b::5-bb |
3530 // 2001:470-471:054-b02b::5-bb |
3531 // up to: |
3531 // up to: |
3532 // 2001:0470-0471:0054-b02b:0000:0000:0000:0005-00bb |
3532 // 2001:0470-0471:0054-b02b:0000:0000:0000:0005-00bb |
3533 $range = preg_replace('/^:/', '0000:', $range); |
3533 $range = preg_replace('/^:/', '0000:', $range); |
3534 $range = explode(':', $range); |
3534 $range = explode(':', $range); |
3535 $expanded = ''; |
3535 $expanded = ''; |
3536 $size = count($range); |
3536 $size = count($range); |
3537 foreach ( $range as $byteset ) |
3537 foreach ( $range as $byteset ) |
3538 { |
3538 { |
3539 if ( empty($byteset) ) |
3539 if ( empty($byteset) ) |
3540 { |
3540 { |
3541 // :: |
3541 // :: |
3542 while ( $size < 9 ) |
3542 while ( $size < 9 ) |
3543 { |
3543 { |
3544 $expanded .= '0000:'; |
3544 $expanded .= '0000:'; |
3545 $size++; |
3545 $size++; |
3546 } |
3546 } |
3547 } |
3547 } |
3548 else |
3548 else |
3549 { |
3549 { |
3550 if ( strstr($byteset, '-') ) |
3550 if ( strstr($byteset, '-') ) |
3551 { |
3551 { |
3552 // this is a range |
3552 // this is a range |
3553 $sides = explode('-', $byteset); |
3553 $sides = explode('-', $byteset); |
3554 foreach ( $sides as &$bytepair ) |
3554 foreach ( $sides as &$bytepair ) |
3555 { |
3555 { |
3556 while ( strlen($bytepair) < 4 ) |
3556 while ( strlen($bytepair) < 4 ) |
3557 { |
3557 { |
3558 $bytepair = "0$bytepair"; |
3558 $bytepair = "0$bytepair"; |
3559 } |
3559 } |
3560 } |
3560 } |
3561 $byteset = implode('-', $sides); |
3561 $byteset = implode('-', $sides); |
3562 } |
3562 } |
3563 else |
3563 else |
3564 { |
3564 { |
3565 while ( strlen($byteset) < 4 ) |
3565 while ( strlen($byteset) < 4 ) |
3566 { |
3566 { |
3567 $byteset = "0$byteset"; |
3567 $byteset = "0$byteset"; |
3568 } |
3568 } |
3569 } |
3569 } |
3570 $expanded .= "$byteset:"; |
3570 $expanded .= "$byteset:"; |
3571 } |
3571 } |
3572 } |
3572 } |
3573 $expanded = explode(':', rtrim($expanded, ':')); |
3573 $expanded = explode(':', rtrim($expanded, ':')); |
3574 |
3574 |
3575 // ready to dive in and start generating range regexes. |
3575 // ready to dive in and start generating range regexes. |
3576 // this has to be pretty optimized... we want to end up with regexes like: |
3576 // this has to be pretty optimized... we want to end up with regexes like: |
3577 // range: 54-b12b |
3577 // range: 54-b12b |
3578 /* |
3578 /* |
3579 /005[4-9a-f]| |
3579 /005[4-9a-f]| |
3580 00[6-9a-f][0-9a-f]| |
3580 00[6-9a-f][0-9a-f]| |
3581 0[1-9a-f][0-9a-f][0-9a-f]| |
3581 0[1-9a-f][0-9a-f][0-9a-f]| |
3582 [1-9a][0-9a-f][0-9a-f][0-9a-f]| |
3582 [1-9a][0-9a-f][0-9a-f][0-9a-f]| |
3583 b[0-0][0-1][0-9a-f]| |
3583 b[0-0][0-1][0-9a-f]| |
3584 b0[0-1][0-9a-f]| |
3584 b0[0-1][0-9a-f]| |
3585 b02[0-9a-b]/x |
3585 b02[0-9a-b]/x |
3586 */ |
3586 */ |
3587 foreach ( $expanded as &$word ) |
3587 foreach ( $expanded as &$word ) |
3588 { |
3588 { |
3589 if ( strstr($word, '-') ) |
3589 if ( strstr($word, '-') ) |
3590 { |
3590 { |
3591 // oh... damn. |
3591 // oh... damn. |
3592 $word = '(?:' . generate_hex_numeral_range($word) . ')'; |
3592 $word = '(?:' . generate_hex_numeral_range($word) . ')'; |
3593 } |
3593 } |
3594 } |
3594 } |
3595 |
3595 |
3596 // return print_r($expanded, true); |
3596 // return print_r($expanded, true); |
3597 return '^' . implode(':', $expanded) . '$'; |
3597 return '^' . implode(':', $expanded) . '$'; |
3598 } |
3598 } |
3599 |
3599 |
3600 /** |
3600 /** |
3601 * Take a hex numeral range and parse it in to a PCRE. |
3601 * Take a hex numeral range and parse it in to a PCRE. |
3602 * @param string |
3602 * @param string |
3604 * @access private |
3604 * @access private |
3605 */ |
3605 */ |
3606 |
3606 |
3607 function generate_hex_numeral_range($word) |
3607 function generate_hex_numeral_range($word) |
3608 { |
3608 { |
3609 list($low, $high) = explode('-', $word); |
3609 list($low, $high) = explode('-', $word); |
3610 |
3610 |
3611 if ( hexdec($low) > hexdec($high) ) |
3611 if ( hexdec($low) > hexdec($high) ) |
3612 { |
3612 { |
3613 $_ = $low; |
3613 $_ = $low; |
3614 $low = $high; |
3614 $low = $high; |
3615 $high = $_; |
3615 $high = $_; |
3616 unset($_); |
3616 unset($_); |
3617 } |
3617 } |
3618 |
3618 |
3619 while ( strlen($low) < strlen($high) ) |
3619 while ( strlen($low) < strlen($high) ) |
3620 { |
3620 { |
3621 $low = "0$low"; |
3621 $low = "0$low"; |
3622 } |
3622 } |
3623 |
3623 |
3624 // trim off everything that's the same |
3624 // trim off everything that's the same |
3625 $trimmed = ''; |
3625 $trimmed = ''; |
3626 $len = strlen($low); |
3626 $len = strlen($low); |
3627 for ( $i = 0; $i < $len; $i++ ) |
3627 for ( $i = 0; $i < $len; $i++ ) |
3628 { |
3628 { |
3629 if ( $low{0} === $high{0} ) |
3629 if ( $low{0} === $high{0} ) |
3630 { |
3630 { |
3631 $trimmed .= $low{0}; |
3631 $trimmed .= $low{0}; |
3632 $low = substr($low, 1); |
3632 $low = substr($low, 1); |
3633 $high = substr($high, 1); |
3633 $high = substr($high, 1); |
3634 } |
3634 } |
3635 else |
3635 else |
3636 { |
3636 { |
3637 break; |
3637 break; |
3638 } |
3638 } |
3639 } |
3639 } |
3640 |
3640 |
3641 $len = strlen($high); |
3641 $len = strlen($high); |
3642 if ( $len == 1 ) |
3642 if ( $len == 1 ) |
3643 { |
3643 { |
3644 // this does happen sometimes, so we can save a bit of CPU power here. |
3644 // this does happen sometimes, so we can save a bit of CPU power here. |
3645 return $trimmed . __hexdigitrange($low, $high); |
3645 return $trimmed . __hexdigitrange($low, $high); |
3646 } |
3646 } |
3647 |
3647 |
3648 $return = ''; |
3648 $return = ''; |
3649 // lower half |
3649 // lower half |
3650 for ( $i = $len - 1; $i > 0; $i-- ) |
3650 for ( $i = $len - 1; $i > 0; $i-- ) |
3651 { |
3651 { |
3652 if ( $low{$i} == 'f' ) |
3652 if ( $low{$i} == 'f' ) |
3653 continue; |
3653 continue; |
3654 $return .= $trimmed; |
3654 $return .= $trimmed; |
3655 for ( $j = 0; $j < $len; $j++ ) |
3655 for ( $j = 0; $j < $len; $j++ ) |
3656 { |
3656 { |
3657 if ( $j < $i ) |
3657 if ( $j < $i ) |
3658 { |
3658 { |
3659 $return .= $low{$j}; |
3659 $return .= $low{$j}; |
3660 } |
3660 } |
3661 else if ( $j == $i && ( $i == $len - 1 || $low{$j} == 'f' ) ) |
3661 else if ( $j == $i && ( $i == $len - 1 || $low{$j} == 'f' ) ) |
3662 { |
3662 { |
3663 $return .= __hexdigitrange($low{$j}, 'f'); |
3663 $return .= __hexdigitrange($low{$j}, 'f'); |
3664 } |
3664 } |
3665 else if ( $j == $i && $i != $len - 1 ) |
3665 else if ( $j == $i && $i != $len - 1 ) |
3666 { |
3666 { |
3667 $return .= __hexdigitrange(dechex(hexdec($low{$j}) + 1), 'f'); |
3667 $return .= __hexdigitrange(dechex(hexdec($low{$j}) + 1), 'f'); |
3668 } |
3668 } |
3669 else |
3669 else |
3670 { |
3670 { |
3671 $return .= __hexdigitrange('0', 'f'); |
3671 $return .= __hexdigitrange('0', 'f'); |
3672 } |
3672 } |
3673 } |
3673 } |
3674 $return .= '|'; |
3674 $return .= '|'; |
3675 } |
3675 } |
3676 // middle block |
3676 // middle block |
3677 if ( hexdec($low{0}) + 1 < hexdec($high{0}) ) |
3677 if ( hexdec($low{0}) + 1 < hexdec($high{0}) ) |
3678 { |
3678 { |
3679 if ( hexdec($low{0}) + 1 < hexdec($high{0}) - 1 ) |
3679 if ( hexdec($low{0}) + 1 < hexdec($high{0}) - 1 ) |
3680 $return .= $trimmed . __hexdigitrange(dechex(hexdec($low{0}) + 1), dechex(hexdec($high{0}) - 1)); |
3680 $return .= $trimmed . __hexdigitrange(dechex(hexdec($low{0}) + 1), dechex(hexdec($high{0}) - 1)); |
3681 else |
3681 else |
3682 $return .= $trimmed . __hexdigitrange($low{0}, $high{0}); |
3682 $return .= $trimmed . __hexdigitrange($low{0}, $high{0}); |
3683 if ( $len - 1 > 0 ) |
3683 if ( $len - 1 > 0 ) |
3684 $return .= '[0-9a-f]{' . ( $len - 1 ) . '}|'; |
3684 $return .= '[0-9a-f]{' . ( $len - 1 ) . '}|'; |
3685 } |
3685 } |
3686 // higher half |
3686 // higher half |
3687 for ( $i = 1; $i < $len; $i++ ) |
3687 for ( $i = 1; $i < $len; $i++ ) |
3688 { |
3688 { |
3689 if ( $high{$i} == '0' ) |
3689 if ( $high{$i} == '0' ) |
3690 continue; |
3690 continue; |
3691 $return .= $trimmed; |
3691 $return .= $trimmed; |
3692 for ( $j = 0; $j < $len; $j++ ) |
3692 for ( $j = 0; $j < $len; $j++ ) |
3693 { |
3693 { |
3694 if ( $j < $i ) |
3694 if ( $j < $i ) |
3695 { |
3695 { |
3696 $return .= $high{$j}; |
3696 $return .= $high{$j}; |
3697 } |
3697 } |
3698 else if ( $j == $i && ( $i == $len - 1 || $high{$j} == '0' ) ) |
3698 else if ( $j == $i && ( $i == $len - 1 || $high{$j} == '0' ) ) |
3699 { |
3699 { |
3700 $return .= __hexdigitrange('0', $high{$j}); |
3700 $return .= __hexdigitrange('0', $high{$j}); |
3701 } |
3701 } |
3702 else if ( $j == $i && $i != $len - 1 ) |
3702 else if ( $j == $i && $i != $len - 1 ) |
3703 { |
3703 { |
3704 $return .= __hexdigitrange('0', dechex(hexdec($high{$j}) - 1)); |
3704 $return .= __hexdigitrange('0', dechex(hexdec($high{$j}) - 1)); |
3705 } |
3705 } |
3706 else if ( $j > $i ) |
3706 else if ( $j > $i ) |
3707 { |
3707 { |
3708 $return .= __hexdigitrange('0', 'f'); |
3708 $return .= __hexdigitrange('0', 'f'); |
3709 } |
3709 } |
3710 else |
3710 else |
3711 { |
3711 { |
3712 die("I don't know what to do! i $i j $j"); |
3712 die("I don't know what to do! i $i j $j"); |
3713 } |
3713 } |
3714 } |
3714 } |
3715 $return .= '|'; |
3715 $return .= '|'; |
3716 } |
3716 } |
3717 |
3717 |
3718 return rtrim($return, '|'); |
3718 return rtrim($return, '|'); |
3719 } |
3719 } |
3720 |
3720 |
3721 function __hexdigitrange($low, $high) |
3721 function __hexdigitrange($low, $high) |
3722 { |
3722 { |
3723 if ( $low == $high ) |
3723 if ( $low == $high ) |
3724 return $low; |
3724 return $low; |
3725 if ( empty($low) ) |
3725 if ( empty($low) ) |
3726 $low = '0'; |
3726 $low = '0'; |
3727 |
3727 |
3728 $low_type = ( preg_match('/[0-9]/', $low) ) ? 'num' : 'alph'; |
3728 $low_type = ( preg_match('/[0-9]/', $low) ) ? 'num' : 'alph'; |
3729 $high_type = ( preg_match('/[0-9]/', $high) ) ? 'num' : 'alph'; |
3729 $high_type = ( preg_match('/[0-9]/', $high) ) ? 'num' : 'alph'; |
3730 if ( ( $low_type == 'num' && $high_type == 'num') || ( $low_type == 'alph' && $high_type == 'alph' ) ) |
3730 if ( ( $low_type == 'num' && $high_type == 'num') || ( $low_type == 'alph' && $high_type == 'alph' ) ) |
3731 { |
3731 { |
3732 return "[$low-$high]"; |
3732 return "[$low-$high]"; |
3733 } |
3733 } |
3734 else if ( $low_type == 'num' && $high_type == 'alph' ) |
3734 else if ( $low_type == 'num' && $high_type == 'alph' ) |
3735 { |
3735 { |
3736 $ret = '['; |
3736 $ret = '['; |
3737 |
3737 |
3738 if ( $low == '9' ) |
3738 if ( $low == '9' ) |
3739 $ret .= '9'; |
3739 $ret .= '9'; |
3740 else |
3740 else |
3741 $ret .= "$low-9"; |
3741 $ret .= "$low-9"; |
3742 if ( $high == 'a' ) |
3742 if ( $high == 'a' ) |
3743 $ret .= 'a'; |
3743 $ret .= 'a'; |
3744 else |
3744 else |
3745 $ret .= "a-$high"; |
3745 $ret .= "a-$high"; |
3746 |
3746 |
3747 $ret .= "]"; |
3747 $ret .= "]"; |
3748 return $ret; |
3748 return $ret; |
3749 } |
3749 } |
3750 else if ( $low_type == 'alph' && $high_type == 'num' ) |
3750 else if ( $low_type == 'alph' && $high_type == 'num' ) |
3751 { |
3751 { |
3752 // ???? this should never happen |
3752 // ???? this should never happen |
3753 return __hexdigitrange($high, $low); |
3753 return __hexdigitrange($high, $low); |
3754 } |
3754 } |
3755 } |
3755 } |
3756 |
3756 |
3757 /** |
3757 /** |
3758 * Expand an IPv6 address to full form |
3758 * Expand an IPv6 address to full form |
3759 * @param string ::1, 2001:470:e054::2 |
3759 * @param string ::1, 2001:470:e054::2 |
3760 * @return string 0000:0000:0000:0000:0000:0000:0000:0001, 2001:0470:e054:0000:0000:0000:0000:0002 |
3760 * @return string 0000:0000:0000:0000:0000:0000:0000:0001, 2001:0470:e054:0000:0000:0000:0000:0002 |
3761 */ |
3761 */ |
3762 |
3762 |
3763 function expand_ipv6_address($addr) |
3763 function expand_ipv6_address($addr) |
3764 { |
3764 { |
3765 $expanded = array(); |
3765 $expanded = array(); |
3766 $addr = explode(':', $addr); |
3766 $addr = explode(':', $addr); |
3767 foreach ( $addr as $i => $bytepair ) |
3767 foreach ( $addr as $i => $bytepair ) |
3768 { |
3768 { |
3769 if ( empty($bytepair) ) |
3769 if ( empty($bytepair) ) |
3770 { |
3770 { |
3771 // :: |
3771 // :: |
3772 while ( count($expanded) < (8 - count($addr) + $i + 1) ) |
3772 while ( count($expanded) < (8 - count($addr) + $i + 1) ) |
3773 { |
3773 { |
3774 $expanded[] = '0000'; |
3774 $expanded[] = '0000'; |
3775 } |
3775 } |
3776 } |
3776 } |
3777 else |
3777 else |
3778 { |
3778 { |
3779 while ( strlen($bytepair) < 4 ) |
3779 while ( strlen($bytepair) < 4 ) |
3780 $bytepair = "0$bytepair"; |
3780 $bytepair = "0$bytepair"; |
3781 $expanded[] = $bytepair; |
3781 $expanded[] = $bytepair; |
3782 } |
3782 } |
3783 } |
3783 } |
3784 return implode(':', $expanded); |
3784 return implode(':', $expanded); |
3785 } |
3785 } |
3786 |
3786 |
3787 /** |
3787 /** |
3788 * Validates an e-mail address. Uses a compacted version of the regular expression generated by the scripts at <http://examples.oreilly.com/regex/>. |
3788 * Validates an e-mail address. Uses a compacted version of the regular expression generated by the scripts at <http://examples.oreilly.com/regex/>. |
3789 * @param string E-mail address |
3789 * @param string E-mail address |
3790 * @return bool |
3790 * @return bool |
3791 */ |
3791 */ |
3792 |
3792 |
3793 function check_email_address($email) |
3793 function check_email_address($email) |
3794 { |
3794 { |
3795 static $regexp = '(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|"[^\\\x80-\xff\n\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|"[^\\\x80-\xff\n\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)*@[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)*|(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|"[^\\\x80-\xff\n\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037]*(?:(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)|"[^\\\x80-\xff\n\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037]*)*<[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:@[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)*(?:,[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*@[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)*)*:[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)?(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|"[^\\\x80-\xff\n\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|"[^\\\x80-\xff\n\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)*@[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)*>)'; |
3795 static $regexp = '(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|"[^\\\x80-\xff\n\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|"[^\\\x80-\xff\n\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)*@[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)*|(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|"[^\\\x80-\xff\n\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037]*(?:(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)|"[^\\\x80-\xff\n\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037]*)*<[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:@[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)*(?:,[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*@[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)*)*:[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)?(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|"[^\\\x80-\xff\n\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|"[^\\\x80-\xff\n\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)*@[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)*>)'; |
3796 return ( preg_match("/^$regexp$/", $email) ) ? true : false; |
3796 return ( preg_match("/^$regexp$/", $email) ) ? true : false; |
3797 } |
3797 } |
3798 |
3798 |
3799 function password_score_len($password) |
3799 function password_score_len($password) |
3800 { |
3800 { |
3801 if ( !is_string($password) ) |
3801 if ( !is_string($password) ) |
3802 { |
3802 { |
3803 return -10; |
3803 return -10; |
3804 } |
3804 } |
3805 $len = strlen($password); |
3805 $len = strlen($password); |
3806 $score = $len - 7; |
3806 $score = $len - 7; |
3807 return $score; |
3807 return $score; |
3808 } |
3808 } |
3809 |
3809 |
3810 /** |
3810 /** |
3811 * Give a numerical score for how strong a password is. This is an open-ended scale based on a score added to or subtracted |
3811 * Give a numerical score for how strong a password is. This is an open-ended scale based on a score added to or subtracted |
3812 * from based on certain complexity rules. Anything less than about 1 or 0 is weak, 3-4 is strong, and 10 is not to be easily cracked. |
3812 * from based on certain complexity rules. Anything less than about 1 or 0 is weak, 3-4 is strong, and 10 is not to be easily cracked. |
3816 * @return int |
3816 * @return int |
3817 */ |
3817 */ |
3818 |
3818 |
3819 function password_score($password, &$debug = false) |
3819 function password_score($password, &$debug = false) |
3820 { |
3820 { |
3821 if ( !is_string($password) ) |
3821 if ( !is_string($password) ) |
3822 { |
3822 { |
3823 return -10; |
3823 return -10; |
3824 } |
3824 } |
3825 $score = 0; |
3825 $score = 0; |
3826 $debug = array(); |
3826 $debug = array(); |
3827 // length check |
3827 // length check |
3828 $lenscore = password_score_len($password); |
3828 $lenscore = password_score_len($password); |
3829 |
3829 |
3830 $debug[] = "<b>How this score was calculated</b>\nYour score was tallied up based on an extensive algorithm which outputted\nthe following scores based on traits of your password. Above you can see the\ncomposite score; your individual scores based on certain tests are below.\n\nThe scale is open-ended, with a minimum score of -10. 10 is very strong, 4\nis strong, 1 is good and -3 is fair. Below -3 scores \"Weak.\"\n"; |
3830 $debug[] = "<b>How this score was calculated</b>\nYour score was tallied up based on an extensive algorithm which outputted\nthe following scores based on traits of your password. Above you can see the\ncomposite score; your individual scores based on certain tests are below.\n\nThe scale is open-ended, with a minimum score of -10. 10 is very strong, 4\nis strong, 1 is good and -3 is fair. Below -3 scores \"Weak.\"\n"; |
3831 |
3831 |
3832 $debug[] = 'Adding '.$lenscore.' points for length'; |
3832 $debug[] = 'Adding '.$lenscore.' points for length'; |
3833 |
3833 |
3834 $score += $lenscore; |
3834 $score += $lenscore; |
3835 |
3835 |
3836 $has_upper_lower = false; |
3836 $has_upper_lower = false; |
3837 $has_symbols = false; |
3837 $has_symbols = false; |
3838 $has_numbers = false; |
3838 $has_numbers = false; |
3839 |
3839 |
3840 // contains uppercase and lowercase |
3840 // contains uppercase and lowercase |
3841 if ( preg_match('/[A-z]+/', $password) && strtolower($password) != $password ) |
3841 if ( preg_match('/[A-z]+/', $password) && strtolower($password) != $password ) |
3842 { |
3842 { |
3843 $score += 1; |
3843 $score += 1; |
3844 $has_upper_lower = true; |
3844 $has_upper_lower = true; |
3845 $debug[] = 'Adding 1 point for having uppercase and lowercase'; |
3845 $debug[] = 'Adding 1 point for having uppercase and lowercase'; |
3846 } |
3846 } |
3847 |
3847 |
3848 // contains symbols |
3848 // contains symbols |
3849 if ( preg_match('/[^A-z0-9]+/', $password) ) |
3849 if ( preg_match('/[^A-z0-9]+/', $password) ) |
3850 { |
3850 { |
3851 $score += 1; |
3851 $score += 1; |
3852 $has_symbols = true; |
3852 $has_symbols = true; |
3853 $debug[] = 'Adding 1 point for having nonalphanumeric characters (matching /[^A-z0-9]+/)'; |
3853 $debug[] = 'Adding 1 point for having nonalphanumeric characters (matching /[^A-z0-9]+/)'; |
3854 } |
3854 } |
3855 |
3855 |
3856 // contains numbers |
3856 // contains numbers |
3857 if ( preg_match('/[0-9]+/', $password) ) |
3857 if ( preg_match('/[0-9]+/', $password) ) |
3858 { |
3858 { |
3859 $score += 1; |
3859 $score += 1; |
3860 $has_numbers = true; |
3860 $has_numbers = true; |
3861 $debug[] = 'Adding 1 point for having numbers'; |
3861 $debug[] = 'Adding 1 point for having numbers'; |
3862 } |
3862 } |
3863 |
3863 |
3864 if ( $has_upper_lower && $has_symbols && $has_numbers && strlen($password) >= 9 ) |
3864 if ( $has_upper_lower && $has_symbols && $has_numbers && strlen($password) >= 9 ) |
3865 { |
3865 { |
3866 // if it has uppercase and lowercase letters, symbols, and numbers, and is of considerable length, add some serious points |
3866 // if it has uppercase and lowercase letters, symbols, and numbers, and is of considerable length, add some serious points |
3867 $score += 4; |
3867 $score += 4; |
3868 $debug[] = 'Adding 4 points for having uppercase and lowercase, numbers, and nonalphanumeric and being more than 8 characters'; |
3868 $debug[] = 'Adding 4 points for having uppercase and lowercase, numbers, and nonalphanumeric and being more than 8 characters'; |
3869 } |
3869 } |
3870 else if ( $has_upper_lower && $has_symbols && $has_numbers ) |
3870 else if ( $has_upper_lower && $has_symbols && $has_numbers ) |
3871 { |
3871 { |
3872 // still give some points for passing complexity check |
3872 // still give some points for passing complexity check |
3873 $score += 2; |
3873 $score += 2; |
3874 $debug[] = 'Adding 2 points for having uppercase and lowercase, numbers, and nonalphanumeric'; |
3874 $debug[] = 'Adding 2 points for having uppercase and lowercase, numbers, and nonalphanumeric'; |
3875 } |
3875 } |
3876 else if ( ( $has_upper_lower && $has_symbols ) || |
3876 else if ( ( $has_upper_lower && $has_symbols ) || |
3877 ( $has_upper_lower && $has_numbers ) || |
3877 ( $has_upper_lower && $has_numbers ) || |
3878 ( $has_symbols && $has_numbers ) ) |
3878 ( $has_symbols && $has_numbers ) ) |
3879 { |
3879 { |
3880 // if 2 of the three main complexity checks passed, add a point |
3880 // if 2 of the three main complexity checks passed, add a point |
3881 $score += 1; |
3881 $score += 1; |
3882 $debug[] = 'Adding 1 point for having 2 of 3 complexity checks'; |
3882 $debug[] = 'Adding 1 point for having 2 of 3 complexity checks'; |
3883 } |
3883 } |
3884 else if ( preg_match('/^[0-9]*?([a-z]+)[0-9]?$/', $password) ) |
3884 else if ( preg_match('/^[0-9]*?([a-z]+)[0-9]?$/', $password) ) |
3885 { |
3885 { |
3886 // password is something like magnum1 which will be cracked in seconds |
3886 // password is something like magnum1 which will be cracked in seconds |
3887 $score += -4; |
3887 $score += -4; |
3888 $debug[] = 'Adding -4 points for being of the form [number][word][number]'; |
3888 $debug[] = 'Adding -4 points for being of the form [number][word][number]'; |
3889 } |
3889 } |
3890 else if ( ( !$has_upper_lower && !$has_numbers && $has_symbols ) || |
3890 else if ( ( !$has_upper_lower && !$has_numbers && $has_symbols ) || |
3891 ( !$has_upper_lower && !$has_symbols && $has_numbers ) || |
3891 ( !$has_upper_lower && !$has_symbols && $has_numbers ) || |
3892 ( !$has_numbers && !$has_symbols && $has_upper_lower ) ) |
3892 ( !$has_numbers && !$has_symbols && $has_upper_lower ) ) |
3893 { |
3893 { |
3894 $score += -2; |
3894 $score += -2; |
3895 $debug[] = 'Adding -2 points for only meeting 1 complexity check'; |
3895 $debug[] = 'Adding -2 points for only meeting 1 complexity check'; |
3896 } |
3896 } |
3897 else if ( !$has_upper_lower && !$has_numbers && !$has_symbols ) |
3897 else if ( !$has_upper_lower && !$has_numbers && !$has_symbols ) |
3898 { |
3898 { |
3899 $debug[] = 'Adding -3 points for not meeting any complexity checks'; |
3899 $debug[] = 'Adding -3 points for not meeting any complexity checks'; |
3900 $score += -3; |
3900 $score += -3; |
3901 } |
3901 } |
3902 |
3902 |
3903 // |
3903 // |
3904 // Repetition |
3904 // Repetition |
3905 // Example: foobar12345 should be deducted points, where f1o2o3b4a5r should be given points |
3905 // Example: foobar12345 should be deducted points, where f1o2o3b4a5r should be given points |
3906 // |
3906 // |
3907 |
3907 |
3908 if ( preg_match('/([A-Z][A-Z][A-Z][A-Z]|[a-z][a-z][a-z][a-z])/', $password) ) |
3908 if ( preg_match('/([A-Z][A-Z][A-Z][A-Z]|[a-z][a-z][a-z][a-z])/', $password) ) |
3909 { |
3909 { |
3910 $debug[] = 'Adding -2 points for having more than 4 letters of the same case in a row'; |
3910 $debug[] = 'Adding -2 points for having more than 4 letters of the same case in a row'; |
3911 $score += -2; |
3911 $score += -2; |
3912 } |
3912 } |
3913 else if ( preg_match('/([A-Z][A-Z][A-Z]|[a-z][a-z][a-z])/', $password) ) |
3913 else if ( preg_match('/([A-Z][A-Z][A-Z]|[a-z][a-z][a-z])/', $password) ) |
3914 { |
3914 { |
3915 $debug[] = 'Adding -1 points for having more than 3 letters of the same case in a row'; |
3915 $debug[] = 'Adding -1 points for having more than 3 letters of the same case in a row'; |
3916 $score += -1; |
3916 $score += -1; |
3917 } |
3917 } |
3918 else if ( preg_match('/[A-z]/', $password) && !preg_match('/([A-Z][A-Z][A-Z]|[a-z][a-z][a-z])/', $password) ) |
3918 else if ( preg_match('/[A-z]/', $password) && !preg_match('/([A-Z][A-Z][A-Z]|[a-z][a-z][a-z])/', $password) ) |
3919 { |
3919 { |
3920 $debug[] = 'Adding 1 point for never having more than 2 letters of the same case in a row'; |
3920 $debug[] = 'Adding 1 point for never having more than 2 letters of the same case in a row'; |
3921 $score += 1; |
3921 $score += 1; |
3922 } |
3922 } |
3923 |
3923 |
3924 if ( preg_match('/[0-9][0-9][0-9][0-9]/', $password) ) |
3924 if ( preg_match('/[0-9][0-9][0-9][0-9]/', $password) ) |
3925 { |
3925 { |
3926 $debug[] = 'Adding -2 points for having 4 or more numbers in a row'; |
3926 $debug[] = 'Adding -2 points for having 4 or more numbers in a row'; |
3927 $score += -2; |
3927 $score += -2; |
3928 } |
3928 } |
3929 else if ( preg_match('/[0-9][0-9][0-9]/', $password) ) |
3929 else if ( preg_match('/[0-9][0-9][0-9]/', $password) ) |
3930 { |
3930 { |
3931 $debug[] = 'Adding -1 points for having 3 or more numbers in a row'; |
3931 $debug[] = 'Adding -1 points for having 3 or more numbers in a row'; |
3932 $score += -1; |
3932 $score += -1; |
3933 } |
3933 } |
3934 else if ( $has_numbers && !preg_match('/[0-9][0-9][0-9]/', $password) ) |
3934 else if ( $has_numbers && !preg_match('/[0-9][0-9][0-9]/', $password) ) |
3935 { |
3935 { |
3936 $debug[] = 'Adding 1 point for never more than 2 numbers in a row'; |
3936 $debug[] = 'Adding 1 point for never more than 2 numbers in a row'; |
3937 $score += -1; |
3937 $score += -1; |
3938 } |
3938 } |
3939 |
3939 |
3940 // make passwords like fooooooooooooooooooooooooooooooooooooo totally die by subtracting a point for each character repeated at least 3 times in a row |
3940 // make passwords like fooooooooooooooooooooooooooooooooooooo totally die by subtracting a point for each character repeated at least 3 times in a row |
3941 $prev_char = ''; |
3941 $prev_char = ''; |
3942 $warn = false; |
3942 $warn = false; |
3943 $loss = 0; |
3943 $loss = 0; |
3944 for ( $i = 0; $i < strlen($password); $i++ ) |
3944 for ( $i = 0; $i < strlen($password); $i++ ) |
3945 { |
3945 { |
3946 $chr = $password{$i}; |
3946 $chr = $password{$i}; |
3947 if ( $chr == $prev_char && $warn ) |
3947 if ( $chr == $prev_char && $warn ) |
3948 { |
3948 { |
3949 $loss += -1; |
3949 $loss += -1; |
3950 } |
3950 } |
3951 else if ( $chr == $prev_char && !$warn ) |
3951 else if ( $chr == $prev_char && !$warn ) |
3952 { |
3952 { |
3953 $warn = true; |
3953 $warn = true; |
3954 } |
3954 } |
3955 else if ( $chr != $prev_char && $warn ) |
3955 else if ( $chr != $prev_char && $warn ) |
3956 { |
3956 { |
3957 $warn = false; |
3957 $warn = false; |
3958 } |
3958 } |
3959 $prev_char = $chr; |
3959 $prev_char = $chr; |
3960 } |
3960 } |
3961 if ( $loss < 0 ) |
3961 if ( $loss < 0 ) |
3962 { |
3962 { |
3963 $debug[] = 'Adding '.$loss.' points for immediate character repetition'; |
3963 $debug[] = 'Adding '.$loss.' points for immediate character repetition'; |
3964 $score += $loss; |
3964 $score += $loss; |
3965 // this can bring the score below -10 sometimes |
3965 // this can bring the score below -10 sometimes |
3966 if ( $score < -10 ) |
3966 if ( $score < -10 ) |
3967 { |
3967 { |
3968 $debug[] = 'Setting score to -10 because it went below ('.$score.')'; |
3968 $debug[] = 'Setting score to -10 because it went below ('.$score.')'; |
3969 $score = -10; |
3969 $score = -10; |
3970 } |
3970 } |
3971 } |
3971 } |
3972 |
3972 |
3973 return $score; |
3973 return $score; |
3974 } |
3974 } |
3975 |
3975 |
3976 /** |
3976 /** |
3977 * Registers a task that will be run every X hours. Scheduled tasks should always be scheduled at runtime - they are not stored in the DB. |
3977 * Registers a task that will be run every X hours. Scheduled tasks should always be scheduled at runtime - they are not stored in the DB. |
3978 * @param string Function name to call, or array(object, string method) |
3978 * @param string Function name to call, or array(object, string method) |
3979 * @param int Interval between runs, in hours. Defaults to 24. |
3979 * @param int Interval between runs, in hours. Defaults to 24. |
3980 */ |
3980 */ |
3981 |
3981 |
3982 function register_cron_task($func, $hour_interval = 24) |
3982 function register_cron_task($func, $hour_interval = 24) |
3983 { |
3983 { |
3984 global $cron_tasks; |
3984 global $cron_tasks; |
3985 $hour_interval = strval($hour_interval); |
3985 $hour_interval = strval($hour_interval); |
3986 if ( !isset($cron_tasks[$hour_interval]) ) |
3986 if ( !isset($cron_tasks[$hour_interval]) ) |
3987 $cron_tasks[$hour_interval] = array(); |
3987 $cron_tasks[$hour_interval] = array(); |
3988 $cron_tasks[$hour_interval][] = $func; |
3988 $cron_tasks[$hour_interval][] = $func; |
3989 } |
3989 } |
3990 |
3990 |
3991 /** |
3991 /** |
3992 * Gets the timestamp for the next estimated cron run. |
3992 * Gets the timestamp for the next estimated cron run. |
3993 * @return int |
3993 * @return int |
3994 */ |
3994 */ |
3995 |
3995 |
3996 function get_cron_next_run() |
3996 function get_cron_next_run() |
3997 { |
3997 { |
3998 global $cron_tasks; |
3998 global $cron_tasks; |
3999 $lowest_ivl = min(array_keys($cron_tasks)); |
3999 $lowest_ivl = min(array_keys($cron_tasks)); |
4000 $last_run = intval(getConfig("cron_lastrun_ivl_$lowest_ivl")); |
4000 $last_run = intval(getConfig("cron_lastrun_ivl_$lowest_ivl")); |
4001 return intval($last_run + ( 3600 * $lowest_ivl )) - 30; |
4001 return intval($last_run + ( 3600 * $lowest_ivl )) - 30; |
4002 } |
4002 } |
4003 |
4003 |
4004 /** |
4004 /** |
4005 * Installs a language. |
4005 * Installs a language. |
4006 * @param string The ISO-639-3 identifier for the language. Maximum of 6 characters, usually 3. |
4006 * @param string The ISO-639-3 identifier for the language. Maximum of 6 characters, usually 3. |
4009 * @param string The path to the file containing the language's strings. Optional. |
4009 * @param string The path to the file containing the language's strings. Optional. |
4010 */ |
4010 */ |
4011 |
4011 |
4012 function install_language($lang_code, $lang_name_neutral, $lang_name_local, $lang_file = false) |
4012 function install_language($lang_code, $lang_name_neutral, $lang_name_local, $lang_file = false) |
4013 { |
4013 { |
4014 global $db, $session, $paths, $template, $plugins; // Common objects |
4014 global $db, $session, $paths, $template, $plugins; // Common objects |
4015 |
4015 |
4016 $q = $db->sql_query('SELECT 1 FROM '.table_prefix.'language WHERE lang_code = \'' . $db->escape($lang_code) . '\';'); |
4016 $q = $db->sql_query('SELECT 1 FROM '.table_prefix.'language WHERE lang_code = \'' . $db->escape($lang_code) . '\';'); |
4017 if ( !$q ) |
4017 if ( !$q ) |
4018 $db->_die('functions.php - checking for language existence'); |
4018 $db->_die('functions.php - checking for language existence'); |
4019 |
4019 |
4020 if ( $db->numrows() > 0 ) |
4020 if ( $db->numrows() > 0 ) |
4021 // Language already exists |
4021 // Language already exists |
4022 return false; |
4022 return false; |
4023 |
4023 |
4024 $q = $db->sql_query('INSERT INTO ' . table_prefix . 'language(lang_code, lang_name_default, lang_name_native) |
4024 $q = $db->sql_query('INSERT INTO ' . table_prefix . 'language(lang_code, lang_name_default, lang_name_native) |
4025 VALUES( |
4025 VALUES( |
4026 \'' . $db->escape($lang_code) . '\', |
4026 \'' . $db->escape($lang_code) . '\', |
4027 \'' . $db->escape($lang_name_neutral) . '\', |
4027 \'' . $db->escape($lang_name_neutral) . '\', |
4028 \'' . $db->escape($lang_name_local) . '\' |
4028 \'' . $db->escape($lang_name_local) . '\' |
4029 );'); |
4029 );'); |
4030 if ( !$q ) |
4030 if ( !$q ) |
4031 $db->_die('functions.php - installing language'); |
4031 $db->_die('functions.php - installing language'); |
4032 |
4032 |
4033 if ( ENANO_DBLAYER == 'PGSQL' ) |
4033 if ( ENANO_DBLAYER == 'PGSQL' ) |
4034 { |
4034 { |
4035 // exception for Postgres, which doesn't support insert IDs |
4035 // exception for Postgres, which doesn't support insert IDs |
4036 // This will cause the Language class to just load by lang code |
4036 // This will cause the Language class to just load by lang code |
4037 // instead of by numeric ID |
4037 // instead of by numeric ID |
4038 $lang_id = $lang_code; |
4038 $lang_id = $lang_code; |
4039 } |
4039 } |
4040 else |
4040 else |
4041 { |
4041 { |
4042 $lang_id = $db->insert_id(); |
4042 $lang_id = $db->insert_id(); |
4043 if ( empty($lang_id) || $lang_id == 0 ) |
4043 if ( empty($lang_id) || $lang_id == 0 ) |
4044 { |
4044 { |
4045 $db->_die('functions.php - invalid returned lang_id'); |
4045 $db->_die('functions.php - invalid returned lang_id'); |
4046 } |
4046 } |
4047 } |
4047 } |
4048 |
4048 |
4049 // Do we also need to install a language file? |
4049 // Do we also need to install a language file? |
4050 if ( is_string($lang_file) && file_exists($lang_file) ) |
4050 if ( is_string($lang_file) && file_exists($lang_file) ) |
4051 { |
4051 { |
4052 $lang = new Language($lang_id); |
4052 $lang = new Language($lang_id); |
4053 $lang->import($lang_file); |
4053 $lang->import($lang_file); |
4054 } |
4054 } |
4055 else if ( is_string($lang_file) && !file_exists($lang_file) ) |
4055 else if ( is_string($lang_file) && !file_exists($lang_file) ) |
4056 { |
4056 { |
4057 echo '<b>Notice:</b> Can\'t load language file, so the specified language wasn\'t fully installed.<br />'; |
4057 echo '<b>Notice:</b> Can\'t load language file, so the specified language wasn\'t fully installed.<br />'; |
4058 return false; |
4058 return false; |
4059 } |
4059 } |
4060 return true; |
4060 return true; |
4061 } |
4061 } |
4062 |
4062 |
4063 /** |
4063 /** |
4064 * Lists available languages. |
4064 * Lists available languages. |
4065 * @return array Multi-depth. Associative, with children associative containing keys name, name_eng, and dir. |
4065 * @return array Multi-depth. Associative, with children associative containing keys name, name_eng, and dir. |
4066 */ |
4066 */ |
4067 |
4067 |
4068 function list_available_languages() |
4068 function list_available_languages() |
4069 { |
4069 { |
4070 // Pulled from install/includes/common.php |
4070 // Pulled from install/includes/common.php |
4071 |
4071 |
4072 // Build a list of available languages |
4072 // Build a list of available languages |
4073 $dir = @opendir( ENANO_ROOT . '/language' ); |
4073 $dir = @opendir( ENANO_ROOT . '/language' ); |
4074 if ( !$dir ) |
4074 if ( !$dir ) |
4075 die('CRITICAL: could not open language directory'); |
4075 die('CRITICAL: could not open language directory'); |
4076 |
4076 |
4077 $languages = array(); |
4077 $languages = array(); |
4078 |
4078 |
4079 while ( $dh = @readdir($dir) ) |
4079 while ( $dh = @readdir($dir) ) |
4080 { |
4080 { |
4081 if ( $dh == '.' || $dh == '..' ) |
4081 if ( $dh == '.' || $dh == '..' ) |
4082 continue; |
4082 continue; |
4083 if ( file_exists( ENANO_ROOT . "/language/$dh/meta.json" ) ) |
4083 if ( file_exists( ENANO_ROOT . "/language/$dh/meta.json" ) ) |
4084 { |
4084 { |
4085 // Found a language directory, determine metadata |
4085 // Found a language directory, determine metadata |
4086 $meta = @file_get_contents( ENANO_ROOT . "/language/$dh/meta.json" ); |
4086 $meta = @file_get_contents( ENANO_ROOT . "/language/$dh/meta.json" ); |
4087 if ( empty($meta) ) |
4087 if ( empty($meta) ) |
4088 // Could not read metadata file, continue silently |
4088 // Could not read metadata file, continue silently |
4089 continue; |
4089 continue; |
4090 |
4090 |
4091 // Do some syntax correction on the metadata |
4091 // Do some syntax correction on the metadata |
4092 $meta = enano_clean_json($meta); |
4092 $meta = enano_clean_json($meta); |
4093 |
4093 |
4094 $meta = enano_json_decode($meta); |
4094 $meta = enano_json_decode($meta); |
4095 if ( isset($meta['lang_name_english']) && isset($meta['lang_name_native']) && isset($meta['lang_code']) ) |
4095 if ( isset($meta['lang_name_english']) && isset($meta['lang_name_native']) && isset($meta['lang_code']) ) |
4096 { |
4096 { |
4097 $languages[$meta['lang_code']] = array( |
4097 $languages[$meta['lang_code']] = array( |
4098 'name' => $meta['lang_name_native'], |
4098 'name' => $meta['lang_name_native'], |
4099 'name_eng' => $meta['lang_name_english'], |
4099 'name_eng' => $meta['lang_name_english'], |
4100 'dir' => $dh |
4100 'dir' => $dh |
4101 ); |
4101 ); |
4102 } |
4102 } |
4103 } |
4103 } |
4104 } |
4104 } |
4105 |
4105 |
4106 return $languages; |
4106 return $languages; |
4107 } |
4107 } |
4108 |
4108 |
4109 /** |
4109 /** |
4110 * Scales an image to the specified width and height, and writes the output to the specified |
4110 * Scales an image to the specified width and height, and writes the output to the specified |
4111 * file. Will use ImageMagick if present, but if not will attempt to scale with GD. This will |
4111 * file. Will use ImageMagick if present, but if not will attempt to scale with GD. This will |
4118 * @return bool True on success, false on failure |
4118 * @return bool True on success, false on failure |
4119 */ |
4119 */ |
4120 |
4120 |
4121 function scale_image($in_file, $out_file, $width = 225, $height = 225, $unlink = false) |
4121 function scale_image($in_file, $out_file, $width = 225, $height = 225, $unlink = false) |
4122 { |
4122 { |
4123 global $db, $session, $paths, $template, $plugins; // Common objects |
4123 global $db, $session, $paths, $template, $plugins; // Common objects |
4124 |
4124 |
4125 if ( !is_int($width) || !is_int($height) ) |
4125 if ( !is_int($width) || !is_int($height) ) |
4126 throw new Exception('Invalid height or width.'); |
4126 throw new Exception('Invalid height or width.'); |
4127 |
4127 |
4128 if ( !file_exists($in_file) ) |
4128 if ( !file_exists($in_file) ) |
4129 throw new Exception('Input file does not exist'); |
4129 throw new Exception('Input file does not exist'); |
4130 |
4130 |
4131 $in_file_sh = escapeshellarg($in_file); |
4131 $in_file_sh = escapeshellarg($in_file); |
4132 $out_file_sh = escapeshellarg($out_file); |
4132 $out_file_sh = escapeshellarg($out_file); |
4133 |
4133 |
4134 if ( file_exists($out_file) && !$unlink ) |
4134 if ( file_exists($out_file) && !$unlink ) |
4135 throw new Exception('Refusing to write output file as it already exists and $unlink was not specified.'); |
4135 throw new Exception('Refusing to write output file as it already exists and $unlink was not specified.'); |
4136 else if ( file_exists($out_file) && $unlink ) |
4136 else if ( file_exists($out_file) && $unlink ) |
4137 @unlink($out_file); |
4137 @unlink($out_file); |
4138 if ( file_exists($out_file) ) |
4138 if ( file_exists($out_file) ) |
4139 // couldn't unlink (delete) the output file |
4139 // couldn't unlink (delete) the output file |
4140 throw new Exception('Failed to delete existing output file.'); |
4140 throw new Exception('Failed to delete existing output file.'); |
4141 |
4141 |
4142 $file_ext = strtolower(substr($in_file, ( strrpos($in_file, '.') + 1))); |
4142 $file_ext = strtolower(substr($in_file, ( strrpos($in_file, '.') + 1))); |
4143 switch($file_ext) |
4143 switch($file_ext) |
4144 { |
4144 { |
4145 case 'png': |
4145 case 'png': |
4146 $func = 'imagecreatefrompng'; |
4146 $func = 'imagecreatefrompng'; |
4147 break; |
4147 break; |
4148 case 'jpg': |
4148 case 'jpg': |
4149 case 'jpeg': |
4149 case 'jpeg': |
4150 $func = 'imagecreatefromjpeg'; |
4150 $func = 'imagecreatefromjpeg'; |
4151 break; |
4151 break; |
4152 case 'gif': |
4152 case 'gif': |
4153 $func = 'imagecreatefromgif'; |
4153 $func = 'imagecreatefromgif'; |
4154 break; |
4154 break; |
4155 case 'xpm': |
4155 case 'xpm': |
4156 $func = 'imagecreatefromxpm'; |
4156 $func = 'imagecreatefromxpm'; |
4157 break; |
4157 break; |
4158 default: |
4158 default: |
4159 throw new Exception('Invalid extension of input file.'); |
4159 throw new Exception('Invalid extension of input file.'); |
4160 } |
4160 } |
4161 |
4161 |
4162 $magick_path = getConfig('imagemagick_path'); |
4162 $magick_path = getConfig('imagemagick_path'); |
4163 $can_use_magick = ( |
4163 $can_use_magick = ( |
4164 getConfig('enable_imagemagick') == '1' && |
4164 getConfig('enable_imagemagick') == '1' && |
4165 file_exists($magick_path) && |
4165 file_exists($magick_path) && |
4166 is_executable($magick_path) |
4166 is_executable($magick_path) |
4167 ); |
4167 ); |
4168 $can_use_gd = ( |
4168 $can_use_gd = ( |
4169 function_exists('getimagesize') && |
4169 function_exists('getimagesize') && |
4170 function_exists('imagecreatetruecolor') && |
4170 function_exists('imagecreatetruecolor') && |
4171 function_exists('imagecopyresampled') && |
4171 function_exists('imagecopyresampled') && |
4172 function_exists($func) |
4172 function_exists($func) |
4173 ); |
4173 ); |
4174 if ( $can_use_magick ) |
4174 if ( $can_use_magick ) |
4175 { |
4175 { |
4176 if ( !preg_match('/^([\/A-z0-9:\. _-]+)$/', $magick_path) ) |
4176 if ( !preg_match('/^([\/A-z0-9:\. _-]+)$/', $magick_path) ) |
4177 { |
4177 { |
4178 die('SECURITY: ImageMagick path is screwy'); |
4178 die('SECURITY: ImageMagick path is screwy'); |
4179 } |
4179 } |
4180 $cmdline = "$magick_path $in_file_sh -resize \"{$width}x{$height}>\" $out_file_sh"; |
4180 $cmdline = "$magick_path $in_file_sh -resize \"{$width}x{$height}>\" $out_file_sh"; |
4181 system($cmdline, $return); |
4181 system($cmdline, $return); |
4182 if ( !file_exists($out_file) ) |
4182 if ( !file_exists($out_file) ) |
4183 throw new Exception('ImageMagick: did not produce output image file.'); |
4183 throw new Exception('ImageMagick: did not produce output image file.'); |
4184 return true; |
4184 return true; |
4185 } |
4185 } |
4186 else if ( $can_use_gd ) |
4186 else if ( $can_use_gd ) |
4187 { |
4187 { |
4188 @list($width_orig, $height_orig) = @getimagesize($in_file); |
4188 @list($width_orig, $height_orig) = @getimagesize($in_file); |
4189 if ( !$width_orig || !$height_orig ) |
4189 if ( !$width_orig || !$height_orig ) |
4190 throw new Exception('GD: Could not get height and width of input file.'); |
4190 throw new Exception('GD: Could not get height and width of input file.'); |
4191 // calculate new width and height |
4191 // calculate new width and height |
4192 |
4192 |
4193 $ratio = $width_orig / $height_orig; |
4193 $ratio = $width_orig / $height_orig; |
4194 if ( $ratio > 1 ) |
4194 if ( $ratio > 1 ) |
4195 { |
4195 { |
4196 // orig. width is greater that height |
4196 // orig. width is greater that height |
4197 $new_width = $width; |
4197 $new_width = $width; |
4198 $new_height = round( $width / $ratio ); |
4198 $new_height = round( $width / $ratio ); |
4199 } |
4199 } |
4200 else if ( $ratio < 1 ) |
4200 else if ( $ratio < 1 ) |
4201 { |
4201 { |
4202 // orig. height is greater than width |
4202 // orig. height is greater than width |
4203 $new_width = round( $height / $ratio ); |
4203 $new_width = round( $height / $ratio ); |
4204 $new_height = $height; |
4204 $new_height = $height; |
4205 } |
4205 } |
4206 else if ( $ratio == 1 ) |
4206 else if ( $ratio == 1 ) |
4207 { |
4207 { |
4208 $new_width = $width; |
4208 $new_width = $width; |
4209 $new_height = $width; |
4209 $new_height = $width; |
4210 } |
4210 } |
4211 if ( $new_width > $width_orig || $new_height > $height_orig ) |
4211 if ( $new_width > $width_orig || $new_height > $height_orig ) |
4212 { |
4212 { |
4213 // Too big for our britches here; set it to only convert the file |
4213 // Too big for our britches here; set it to only convert the file |
4214 $new_width = $width_orig; |
4214 $new_width = $width_orig; |
4215 $new_height = $height_orig; |
4215 $new_height = $height_orig; |
4216 } |
4216 } |
4217 |
4217 |
4218 $newimage = @imagecreatetruecolor($new_width, $new_height); |
4218 $newimage = @imagecreatetruecolor($new_width, $new_height); |
4219 if ( !$newimage ) |
4219 if ( !$newimage ) |
4220 throw new Exception('GD: Request to create new truecolor image refused.'); |
4220 throw new Exception('GD: Request to create new truecolor image refused.'); |
4221 $oldimage = @$func($in_file); |
4221 $oldimage = @$func($in_file); |
4222 if ( !$oldimage ) |
4222 if ( !$oldimage ) |
4223 throw new Exception('GD: Request to load input image file failed.'); |
4223 throw new Exception('GD: Request to load input image file failed.'); |
4224 |
4224 |
4225 // Perform scaling |
4225 // Perform scaling |
4226 imagecopyresampled($newimage, $oldimage, 0, 0, 0, 0, $new_width, $new_height, $width_orig, $height_orig); |
4226 imagecopyresampled($newimage, $oldimage, 0, 0, 0, 0, $new_width, $new_height, $width_orig, $height_orig); |
4227 |
4227 |
4228 // Get output format |
4228 // Get output format |
4229 $out_ext = strtolower(substr($out_file, ( strrpos($out_file, '.') + 1))); |
4229 $out_ext = strtolower(substr($out_file, ( strrpos($out_file, '.') + 1))); |
4230 switch($out_ext) |
4230 switch($out_ext) |
4231 { |
4231 { |
4232 case 'png': |
4232 case 'png': |
4233 $outfunc = 'imagepng'; |
4233 $outfunc = 'imagepng'; |
4234 break; |
4234 break; |
4235 case 'jpg': |
4235 case 'jpg': |
4236 case 'jpeg': |
4236 case 'jpeg': |
4237 $outfunc = 'imagejpeg'; |
4237 $outfunc = 'imagejpeg'; |
4238 break; |
4238 break; |
4239 case 'gif': |
4239 case 'gif': |
4240 $outfunc = 'imagegif'; |
4240 $outfunc = 'imagegif'; |
4241 break; |
4241 break; |
4242 case 'xpm': |
4242 case 'xpm': |
4243 $outfunc = 'imagexpm'; |
4243 $outfunc = 'imagexpm'; |
4244 break; |
4244 break; |
4245 default: |
4245 default: |
4246 imagedestroy($newimage); |
4246 imagedestroy($newimage); |
4247 imagedestroy($oldimage); |
4247 imagedestroy($oldimage); |
4248 throw new Exception('GD: Invalid extension of output file.'); |
4248 throw new Exception('GD: Invalid extension of output file.'); |
4249 } |
4249 } |
4250 |
4250 |
4251 // Write output |
4251 // Write output |
4252 $outfunc($newimage, $out_file); |
4252 $outfunc($newimage, $out_file); |
4253 |
4253 |
4254 // clean up |
4254 // clean up |
4255 imagedestroy($newimage); |
4255 imagedestroy($newimage); |
4256 imagedestroy($oldimage); |
4256 imagedestroy($oldimage); |
4257 |
4257 |
4258 // done! |
4258 // done! |
4259 return true; |
4259 return true; |
4260 } |
4260 } |
4261 // Neither scaling method worked; we'll let plugins try to scale it, and then if the file still doesn't exist, die |
4261 // Neither scaling method worked; we'll let plugins try to scale it, and then if the file still doesn't exist, die |
4262 $code = $plugins->setHook('scale_image_failure'); |
4262 $code = $plugins->setHook('scale_image_failure'); |
4263 foreach ( $code as $cmd ) |
4263 foreach ( $code as $cmd ) |
4264 { |
4264 { |
4265 eval($cmd); |
4265 eval($cmd); |
4266 } |
4266 } |
4267 if ( file_exists($out_file) ) |
4267 if ( file_exists($out_file) ) |
4268 return true; |
4268 return true; |
4269 |
4269 |
4270 throw new Exception('Failed to find an appropriate method for scaling.'); |
4270 throw new Exception('Failed to find an appropriate method for scaling.'); |
4271 } |
4271 } |
4272 |
4272 |
4273 /** |
4273 /** |
4274 * Determines whether a GIF file is animated or not. Credit goes to ZeBadger from <http://www.php.net/imagecreatefromgif>. |
4274 * Determines whether a GIF file is animated or not. Credit goes to ZeBadger from <http://www.php.net/imagecreatefromgif>. |
4275 * Modified to conform to Enano coding standards. |
4275 * Modified to conform to Enano coding standards. |
4278 */ |
4278 */ |
4279 |
4279 |
4280 |
4280 |
4281 function is_gif_animated($filename) |
4281 function is_gif_animated($filename) |
4282 { |
4282 { |
4283 $filecontents = @file_get_contents($filename); |
4283 $filecontents = @file_get_contents($filename); |
4284 if ( empty($filecontents) ) |
4284 if ( empty($filecontents) ) |
4285 return false; |
4285 return false; |
4286 |
4286 |
4287 $str_loc = 0; |
4287 $str_loc = 0; |
4288 $count = 0; |
4288 $count = 0; |
4289 while ( $count < 2 ) // There is no point in continuing after we find a 2nd frame |
4289 while ( $count < 2 ) // There is no point in continuing after we find a 2nd frame |
4290 { |
4290 { |
4291 $where1 = strpos($filecontents,"\x00\x21\xF9\x04", $str_loc); |
4291 $where1 = strpos($filecontents,"\x00\x21\xF9\x04", $str_loc); |
4292 if ( $where1 === false ) |
4292 if ( $where1 === false ) |
4293 { |
4293 { |
4294 break; |
4294 break; |
4295 } |
4295 } |
4296 else |
4296 else |
4297 { |
4297 { |
4298 $str_loc = $where1 + 1; |
4298 $str_loc = $where1 + 1; |
4299 $where2 = strpos($filecontents,"\x00\x2C", $str_loc); |
4299 $where2 = strpos($filecontents,"\x00\x2C", $str_loc); |
4300 if ( $where2 === false ) |
4300 if ( $where2 === false ) |
4301 { |
4301 { |
4302 break; |
4302 break; |
4303 } |
4303 } |
4304 else |
4304 else |
4305 { |
4305 { |
4306 if ( $where1 + 8 == $where2 ) |
4306 if ( $where1 + 8 == $where2 ) |
4307 { |
4307 { |
4308 $count++; |
4308 $count++; |
4309 } |
4309 } |
4310 $str_loc = $where2 + 1; |
4310 $str_loc = $where2 + 1; |
4311 } |
4311 } |
4312 } |
4312 } |
4313 } |
4313 } |
4314 |
4314 |
4315 return ( $count > 1 ) ? true : false; |
4315 return ( $count > 1 ) ? true : false; |
4316 } |
4316 } |
4317 |
4317 |
4318 /** |
4318 /** |
4319 * Retrieves the dimensions of a GIF image. |
4319 * Retrieves the dimensions of a GIF image. |
4320 * @param string The path to the GIF file. |
4320 * @param string The path to the GIF file. |
4321 * @return array Key 0 is width, key 1 is height |
4321 * @return array Key 0 is width, key 1 is height |
4322 */ |
4322 */ |
4323 |
4323 |
4324 function gif_get_dimensions($filename) |
4324 function gif_get_dimensions($filename) |
4325 { |
4325 { |
4326 $filecontents = @file_get_contents($filename); |
4326 $filecontents = @file_get_contents($filename); |
4327 if ( empty($filecontents) ) |
4327 if ( empty($filecontents) ) |
4328 return false; |
4328 return false; |
4329 if ( strlen($filecontents) < 10 ) |
4329 if ( strlen($filecontents) < 10 ) |
4330 return false; |
4330 return false; |
4331 |
4331 |
4332 $width = substr($filecontents, 6, 2); |
4332 $width = substr($filecontents, 6, 2); |
4333 $height = substr($filecontents, 8, 2); |
4333 $height = substr($filecontents, 8, 2); |
4334 $width = unpack('v', $width); |
4334 $width = unpack('v', $width); |
4335 $height = unpack('v', $height); |
4335 $height = unpack('v', $height); |
4336 return array($width[1], $height[1]); |
4336 return array($width[1], $height[1]); |
4337 } |
4337 } |
4338 |
4338 |
4339 /** |
4339 /** |
4340 * Determines whether a PNG image is animated or not. Based on some specification information from <http://wiki.mozilla.org/APNG_Specification>. |
4340 * Determines whether a PNG image is animated or not. Based on some specification information from <http://wiki.mozilla.org/APNG_Specification>. |
4341 * @param string Path to PNG file. |
4341 * @param string Path to PNG file. |
4342 * @return bool If animated, returns true |
4342 * @return bool If animated, returns true |
4343 */ |
4343 */ |
4344 |
4344 |
4345 function is_png_animated($filename) |
4345 function is_png_animated($filename) |
4346 { |
4346 { |
4347 $filecontents = @file_get_contents($filename); |
4347 $filecontents = @file_get_contents($filename); |
4348 if ( empty($filecontents) ) |
4348 if ( empty($filecontents) ) |
4349 return false; |
4349 return false; |
4350 |
4350 |
4351 $parsed = parse_png($filecontents); |
4351 $parsed = parse_png($filecontents); |
4352 if ( !$parsed ) |
4352 if ( !$parsed ) |
4353 return false; |
4353 return false; |
4354 |
4354 |
4355 if ( !isset($parsed['fdAT']) ) |
4355 if ( !isset($parsed['fdAT']) ) |
4356 return false; |
4356 return false; |
4357 |
4357 |
4358 if ( count($parsed['fdAT']) > 1 ) |
4358 if ( count($parsed['fdAT']) > 1 ) |
4359 return true; |
4359 return true; |
4360 } |
4360 } |
4361 |
4361 |
4362 /** |
4362 /** |
4363 * Gets the dimensions of a PNG image. |
4363 * Gets the dimensions of a PNG image. |
4364 * @param string Path to PNG file |
4364 * @param string Path to PNG file |
4365 * @return array Key 0 is width, key 1 is length. |
4365 * @return array Key 0 is width, key 1 is length. |
4366 */ |
4366 */ |
4367 |
4367 |
4368 function png_get_dimensions($filename) |
4368 function png_get_dimensions($filename) |
4369 { |
4369 { |
4370 $filecontents = @file_get_contents($filename); |
4370 $filecontents = @file_get_contents($filename); |
4371 if ( empty($filecontents) ) |
4371 if ( empty($filecontents) ) |
4372 return false; |
4372 return false; |
4373 |
4373 |
4374 $parsed = parse_png($filecontents); |
4374 $parsed = parse_png($filecontents); |
4375 if ( !$parsed ) |
4375 if ( !$parsed ) |
4376 return false; |
4376 return false; |
4377 |
4377 |
4378 $ihdr_stream = $parsed['IHDR'][0]; |
4378 $ihdr_stream = $parsed['IHDR'][0]; |
4379 $width = substr($ihdr_stream, 0, 4); |
4379 $width = substr($ihdr_stream, 0, 4); |
4380 $height = substr($ihdr_stream, 4, 4); |
4380 $height = substr($ihdr_stream, 4, 4); |
4381 $width = unpack('N', $width); |
4381 $width = unpack('N', $width); |
4382 $height = unpack('N', $height); |
4382 $height = unpack('N', $height); |
4383 $x = $width[1]; |
4383 $x = $width[1]; |
4384 $y = $height[1]; |
4384 $y = $height[1]; |
4385 return array($x, $y); |
4385 return array($x, $y); |
4386 } |
4386 } |
4387 |
4387 |
4388 /** |
4388 /** |
4389 * Internal function to parse out the streams of a PNG file. Based on the W3 PNG spec: http://www.w3.org/TR/PNG/ |
4389 * Internal function to parse out the streams of a PNG file. Based on the W3 PNG spec: http://www.w3.org/TR/PNG/ |
4390 * @param string The contents of the PNG |
4390 * @param string The contents of the PNG |
4391 * @return array Associative array containing the streams |
4391 * @return array Associative array containing the streams |
4392 */ |
4392 */ |
4393 |
4393 |
4394 function parse_png($data) |
4394 function parse_png($data) |
4395 { |
4395 { |
4396 // Trim off first 8 bytes to check for PNG header |
4396 // Trim off first 8 bytes to check for PNG header |
4397 $header = substr($data, 0, 8); |
4397 $header = substr($data, 0, 8); |
4398 if ( $header != "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a" ) |
4398 if ( $header != "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a" ) |
4399 { |
4399 { |
4400 return false; |
4400 return false; |
4401 } |
4401 } |
4402 $return = array(); |
4402 $return = array(); |
4403 $data = substr($data, 8); |
4403 $data = substr($data, 8); |
4404 while ( strlen($data) > 0 ) |
4404 while ( strlen($data) > 0 ) |
4405 { |
4405 { |
4406 $chunklen_bin = substr($data, 0, 4); |
4406 $chunklen_bin = substr($data, 0, 4); |
4407 $chunk_type = substr($data, 4, 4); |
4407 $chunk_type = substr($data, 4, 4); |
4408 $chunklen = unpack('N', $chunklen_bin); |
4408 $chunklen = unpack('N', $chunklen_bin); |
4409 $chunklen = $chunklen[1]; |
4409 $chunklen = $chunklen[1]; |
4410 $chunk_data = substr($data, 8, $chunklen); |
4410 $chunk_data = substr($data, 8, $chunklen); |
4411 |
4411 |
4412 // If the chunk type is not valid, this may be a malicious PNG with bad offsets. Break out of the loop. |
4412 // If the chunk type is not valid, this may be a malicious PNG with bad offsets. Break out of the loop. |
4413 if ( !preg_match('/^[A-z]{4}$/', $chunk_type) ) |
4413 if ( !preg_match('/^[A-z]{4}$/', $chunk_type) ) |
4414 break; |
4414 break; |
4415 |
4415 |
4416 if ( !isset($return[$chunk_type]) ) |
4416 if ( !isset($return[$chunk_type]) ) |
4417 $return[$chunk_type] = array(); |
4417 $return[$chunk_type] = array(); |
4418 $return[$chunk_type][] = $chunk_data; |
4418 $return[$chunk_type][] = $chunk_data; |
4419 |
4419 |
4420 $offset_next = 4 // Length |
4420 $offset_next = 4 // Length |
4421 + 4 // Type |
4421 + 4 // Type |
4422 + $chunklen // Data |
4422 + $chunklen // Data |
4423 + 4; // CRC |
4423 + 4; // CRC |
4424 $data = substr($data, $offset_next); |
4424 $data = substr($data, $offset_next); |
4425 } |
4425 } |
4426 return $return; |
4426 return $return; |
4427 } |
4427 } |
4428 |
4428 |
4429 /** |
4429 /** |
4430 * Retreives information about the intrinsic characteristics of the jpeg image, such as Bits per Component, Height and Width. This function is from the PHP JPEG Metadata Toolkit. Licensed under the GPLv2 or later. |
4430 * Retreives information about the intrinsic characteristics of the jpeg image, such as Bits per Component, Height and Width. This function is from the PHP JPEG Metadata Toolkit. Licensed under the GPLv2 or later. |
4431 * @param array The JPEG header data, as retrieved from the get_jpeg_header_data function |
4431 * @param array The JPEG header data, as retrieved from the get_jpeg_header_data function |
4491 * @copyright Copyright Evan Hunter 2004 |
4491 * @copyright Copyright Evan Hunter 2004 |
4492 */ |
4492 */ |
4493 |
4493 |
4494 function get_jpeg_header_data( $filename ) |
4494 function get_jpeg_header_data( $filename ) |
4495 { |
4495 { |
4496 // Attempt to open the jpeg file - the at symbol supresses the error message about |
4496 // Attempt to open the jpeg file - the at symbol supresses the error message about |
4497 // not being able to open files. The file_exists would have been used, but it |
4497 // not being able to open files. The file_exists would have been used, but it |
4498 // does not work with files fetched over http or ftp. |
4498 // does not work with files fetched over http or ftp. |
4499 $filehnd = @fopen($filename, 'rb'); |
4499 $filehnd = @fopen($filename, 'rb'); |
4500 |
4500 |
4501 // Check if the file opened successfully |
4501 // Check if the file opened successfully |
4502 if ( ! $filehnd ) |
4502 if ( ! $filehnd ) |
4503 { |
4503 { |
4504 // Could't open the file - exit |
4504 // Could't open the file - exit |
4505 return FALSE; |
4505 return FALSE; |
4506 } |
4506 } |
4507 |
4507 |
4508 |
4508 |
4509 // Read the first two characters |
4509 // Read the first two characters |
4510 $data = fread( $filehnd, 2 ); |
4510 $data = fread( $filehnd, 2 ); |
4511 |
4511 |
4512 // Check that the first two characters are 0xFF 0xDA (SOI - Start of image) |
4512 // Check that the first two characters are 0xFF 0xDA (SOI - Start of image) |
4513 if ( $data != "\xFF\xD8" ) |
4513 if ( $data != "\xFF\xD8" ) |
4514 { |
4514 { |
4515 // No SOI (FF D8) at start of file - This probably isn't a JPEG file - close file and return; |
4515 // No SOI (FF D8) at start of file - This probably isn't a JPEG file - close file and return; |
4516 fclose($filehnd); |
4516 fclose($filehnd); |
4517 return FALSE; |
4517 return FALSE; |
4518 } |
4518 } |
4519 |
4519 |
4520 |
4520 |
4521 // Read the third character |
4521 // Read the third character |
4522 $data = fread( $filehnd, 2 ); |
4522 $data = fread( $filehnd, 2 ); |
4523 |
4523 |
4524 // Check that the third character is 0xFF (Start of first segment header) |
4524 // Check that the third character is 0xFF (Start of first segment header) |
4525 if ( $data{0} != "\xFF" ) |
4525 if ( $data{0} != "\xFF" ) |
4526 { |
4526 { |
4527 // NO FF found - close file and return - JPEG is probably corrupted |
4527 // NO FF found - close file and return - JPEG is probably corrupted |
4528 fclose($filehnd); |
4528 fclose($filehnd); |
4529 return FALSE; |
4529 return FALSE; |
4530 } |
4530 } |
4531 |
4531 |
4532 // Flag that we havent yet hit the compressed image data |
4532 // Flag that we havent yet hit the compressed image data |
4533 $hit_compressed_image_data = FALSE; |
4533 $hit_compressed_image_data = FALSE; |
4534 |
4534 |
4535 |
4535 |
4536 // Cycle through the file until, one of: 1) an EOI (End of image) marker is hit, |
4536 // Cycle through the file until, one of: 1) an EOI (End of image) marker is hit, |
4537 // 2) we have hit the compressed image data (no more headers are allowed after data) |
4537 // 2) we have hit the compressed image data (no more headers are allowed after data) |
4538 // 3) or end of file is hit |
4538 // 3) or end of file is hit |
4539 |
4539 |
4540 while ( ( $data{1} != "\xD9" ) && (! $hit_compressed_image_data) && ( ! feof( $filehnd ) )) |
4540 while ( ( $data{1} != "\xD9" ) && (! $hit_compressed_image_data) && ( ! feof( $filehnd ) )) |
4541 { |
4541 { |
4542 // Found a segment to look at. |
4542 // Found a segment to look at. |
4543 // Check that the segment marker is not a Restart marker - restart markers don't have size or data after them |
4543 // Check that the segment marker is not a Restart marker - restart markers don't have size or data after them |
4544 if ( ( ord($data{1}) < 0xD0 ) || ( ord($data{1}) > 0xD7 ) ) |
4544 if ( ( ord($data{1}) < 0xD0 ) || ( ord($data{1}) > 0xD7 ) ) |
4545 { |
4545 { |
4546 // Segment isn't a Restart marker |
4546 // Segment isn't a Restart marker |
4547 // Read the next two bytes (size) |
4547 // Read the next two bytes (size) |
4548 $sizestr = fread( $filehnd, 2 ); |
4548 $sizestr = fread( $filehnd, 2 ); |
4549 |
4549 |
4550 // convert the size bytes to an integer |
4550 // convert the size bytes to an integer |
4551 $decodedsize = unpack ("nsize", $sizestr); |
4551 $decodedsize = unpack ("nsize", $sizestr); |
4552 |
4552 |
4553 // Save the start position of the data |
4553 // Save the start position of the data |
4554 $segdatastart = ftell( $filehnd ); |
4554 $segdatastart = ftell( $filehnd ); |
4555 |
4555 |
4556 // Read the segment data with length indicated by the previously read size |
4556 // Read the segment data with length indicated by the previously read size |
4557 $segdata = fread( $filehnd, $decodedsize['size'] - 2 ); |
4557 $segdata = fread( $filehnd, $decodedsize['size'] - 2 ); |
4558 |
4558 |
4559 |
4559 |
4560 // Store the segment information in the output array |
4560 // Store the segment information in the output array |
4561 $headerdata[] = array( "SegType" => ord($data{1}), |
4561 $headerdata[] = array( "SegType" => ord($data{1}), |
4562 "SegName" => $GLOBALS[ "JPEG_Segment_Names" ][ ord($data{1}) ], |
4562 "SegName" => $GLOBALS[ "JPEG_Segment_Names" ][ ord($data{1}) ], |
4563 "SegDataStart" => $segdatastart, |
4563 "SegDataStart" => $segdatastart, |
4564 "SegData" => $segdata ); |
4564 "SegData" => $segdata ); |
4565 } |
4565 } |
4566 |
4566 |
4567 // If this is a SOS (Start Of Scan) segment, then there is no more header data - the compressed image data follows |
4567 // If this is a SOS (Start Of Scan) segment, then there is no more header data - the compressed image data follows |
4568 if ( $data{1} == "\xDA" ) |
4568 if ( $data{1} == "\xDA" ) |
4569 { |
4569 { |
4570 // Flag that we have hit the compressed image data - exit loop as no more headers available. |
4570 // Flag that we have hit the compressed image data - exit loop as no more headers available. |
4571 $hit_compressed_image_data = TRUE; |
4571 $hit_compressed_image_data = TRUE; |
4572 } |
4572 } |
4573 else |
4573 else |
4574 { |
4574 { |
4575 // Not an SOS - Read the next two bytes - should be the segment marker for the next segment |
4575 // Not an SOS - Read the next two bytes - should be the segment marker for the next segment |
4576 $data = fread( $filehnd, 2 ); |
4576 $data = fread( $filehnd, 2 ); |
4577 |
4577 |
4578 // Check that the first byte of the two is 0xFF as it should be for a marker |
4578 // Check that the first byte of the two is 0xFF as it should be for a marker |
4579 if ( $data{0} != "\xFF" ) |
4579 if ( $data{0} != "\xFF" ) |
4580 { |
4580 { |
4581 // NO FF found - close file and return - JPEG is probably corrupted |
4581 // NO FF found - close file and return - JPEG is probably corrupted |
4582 fclose($filehnd); |
4582 fclose($filehnd); |
4583 return FALSE; |
4583 return FALSE; |
4584 } |
4584 } |
4585 } |
4585 } |
4586 } |
4586 } |
4587 |
4587 |
4588 // Close File |
4588 // Close File |
4589 fclose($filehnd); |
4589 fclose($filehnd); |
4590 |
4590 |
4591 // Return the header data retrieved |
4591 // Return the header data retrieved |
4592 return $headerdata; |
4592 return $headerdata; |
4593 } |
4593 } |
4594 |
4594 |
4595 /** |
4595 /** |
4596 * Returns the dimensions of a JPEG image in the same format as {php,gif}_get_dimensions(). |
4596 * Returns the dimensions of a JPEG image in the same format as {php,gif}_get_dimensions(). |
4597 * @param string JPEG file to check |
4597 * @param string JPEG file to check |
4598 * @return array Key 0 is width, key 1 is height |
4598 * @return array Key 0 is width, key 1 is height |
4599 */ |
4599 */ |
4600 |
4600 |
4601 function jpg_get_dimensions($filename) |
4601 function jpg_get_dimensions($filename) |
4602 { |
4602 { |
4603 if ( !file_exists($filename) ) |
4603 if ( !file_exists($filename) ) |
4604 { |
4604 { |
4605 echo "Doesn't exist<br />"; |
4605 echo "Doesn't exist<br />"; |
4606 return false; |
4606 return false; |
4607 } |
4607 } |
4608 |
4608 |
4609 $headers = get_jpeg_header_data($filename); |
4609 $headers = get_jpeg_header_data($filename); |
4610 if ( !$headers ) |
4610 if ( !$headers ) |
4611 { |
4611 { |
4612 echo "Bad headers<br />"; |
4612 echo "Bad headers<br />"; |
4613 return false; |
4613 return false; |
4614 } |
4614 } |
4615 |
4615 |
4616 $metadata = get_jpeg_intrinsic_values($headers); |
4616 $metadata = get_jpeg_intrinsic_values($headers); |
4617 if ( !$metadata ) |
4617 if ( !$metadata ) |
4618 { |
4618 { |
4619 echo "Bad metadata: <pre>" . print_r($metadata, true) . "</pre><br />"; |
4619 echo "Bad metadata: <pre>" . print_r($metadata, true) . "</pre><br />"; |
4620 return false; |
4620 return false; |
4621 } |
4621 } |
4622 |
4622 |
4623 if ( !isset($metadata['Image Width']) || !isset($metadata['Image Height']) ) |
4623 if ( !isset($metadata['Image Width']) || !isset($metadata['Image Height']) ) |
4624 { |
4624 { |
4625 echo "No metadata<br />"; |
4625 echo "No metadata<br />"; |
4626 return false; |
4626 return false; |
4627 } |
4627 } |
4628 |
4628 |
4629 return array($metadata['Image Width'], $metadata['Image Height']); |
4629 return array($metadata['Image Width'], $metadata['Image Height']); |
4630 } |
4630 } |
4631 |
4631 |
4632 /** |
4632 /** |
4633 * Generates a URL for the avatar for the given user ID and avatar type. |
4633 * Generates a URL for the avatar for the given user ID and avatar type. |
4634 * @param int User ID |
4634 * @param int User ID |
4684 * @return string URL |
4684 * @return string URL |
4685 */ |
4685 */ |
4686 |
4686 |
4687 function make_gravatar_url($email, $size = false) |
4687 function make_gravatar_url($email, $size = false) |
4688 { |
4688 { |
4689 $email = md5($email); |
4689 $email = md5($email); |
4690 |
4690 |
4691 // gravatar parameters |
4691 // gravatar parameters |
4692 if ( $size ) |
4692 if ( $size ) |
4693 { |
4693 { |
4694 $max_size = intval($size); |
4694 $max_size = intval($size); |
4695 } |
4695 } |
4696 else |
4696 else |
4697 { |
4697 { |
4698 $max_x = intval(getConfig('avatar_max_width', '150')); |
4698 $max_x = intval(getConfig('avatar_max_width', '150')); |
4699 $max_y = intval(getConfig('avatar_max_height', '150')); |
4699 $max_y = intval(getConfig('avatar_max_height', '150')); |
4700 // ?s= |
4700 // ?s= |
4701 $max_size = ( $max_x > $max_y ) ? $max_y : $max_x; |
4701 $max_size = ( $max_x > $max_y ) ? $max_y : $max_x; |
4702 } |
4702 } |
4703 |
4703 |
4704 // ?r= |
4704 // ?r= |
4705 $rating = getConfig('gravatar_rating', 'g'); |
4705 $rating = getConfig('gravatar_rating', 'g'); |
4706 |
4706 |
4707 // final URL |
4707 // final URL |
4708 $url = "http://www.gravatar.com/avatar/$email?r=$rating&s=$max_size"; |
4708 $url = "http://www.gravatar.com/avatar/$email?r=$rating&s=$max_size"; |
4709 |
4709 |
4710 return $url; |
4710 return $url; |
4711 } |
4711 } |
4712 |
4712 |
4713 /** |
4713 /** |
4714 * Determines an image's filetype based on its signature. |
4714 * Determines an image's filetype based on its signature. |
4715 * @param string Path to image file |
4715 * @param string Path to image file |
4716 * @return string One of gif, png, or jpg, or false if none of these. |
4716 * @return string One of gif, png, or jpg, or false if none of these. |
4717 */ |
4717 */ |
4718 |
4718 |
4719 function get_image_filetype($filename) |
4719 function get_image_filetype($filename) |
4720 { |
4720 { |
4721 $filecontents = @file_get_contents($filename); |
4721 $filecontents = @file_get_contents($filename); |
4722 if ( empty($filecontents) ) |
4722 if ( empty($filecontents) ) |
4723 return false; |
4723 return false; |
4724 |
4724 |
4725 if ( substr($filecontents, 0, 8) == "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a" ) |
4725 if ( substr($filecontents, 0, 8) == "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a" ) |
4726 return 'png'; |
4726 return 'png'; |
4727 |
4727 |
4728 if ( substr($filecontents, 0, 6) == 'GIF87a' || substr($filecontents, 0, 6) == 'GIF89a' ) |
4728 if ( substr($filecontents, 0, 6) == 'GIF87a' || substr($filecontents, 0, 6) == 'GIF89a' ) |
4729 return 'gif'; |
4729 return 'gif'; |
4730 |
4730 |
4731 if ( substr($filecontents, 0, 2) == "\xFF\xD8" ) |
4731 if ( substr($filecontents, 0, 2) == "\xFF\xD8" ) |
4732 return 'jpg'; |
4732 return 'jpg'; |
4733 |
4733 |
4734 return false; |
4734 return false; |
4735 } |
4735 } |
4736 |
4736 |
4737 /** |
4737 /** |
4738 * Generates a JSON encoder/decoder singleton. |
4738 * Generates a JSON encoder/decoder singleton. |
4739 * @return object |
4739 * @return object |
4740 */ |
4740 */ |
4741 |
4741 |
4742 function enano_json_singleton() |
4742 function enano_json_singleton() |
4743 { |
4743 { |
4744 static $json_obj; |
4744 static $json_obj; |
4745 if ( !is_object($json_obj) ) |
4745 if ( !is_object($json_obj) ) |
4746 $json_obj = new Services_JSON(SERVICES_JSON_LOOSE_TYPE | SERVICES_JSON_SUPPRESS_ERRORS); |
4746 $json_obj = new Services_JSON(SERVICES_JSON_LOOSE_TYPE | SERVICES_JSON_SUPPRESS_ERRORS); |
4747 |
4747 |
4748 return $json_obj; |
4748 return $json_obj; |
4749 } |
4749 } |
4750 |
4750 |
4751 /** |
4751 /** |
4752 * Wrapper for JSON encoding. |
4752 * Wrapper for JSON encoding. |
4753 * @param mixed Variable to encode |
4753 * @param mixed Variable to encode |
4754 * @return string JSON-encoded string |
4754 * @return string JSON-encoded string |
4755 */ |
4755 */ |
4756 |
4756 |
4757 function enano_json_encode($data) |
4757 function enano_json_encode($data) |
4758 { |
4758 { |
4759 /* |
4759 /* |
4760 if ( function_exists('json_encode') ) |
4760 if ( function_exists('json_encode') ) |
4761 { |
4761 { |
4762 // using PHP5 with JSON support |
4762 // using PHP5 with JSON support |
4763 return json_encode($data); |
4763 return json_encode($data); |
4764 } |
4764 } |
4765 */ |
4765 */ |
4766 |
4766 |
4767 return Zend_Json::encode($data, true); |
4767 return Zend_Json::encode($data, true); |
4768 } |
4768 } |
4769 |
4769 |
4770 /** |
4770 /** |
4771 * Wrapper for JSON decoding. |
4771 * Wrapper for JSON decoding. |
4772 * @param string JSON-encoded string |
4772 * @param string JSON-encoded string |
4773 * @return mixed Decoded value |
4773 * @return mixed Decoded value |
4774 */ |
4774 */ |
4775 |
4775 |
4776 function enano_json_decode($data) |
4776 function enano_json_decode($data) |
4777 { |
4777 { |
4778 /* |
4778 /* |
4779 if ( function_exists('json_decode') ) |
4779 if ( function_exists('json_decode') ) |
4780 { |
4780 { |
4781 // using PHP5 with JSON support |
4781 // using PHP5 with JSON support |
4782 return json_decode($data); |
4782 return json_decode($data); |
4783 } |
4783 } |
4784 */ |
4784 */ |
4785 |
4785 |
4786 return Zend_Json::decode($data, Zend_Json::TYPE_ARRAY); |
4786 return Zend_Json::decode($data, Zend_Json::TYPE_ARRAY); |
4787 } |
4787 } |
4788 |
4788 |
4789 /** |
4789 /** |
4790 * Cleans a snippet of JSON for closer standards compliance (shuts up the picky Zend parser) |
4790 * Cleans a snippet of JSON for closer standards compliance (shuts up the picky Zend parser) |
4791 * @param string Dirty JSON |
4791 * @param string Dirty JSON |
4792 * @return string Clean JSON |
4792 * @return string Clean JSON |
4793 */ |
4793 */ |
4794 |
4794 |
4795 function enano_clean_json($json) |
4795 function enano_clean_json($json) |
4796 { |
4796 { |
4797 // eliminate comments |
4797 // eliminate comments |
4798 $json = preg_replace(array( |
4798 $json = preg_replace(array( |
4799 // eliminate single line comments in '// ...' form |
4799 // eliminate single line comments in '// ...' form |
4800 '#^\s*//(.*)$#m', |
4800 '#^\s*//(.*)$#m', |
4801 // eliminate multi-line comments in '/* ... */' form, at start of string |
4801 // eliminate multi-line comments in '/* ... */' form, at start of string |
4802 '#^\s*/\*(.+)\*/#Us', |
4802 '#^\s*/\*(.+)\*/#Us', |
4803 // eliminate multi-line comments in '/* ... */' form, at end of string |
4803 // eliminate multi-line comments in '/* ... */' form, at end of string |
4804 '#/\*(.+)\*/\s*$#Us' |
4804 '#/\*(.+)\*/\s*$#Us' |
4805 ), '', $json); |
4805 ), '', $json); |
4806 |
4806 |
4807 $json = preg_replace('/([,\{\[])(?:[\r\n]+)([\s]*?)([a-z0-9_]+)([\s]*?):/', '\\1\\2"\\3" :', $json); |
4807 $json = preg_replace('/([,\{\[])(?:[\r\n]+)([\s]*?)([a-z0-9_]+)([\s]*?):/', '\\1\\2"\\3" :', $json); |
4808 |
4808 |
4809 return $json; |
4809 return $json; |
4810 } |
4810 } |
4811 |
4811 |
4812 /** |
4812 /** |
4813 * Trims a snippet of text to the first and last curly braces. Useful for JSON. |
4813 * Trims a snippet of text to the first and last curly braces. Useful for JSON. |
4814 * @param string Text to trim |
4814 * @param string Text to trim |
4815 * @return string |
4815 * @return string |
4816 */ |
4816 */ |
4817 |
4817 |
4818 function enano_trim_json($json) |
4818 function enano_trim_json($json) |
4819 { |
4819 { |
4820 return preg_replace('/^([^{]+)\{/', '{', preg_replace('/\}([^}]+)$/', '}', $json)); |
4820 return preg_replace('/^([^{]+)\{/', '{', preg_replace('/\}([^}]+)$/', '}', $json)); |
4821 } |
4821 } |
4822 |
4822 |
4823 /** |
4823 /** |
4824 * Starts the profiler. |
4824 * Starts the profiler. |
4825 */ |
4825 */ |
4826 |
4826 |
4827 function profiler_start() |
4827 function profiler_start() |
4828 { |
4828 { |
4829 global $_profiler; |
4829 global $_profiler; |
4830 $_profiler = array(); |
4830 $_profiler = array(); |
4831 |
4831 |
4832 if ( !defined('ENANO_DEBUG') ) |
4832 if ( !defined('ENANO_DEBUG') ) |
4833 return false; |
4833 return false; |
4834 |
4834 |
4835 $_profiler[] = array( |
4835 $_profiler[] = array( |
4836 'point' => 'Profiling started', |
4836 'point' => 'Profiling started', |
4837 'time' => microtime_float(), |
4837 'time' => microtime_float(), |
4838 'backtrace' => false, |
4838 'backtrace' => false, |
4839 'mem' => false |
4839 'mem' => false |
4840 ); |
4840 ); |
4841 if ( function_exists('memory_get_usage') ) |
4841 if ( function_exists('memory_get_usage') ) |
4842 { |
4842 { |
4843 $_profiler[ count($_profiler) - 1 ]['mem'] = memory_get_usage(); |
4843 $_profiler[ count($_profiler) - 1 ]['mem'] = memory_get_usage(); |
4844 } |
4844 } |
4845 } |
4845 } |
4846 |
4846 |
4847 /** |
4847 /** |
4848 * Logs something in the profiler. |
4848 * Logs something in the profiler. |
4849 * @param string Point name or message |
4849 * @param string Point name or message |
4852 * @return resource Event ID |
4852 * @return resource Event ID |
4853 */ |
4853 */ |
4854 |
4854 |
4855 function profiler_log($point, $allow_backtrace = true, $parent_event = false) |
4855 function profiler_log($point, $allow_backtrace = true, $parent_event = false) |
4856 { |
4856 { |
4857 if ( !defined('ENANO_DEBUG') ) |
4857 if ( !defined('ENANO_DEBUG') ) |
4858 return false; |
4858 return false; |
4859 |
4859 |
4860 global $_profiler; |
4860 global $_profiler; |
4861 $backtrace = false; |
4861 $backtrace = false; |
4862 if ( $allow_backtrace && function_exists('debug_print_backtrace') ) |
4862 if ( $allow_backtrace && function_exists('debug_print_backtrace') ) |
4863 { |
4863 { |
4864 list(, $backtrace) = explode("\n", enano_debug_print_backtrace(true)); |
4864 list(, $backtrace) = explode("\n", enano_debug_print_backtrace(true)); |
4865 } |
4865 } |
4866 $_profiler[] = array( |
4866 $_profiler[] = array( |
4867 'point' => $point, |
4867 'point' => $point, |
4868 'time' => microtime_float(), |
4868 'time' => microtime_float(), |
4869 'backtrace' => $backtrace, |
4869 'backtrace' => $backtrace, |
4870 'mem' => false, |
4870 'mem' => false, |
4871 'parent_event' => $parent_event |
4871 'parent_event' => $parent_event |
4872 ); |
4872 ); |
4873 if ( function_exists('memory_get_usage') ) |
4873 if ( function_exists('memory_get_usage') ) |
4874 { |
4874 { |
4875 $_profiler[ count($_profiler) - 1 ]['mem'] = memory_get_usage(); |
4875 $_profiler[ count($_profiler) - 1 ]['mem'] = memory_get_usage(); |
4876 } |
4876 } |
4877 return count($_profiler) - 1; |
4877 return count($_profiler) - 1; |
4878 } |
4878 } |
4879 |
4879 |
4880 /** |
4880 /** |
4881 * Insert a message (an event without any time data) into the profiler. |
4881 * Insert a message (an event without any time data) into the profiler. |
4882 * @param string Message |
4882 * @param string Message |
4883 */ |
4883 */ |
4884 |
4884 |
4885 function profiler_message($message) |
4885 function profiler_message($message) |
4886 { |
4886 { |
4887 if ( !defined('ENANO_DEBUG') ) |
4887 if ( !defined('ENANO_DEBUG') ) |
4888 return false; |
4888 return false; |
4889 |
4889 |
4890 global $_profiler; |
4890 global $_profiler; |
4891 |
4891 |
4892 $_profiler[] = array( |
4892 $_profiler[] = array( |
4893 'message' => $message, |
4893 'message' => $message, |
4894 ); |
4894 ); |
4895 } |
4895 } |
4896 |
4896 |
4897 /** |
4897 /** |
4898 * Returns the profiler's data (so far). |
4898 * Returns the profiler's data (so far). |
4899 * @return array |
4899 * @return array |
4900 */ |
4900 */ |
4901 |
4901 |
4902 function profiler_dump() |
4902 function profiler_dump() |
4903 { |
4903 { |
4904 return $GLOBALS['_profiler']; |
4904 return $GLOBALS['_profiler']; |
4905 } |
4905 } |
4906 |
4906 |
4907 /** |
4907 /** |
4908 * Generates an HTML version of the performance profile. Not localized because only used as a debugging tool. |
4908 * Generates an HTML version of the performance profile. Not localized because only used as a debugging tool. |
4909 * @return string |
4909 * @return string |
4910 */ |
4910 */ |
4911 |
4911 |
4912 function profiler_make_html() |
4912 function profiler_make_html() |
4913 { |
4913 { |
4914 if ( !defined('ENANO_DEBUG') ) |
4914 if ( !defined('ENANO_DEBUG') ) |
4915 return ''; |
4915 return ''; |
4916 |
4916 |
4917 $profile = profiler_dump(); |
4917 $profile = profiler_dump(); |
4918 |
4918 |
4919 $html = '<div class="tblholder">'; |
4919 $html = '<div class="tblholder">'; |
4920 $html .= '<table border="0" cellspacing="1" cellpadding="4">'; |
4920 $html .= '<table border="0" cellspacing="1" cellpadding="4">'; |
4921 |
4921 |
4922 $time_start = $time_last = $profile[0]['time']; |
4922 $time_start = $time_last = $profile[0]['time']; |
4923 |
4923 |
4924 foreach ( $profile as $i => $entry ) |
4924 foreach ( $profile as $i => $entry ) |
4925 { |
4925 { |
4926 // $time_since_last = $entry['time'] - $time_last; |
4926 // $time_since_last = $entry['time'] - $time_last; |
4927 // if ( $time_since_last < 0.01 ) |
4927 // if ( $time_since_last < 0.01 ) |
4928 // continue; |
4928 // continue; |
4929 |
4929 |
4930 if ( isset($entry['message']) ) |
4930 if ( isset($entry['message']) ) |
4931 { |
4931 { |
4932 $html .= "<!-- ########################################################## -->\n<tr>\n <th colspan=\"2\">Message $i</th>\n</tr>"; |
4932 $html .= "<!-- ########################################################## -->\n<tr>\n <th colspan=\"2\">Message $i</th>\n</tr>"; |
4933 |
4933 |
4934 $html .= '<tr>' . "\n"; |
4934 $html .= '<tr>' . "\n"; |
4935 $html .= ' <td class="row2">Message:</td>' . "\n"; |
4935 $html .= ' <td class="row2">Message:</td>' . "\n"; |
4936 $html .= ' <td class="row1">' . htmlspecialchars($entry['message']) . '</td>' . "\n"; |
4936 $html .= ' <td class="row1">' . htmlspecialchars($entry['message']) . '</td>' . "\n"; |
4937 $html .= '</tr>' . "\n"; |
4937 $html .= '</tr>' . "\n"; |
4938 continue; |
4938 continue; |
4939 } |
4939 } |
4940 |
4940 |
4941 $html .= "<!-- ########################################################## -->\n<tr>\n <th colspan=\"2\">Event $i</th>\n</tr>"; |
4941 $html .= "<!-- ########################################################## -->\n<tr>\n <th colspan=\"2\">Event $i</th>\n</tr>"; |
4942 |
4942 |
4943 $html .= '<tr>' . "\n"; |
4943 $html .= '<tr>' . "\n"; |
4944 $html .= ' <td class="row2">Event:</td>' . "\n"; |
4944 $html .= ' <td class="row2">Event:</td>' . "\n"; |
4945 $html .= ' <td class="row1">' . htmlspecialchars($entry['point']) . '</td>' . "\n"; |
4945 $html .= ' <td class="row1">' . htmlspecialchars($entry['point']) . '</td>' . "\n"; |
4946 $html .= '</tr>' . "\n"; |
4946 $html .= '</tr>' . "\n"; |
4947 |
4947 |
4948 $time = $entry['time'] - $time_start; |
4948 $time = $entry['time'] - $time_start; |
4949 |
4949 |
4950 $html .= '<tr>' . "\n"; |
4950 $html .= '<tr>' . "\n"; |
4951 $html .= ' <td class="row2">Time since start:</td>' . "\n"; |
4951 $html .= ' <td class="row2">Time since start:</td>' . "\n"; |
4952 $html .= ' <td class="row1">' . $time . 's</td>' . "\n"; |
4952 $html .= ' <td class="row1">' . $time . 's</td>' . "\n"; |
4953 $html .= '</tr>' . "\n"; |
4953 $html .= '</tr>' . "\n"; |
4954 |
4954 |
4955 $time_label = 'Time since last event:'; |
4955 $time_label = 'Time since last event:'; |
4956 if ( $entry['parent_event'] && is_int($entry['parent_event']) && isset($profile[$entry['parent_event']]) ) |
4956 if ( $entry['parent_event'] && is_int($entry['parent_event']) && isset($profile[$entry['parent_event']]) ) |
4957 { |
4957 { |
4958 $time_last = $profile[$entry['parent_event']]['time']; |
4958 $time_last = $profile[$entry['parent_event']]['time']; |
4959 $time_label = "Time since event #{$entry['parent_event']}:"; |
4959 $time_label = "Time since event #{$entry['parent_event']}:"; |
4960 } |
4960 } |
4961 |
4961 |
4962 $time = $entry['time'] - $time_last; |
4962 $time = $entry['time'] - $time_last; |
4963 if ( $time < 0.0001 ) |
4963 if ( $time < 0.0001 ) |
4964 $time_html = 'Marginal'; |
4964 $time_html = 'Marginal'; |
4965 else |
4965 else |
4966 $time_html = number_format($time, 6) . "s"; |
4966 $time_html = number_format($time, 6) . "s"; |
4967 |
4967 |
4968 if ( $time > 0.02 ) |
4968 if ( $time > 0.02 ) |
4969 $time_html = "<span style=\"background-color: #a00; padding: 4px; color: #fff; font-weight: bold;\">$time_html</span>"; |
4969 $time_html = "<span style=\"background-color: #a00; padding: 4px; color: #fff; font-weight: bold;\">$time_html</span>"; |
4970 |
4970 |
4971 $html .= '<tr>' . "\n"; |
4971 $html .= '<tr>' . "\n"; |
4972 $html .= ' <td class="row2">' . $time_label . '</td>' . "\n"; |
4972 $html .= ' <td class="row2">' . $time_label . '</td>' . "\n"; |
4973 $html .= ' <td class="row1">' . $time_html . '</td>' . "\n"; |
4973 $html .= ' <td class="row1">' . $time_html . '</td>' . "\n"; |
4974 $html .= '</tr>' . "\n"; |
4974 $html .= '</tr>' . "\n"; |
4975 |
4975 |
4976 if ( $entry['backtrace'] ) |
4976 if ( $entry['backtrace'] ) |
4977 { |
4977 { |
4978 $html .= '<tr>' . "\n"; |
4978 $html .= '<tr>' . "\n"; |
4979 $html .= ' <td class="row2">Called from:</td>' . "\n"; |
4979 $html .= ' <td class="row2">Called from:</td>' . "\n"; |
4980 $html .= ' <td class="row1">' . htmlspecialchars($entry['backtrace']) . '</td>' . "\n"; |
4980 $html .= ' <td class="row1">' . htmlspecialchars($entry['backtrace']) . '</td>' . "\n"; |
4981 $html .= '</tr>' . "\n"; |
4981 $html .= '</tr>' . "\n"; |
4982 } |
4982 } |
4983 |
4983 |
4984 if ( $entry['mem'] ) |
4984 if ( $entry['mem'] ) |
4985 { |
4985 { |
4986 $html .= '<tr>' . "\n"; |
4986 $html .= '<tr>' . "\n"; |
4987 $html .= ' <td class="row2">Total mem usage:</td>' . "\n"; |
4987 $html .= ' <td class="row2">Total mem usage:</td>' . "\n"; |
4988 $html .= ' <td class="row1">' . htmlspecialchars($entry['mem']) . ' (bytes)</td>' . "\n"; |
4988 $html .= ' <td class="row1">' . htmlspecialchars($entry['mem']) . ' (bytes)</td>' . "\n"; |
4989 $html .= '</tr>' . "\n"; |
4989 $html .= '</tr>' . "\n"; |
4990 } |
4990 } |
4991 |
4991 |
4992 $html .= "\n"; |
4992 $html .= "\n"; |
4993 |
4993 |
4994 $time_last = $entry['time']; |
4994 $time_last = $entry['time']; |
4995 } |
4995 } |
4996 $html .= '</table></div>'; |
4996 $html .= '</table></div>'; |
4997 |
4997 |
4998 return $html; |
4998 return $html; |
4999 } |
4999 } |
5000 |
5000 |
5001 // Might as well start the profiler, it has no external dependencies except from this file. |
5001 // Might as well start the profiler, it has no external dependencies except from this file. |
5002 profiler_start(); |
5002 profiler_start(); |
5003 |
5003 |
5008 * @return int |
5008 * @return int |
5009 */ |
5009 */ |
5010 |
5010 |
5011 function get_char_count($string, $char) |
5011 function get_char_count($string, $char) |
5012 { |
5012 { |
5013 $char = substr($char, 0, 1); |
5013 $char = substr($char, 0, 1); |
5014 $count = 0; |
5014 $count = 0; |
5015 for ( $i = 0; $i < strlen($string); $i++ ) |
5015 for ( $i = 0; $i < strlen($string); $i++ ) |
5016 { |
5016 { |
5017 if ( $string{$i} == $char ) |
5017 if ( $string{$i} == $char ) |
5018 $count++; |
5018 $count++; |
5019 } |
5019 } |
5020 return $count; |
5020 return $count; |
5021 } |
5021 } |
5022 |
5022 |
5023 /** |
5023 /** |
5024 * Returns the number of lines in a string. |
5024 * Returns the number of lines in a string. |
5025 * @param string String to check |
5025 * @param string String to check |
5026 * @return int |
5026 * @return int |
5027 */ |
5027 */ |
5028 |
5028 |
5029 function get_line_count($string) |
5029 function get_line_count($string) |
5030 { |
5030 { |
5031 return ( get_char_count($string, "\n") ) + 1; |
5031 return ( get_char_count($string, "\n") ) + 1; |
5032 } |
5032 } |
5033 |
5033 |
5034 if ( !function_exists('sys_get_temp_dir') ) |
5034 if ( !function_exists('sys_get_temp_dir') ) |
5035 { |
5035 { |
5036 // Based on http://www.phpit.net/ |
5036 // Based on http://www.phpit.net/ |
5037 // article/creating-zip-tar-archives-dynamically-php/2/ |
5037 // article/creating-zip-tar-archives-dynamically-php/2/ |
5038 /** |
5038 /** |
5039 * Attempt to get the system's temp directory. |
5039 * Attempt to get the system's temp directory. |
5040 * @return string or bool false on failure |
5040 * @return string or bool false on failure |
5041 */ |
5041 */ |
5042 |
5042 |
5043 function sys_get_temp_dir() |
5043 function sys_get_temp_dir() |
5044 { |
5044 { |
5045 // Try to get from environment variable |
5045 // Try to get from environment variable |
5046 if ( !empty($_ENV['TMP']) ) |
5046 if ( !empty($_ENV['TMP']) ) |
5047 { |
5047 { |
5048 return realpath( $_ENV['TMP'] ); |
5048 return realpath( $_ENV['TMP'] ); |
5049 } |
5049 } |
5050 else if ( !empty($_ENV['TMPDIR']) ) |
5050 else if ( !empty($_ENV['TMPDIR']) ) |
5051 { |
5051 { |
5052 return realpath( $_ENV['TMPDIR'] ); |
5052 return realpath( $_ENV['TMPDIR'] ); |
5053 } |
5053 } |
5054 else if ( !empty($_ENV['TEMP']) ) |
5054 else if ( !empty($_ENV['TEMP']) ) |
5055 { |
5055 { |
5056 return realpath( $_ENV['TEMP'] ); |
5056 return realpath( $_ENV['TEMP'] ); |
5057 } |
5057 } |
5058 |
5058 |
5059 // Detect by creating a temporary file |
5059 // Detect by creating a temporary file |
5060 else |
5060 else |
5061 { |
5061 { |
5062 // Try to use system's temporary directory |
5062 // Try to use system's temporary directory |
5063 // as random name shouldn't exist |
5063 // as random name shouldn't exist |
5064 $temp_file = tempnam( md5(uniqid(rand(), TRUE)), '' ); |
5064 $temp_file = tempnam( md5(uniqid(rand(), TRUE)), '' ); |
5065 if ( $temp_file ) |
5065 if ( $temp_file ) |
5066 { |
5066 { |
5067 $temp_dir = realpath( dirname($temp_file) ); |
5067 $temp_dir = realpath( dirname($temp_file) ); |
5068 unlink( $temp_file ); |
5068 unlink( $temp_file ); |
5069 return $temp_dir; |
5069 return $temp_dir; |
5070 } |
5070 } |
5071 else |
5071 else |
5072 { |
5072 { |
5073 return FALSE; |
5073 return FALSE; |
5074 } |
5074 } |
5075 } |
5075 } |
5076 } |
5076 } |
5077 } |
5077 } |
5078 |
5078 |
5079 /** |
5079 /** |
5080 * Grabs and processes all rank information directly from the database. |
5080 * Grabs and processes all rank information directly from the database. |
5081 */ |
5081 */ |
5082 |
5082 |
5083 function fetch_rank_data() |
5083 function fetch_rank_data() |
5084 { |
5084 { |
5085 global $db, $session, $paths, $template, $plugins; // Common objects |
5085 global $db, $session, $paths, $template, $plugins; // Common objects |
5086 global $lang; |
5086 global $lang; |
5087 |
5087 |
5088 $sql = $session->generate_rank_sql(); |
5088 $sql = $session->generate_rank_sql(); |
5089 $q = $db->sql_query($sql); |
5089 $q = $db->sql_query($sql); |
5090 if ( !$q ) |
5090 if ( !$q ) |
5091 $db->_die(); |
5091 $db->_die(); |
5092 |
5092 |
5093 $GLOBALS['user_ranks'] = array(); |
5093 $GLOBALS['user_ranks'] = array(); |
5094 global $user_ranks; |
5094 global $user_ranks; |
5095 |
5095 |
5096 while ( $row = $db->fetchrow($q) ) |
5096 while ( $row = $db->fetchrow($q) ) |
5097 { |
5097 { |
5098 $user_id = $row['user_id']; |
5098 $user_id = $row['user_id']; |
5099 $username = $row['username']; |
5099 $username = $row['username']; |
5100 $row = $session->calculate_user_rank($row); |
5100 $row = $session->calculate_user_rank($row); |
5101 $user_ranks[$username] = $row; |
5101 $user_ranks[$username] = $row; |
5102 $user_ranks[$user_id] =& $user_ranks[$username]; |
5102 $user_ranks[$user_id] =& $user_ranks[$username]; |
5103 } |
5103 } |
5104 } |
5104 } |
5105 |
5105 |
5106 /** |
5106 /** |
5107 * Caches the computed user rank information. |
5107 * Caches the computed user rank information. |
5108 */ |
5108 */ |
5109 |
5109 |
5110 function generate_cache_userranks() |
5110 function generate_cache_userranks() |
5111 { |
5111 { |
5112 global $db, $session, $paths, $template, $plugins; // Common objects |
5112 global $db, $session, $paths, $template, $plugins; // Common objects |
5113 global $lang; |
5113 global $lang; |
5114 global $user_ranks; |
5114 global $user_ranks; |
5115 |
5115 |
5116 fetch_rank_data(); |
5116 fetch_rank_data(); |
5117 |
5117 |
5118 $user_ranks_stripped = array(); |
5118 $user_ranks_stripped = array(); |
5119 foreach ( $user_ranks as $key => $value ) |
5119 foreach ( $user_ranks as $key => $value ) |
5120 { |
5120 { |
5121 if ( is_int($key) ) |
5121 if ( is_int($key) ) |
5122 $user_ranks_stripped[$key] = $value; |
5122 $user_ranks_stripped[$key] = $value; |
5123 } |
5123 } |
5124 |
5124 |
5125 $ranks_exported = "<?php\n\n// Automatically generated user rank cache.\nglobal \$user_ranks;\n" . '$user_ranks = ' . $lang->var_export_string($user_ranks_stripped) . ';'; |
5125 $ranks_exported = "<?php\n\n// Automatically generated user rank cache.\nglobal \$user_ranks;\n" . '$user_ranks = ' . $lang->var_export_string($user_ranks_stripped) . ';'; |
5126 $uid_map = array(); |
5126 $uid_map = array(); |
5127 foreach ( $user_ranks as $id => $row ) |
5127 foreach ( $user_ranks as $id => $row ) |
5128 { |
5128 { |
5129 if ( !is_int($id) ) |
5129 if ( !is_int($id) ) |
5130 { |
5130 { |
5131 $username = $id; |
5131 $username = $id; |
5132 continue; |
5132 continue; |
5133 } |
5133 } |
5134 |
5134 |
5135 $un_san = addslashes($username); |
5135 $un_san = addslashes($username); |
5136 $ranks_exported .= "\n\$user_ranks['$un_san'] =& \$user_ranks[{$row['user_id']}];"; |
5136 $ranks_exported .= "\n\$user_ranks['$un_san'] =& \$user_ranks[{$row['user_id']}];"; |
5137 } |
5137 } |
5138 $ranks_exported .= "\n\ndefine('ENANO_RANKS_CACHE_LOADED', 1); \n?>"; |
5138 $ranks_exported .= "\n\ndefine('ENANO_RANKS_CACHE_LOADED', 1); \n?>"; |
5139 |
5139 |
5140 // open ranks cache file |
5140 // open ranks cache file |
5141 $fh = @fopen( ENANO_ROOT . '/cache/cache_ranks.php', 'w' ); |
5141 $fh = @fopen( ENANO_ROOT . '/cache/cache_ranks.php', 'w' ); |
5142 if ( !$fh ) |
5142 if ( !$fh ) |
5143 return false; |
5143 return false; |
5144 fwrite($fh, $ranks_exported); |
5144 fwrite($fh, $ranks_exported); |
5145 fclose($fh); |
5145 fclose($fh); |
5146 |
5146 |
5147 return true; |
5147 return true; |
5148 } |
5148 } |
5149 |
5149 |
5150 /** |
5150 /** |
5151 * Loads the rank data, first attempting the cache file and then the database. |
5151 * Loads the rank data, first attempting the cache file and then the database. |
5152 */ |
5152 */ |
5153 |
5153 |
5154 function load_rank_data() |
5154 function load_rank_data() |
5155 { |
5155 { |
5156 if ( file_exists( ENANO_ROOT . '/cache/cache_ranks.php' ) ) |
5156 if ( file_exists( ENANO_ROOT . '/cache/cache_ranks.php' ) ) |
5157 { |
5157 { |
5158 @include(ENANO_ROOT . '/cache/cache_ranks.php'); |
5158 @include(ENANO_ROOT . '/cache/cache_ranks.php'); |
5159 } |
5159 } |
5160 if ( !defined('ENANO_RANKS_CACHE_LOADED') ) |
5160 if ( !defined('ENANO_RANKS_CACHE_LOADED') ) |
5161 { |
5161 { |
5162 fetch_rank_data(); |
5162 fetch_rank_data(); |
5163 } |
5163 } |
5164 } |
5164 } |
5165 |
5165 |
5166 /** |
5166 /** |
5167 * Function to purge all caches used in Enano. Useful for upgrades, maintenance, backing the site up, etc. |
5167 * Function to purge all caches used in Enano. Useful for upgrades, maintenance, backing the site up, etc. |
5168 */ |
5168 */ |
5169 |
5169 |
5170 function purge_all_caches() |
5170 function purge_all_caches() |
5171 { |
5171 { |
5172 global $cache; |
5172 global $cache; |
5173 if ( $dh = opendir(ENANO_ROOT . '/cache') ) |
5173 if ( $dh = opendir(ENANO_ROOT . '/cache') ) |
5174 { |
5174 { |
5175 $cache->purge('page_meta'); |
5175 $cache->purge('page_meta'); |
5176 $cache->purge('anon_sidebar'); |
5176 $cache->purge('anon_sidebar'); |
5177 $cache->purge('plugins'); |
5177 $cache->purge('plugins'); |
5178 $cache->purge('wiki_edit_notice'); |
5178 $cache->purge('wiki_edit_notice'); |
5179 |
5179 |
5180 $data_files = array( |
5180 $data_files = array( |
5181 'aes_decrypt.php', |
5181 'aes_decrypt.php', |
5182 // ranks cache is stored using a custom engine (not enano's default cache) |
5182 // ranks cache is stored using a custom engine (not enano's default cache) |
5183 'cache_ranks.php' |
5183 'cache_ranks.php' |
5184 ); |
5184 ); |
5185 while ( $file = @readdir($dh) ) |
5185 while ( $file = @readdir($dh) ) |
5186 { |
5186 { |
5187 $fullpath = ENANO_ROOT . "/cache/$file"; |
5187 $fullpath = ENANO_ROOT . "/cache/$file"; |
5188 // we don't want to mess with directories |
5188 // we don't want to mess with directories |
5189 if ( !is_file($fullpath) ) |
5189 if ( !is_file($fullpath) ) |
5190 continue; |
5190 continue; |
5191 |
5191 |
5192 // data files |
5192 // data files |
5193 if ( in_array($file, $data_files) ) |
5193 if ( in_array($file, $data_files) ) |
5194 unlink($fullpath); |
5194 unlink($fullpath); |
5195 // template files |
5195 // template files |
5196 else if ( preg_match('/\.(?:tpl|css)\.php$/', $file) ) |
5196 else if ( preg_match('/\.(?:tpl|css)\.php$/', $file) ) |
5197 unlink($fullpath); |
5197 unlink($fullpath); |
5198 // compressed javascript |
5198 // compressed javascript |
5199 else if ( preg_match('/^jsres_(?:[A-z0-9_-]+)\.js\.json$/', $file) ) |
5199 else if ( preg_match('/^jsres_(?:[A-z0-9_-]+)\.js\.json$/', $file) ) |
5200 unlink($fullpath); |
5200 unlink($fullpath); |
5201 // tinymce stuff |
5201 // tinymce stuff |
5202 else if ( preg_match('/^tiny_mce_(?:[a-f0-9]+)\.gz$/', $file) ) |
5202 else if ( preg_match('/^tiny_mce_(?:[a-f0-9]+)\.gz$/', $file) ) |
5203 unlink($fullpath); |
5203 unlink($fullpath); |
5204 // language files |
5204 // language files |
5205 else if ( preg_match('/^lang_json_(?:[a-f0-9]+?)\.php$/', $file) || preg_match('/^(?:cache_)?lang_(?:[0-9]+?)\.php$/', $file) ) |
5205 else if ( preg_match('/^lang_json_(?:[a-f0-9]+?)\.php$/', $file) || preg_match('/^(?:cache_)?lang_(?:[0-9]+?)\.php$/', $file) ) |
5206 unlink($fullpath); |
5206 unlink($fullpath); |
5207 } |
5207 } |
5208 return true; |
5208 return true; |
5209 } |
5209 } |
5210 return false; |
5210 return false; |
5211 } |
5211 } |
5212 |
5212 |
5213 /** |
5213 /** |
5214 * Implementation of the "which" command in native PHP. |
5214 * Implementation of the "which" command in native PHP. |
5215 * @param string command |
5215 * @param string command |
5216 * @return string path to executable, or false on failure |
5216 * @return string path to executable, or false on failure |
5217 */ |
5217 */ |
5218 |
5218 |
5219 function which($executable) |
5219 function which($executable) |
5220 { |
5220 { |
5221 $path = ( isset($_ENV['PATH']) ) ? $_ENV['PATH'] : ( isset($_SERVER['PATH']) ? $_SERVER['PATH'] : false ); |
5221 $path = ( isset($_ENV['PATH']) ) ? $_ENV['PATH'] : ( isset($_SERVER['PATH']) ? $_SERVER['PATH'] : false ); |
5222 if ( !$path ) |
5222 if ( !$path ) |
5223 // couldn't get OS's PATH |
5223 // couldn't get OS's PATH |
5224 return false; |
5224 return false; |
5225 |
5225 |
5226 $win32 = ( PHP_OS == 'WINNT' || PHP_OS == 'WIN32' ); |
5226 $win32 = ( PHP_OS == 'WINNT' || PHP_OS == 'WIN32' ); |
5227 $extensions = $win32 ? array('.exe', '.com', '.bat') : array(''); |
5227 $extensions = $win32 ? array('.exe', '.com', '.bat') : array(''); |
5228 $separator = $win32 ? ';' : ':'; |
5228 $separator = $win32 ? ';' : ':'; |
5229 $paths = explode($separator, $path); |
5229 $paths = explode($separator, $path); |
5230 foreach ( $paths as $dir ) |
5230 foreach ( $paths as $dir ) |
5231 { |
5231 { |
5232 foreach ( $extensions as $ext ) |
5232 foreach ( $extensions as $ext ) |
5233 { |
5233 { |
5234 $fullpath = "$dir/{$executable}{$ext}"; |
5234 $fullpath = "$dir/{$executable}{$ext}"; |
5235 if ( @file_exists($fullpath) && @is_executable($fullpath) ) |
5235 if ( @file_exists($fullpath) && @is_executable($fullpath) ) |
5236 { |
5236 { |
5237 return $fullpath; |
5237 return $fullpath; |
5238 } |
5238 } |
5239 } |
5239 } |
5240 } |
5240 } |
5241 return false; |
5241 return false; |
5242 } |
5242 } |
5243 |
5243 |
5244 /** |
5244 /** |
5245 * Properly test a file or directory for writability. Used in various places around installer. |
5245 * Properly test a file or directory for writability. Used in various places around installer. |
5246 * @param string File or directory to test |
5246 * @param string File or directory to test |
5247 * @return bool |
5247 * @return bool |
5248 */ |
5248 */ |
5249 |
5249 |
5250 function write_test($filename) |
5250 function write_test($filename) |
5251 { |
5251 { |
5252 // We need to actually _open_ the file to make sure it can be written, because sometimes this fails even when is_writable() returns |
5252 // We need to actually _open_ the file to make sure it can be written, because sometimes this fails even when is_writable() returns |
5253 // true on Windows/IIS servers. Don't ask me why. |
5253 // true on Windows/IIS servers. Don't ask me why. |
5254 |
5254 |
5255 $file = ENANO_ROOT . '/' . $filename; |
5255 $file = ENANO_ROOT . '/' . $filename; |
5256 if ( is_dir($file) ) |
5256 if ( is_dir($file) ) |
5257 { |
5257 { |
5258 $file = rtrim($file, '/') . '/' . 'enanoinstalltest.txt'; |
5258 $file = rtrim($file, '/') . '/' . 'enanoinstalltest.txt'; |
5259 if ( file_exists($file) ) |
5259 if ( file_exists($file) ) |
5260 { |
5260 { |
5261 $fp = @fopen($file, 'a+'); |
5261 $fp = @fopen($file, 'a+'); |
5262 if ( !$fp ) |
5262 if ( !$fp ) |
5263 return false; |
5263 return false; |
5264 fclose($fp); |
5264 fclose($fp); |
5265 unlink($file); |
5265 unlink($file); |
5266 return true; |
5266 return true; |
5267 } |
5267 } |
5268 else |
5268 else |
5269 { |
5269 { |
5270 $fp = @fopen($file, 'w'); |
5270 $fp = @fopen($file, 'w'); |
5271 if ( !$fp ) |
5271 if ( !$fp ) |
5272 return false; |
5272 return false; |
5273 fclose($fp); |
5273 fclose($fp); |
5274 unlink($file); |
5274 unlink($file); |
5275 return true; |
5275 return true; |
5276 } |
5276 } |
5277 } |
5277 } |
5278 else |
5278 else |
5279 { |
5279 { |
5280 if ( file_exists($file) ) |
5280 if ( file_exists($file) ) |
5281 { |
5281 { |
5282 $fp = @fopen($file, 'a+'); |
5282 $fp = @fopen($file, 'a+'); |
5283 if ( !$fp ) |
5283 if ( !$fp ) |
5284 return false; |
5284 return false; |
5285 fclose($fp); |
5285 fclose($fp); |
5286 return true; |
5286 return true; |
5287 } |
5287 } |
5288 else |
5288 else |
5289 { |
5289 { |
5290 $fp = @fopen($file, 'w'); |
5290 $fp = @fopen($file, 'w'); |
5291 if ( !$fp ) |
5291 if ( !$fp ) |
5292 return false; |
5292 return false; |
5293 fclose($fp); |
5293 fclose($fp); |
5294 return true; |
5294 return true; |
5295 } |
5295 } |
5296 } |
5296 } |
5297 } |
5297 } |
5298 |
5298 |
5299 /** |
5299 /** |
5300 * Get the appropriate crypto backend for this server |
5300 * Get the appropriate crypto backend for this server |
5301 * @return string |
5301 * @return string |
5302 */ |
5302 */ |
5303 |
5303 |
5304 function install_get_crypto_backend() |
5304 function install_get_crypto_backend() |
5305 { |
5305 { |
5306 $crypto_backend = 'none'; |
5306 $crypto_backend = 'none'; |
5307 |
5307 |
5308 // Extension test: BCMath |
5308 // Extension test: BCMath |
5309 if ( function_exists('bcadd') ) |
5309 if ( function_exists('bcadd') ) |
5310 $crypto_backend = 'bcmath'; |
5310 $crypto_backend = 'bcmath'; |
5311 |
5311 |
5312 // Extension test: Big_Int |
5312 // Extension test: Big_Int |
5313 if ( function_exists('bi_from_str') ) |
5313 if ( function_exists('bi_from_str') ) |
5314 $crypto_backend = 'bigint'; |
5314 $crypto_backend = 'bigint'; |
5315 |
5315 |
5316 // Extension test: GMP |
5316 // Extension test: GMP |
5317 if ( function_exists('gmp_init') ) |
5317 if ( function_exists('gmp_init') ) |
5318 $crypto_backend = 'gmp'; |
5318 $crypto_backend = 'gmp'; |
5319 |
5319 |
5320 return $crypto_backend; |
5320 return $crypto_backend; |
5321 } |
5321 } |
5322 |
5322 |