4 * Library of functions for handling input validation
5 * and some HTML generation
6 * This library is a combination of bits of lib/weblib.php
7 * and lib/moodlelib.php from moodle
8 * http://moodle.org || http://sourceforge.net/projects/moodle
9 * Copyright (C) 2001-2003 Martin Dougiamas http://dougiamas.com
10 * @author Martin Dougiamas and many others
11 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
15 /// PARAMETER HANDLING ////////////////////////////////////////////////////
18 * Returns a particular value for the named variable, taken from
19 * POST or GET. If the parameter doesn't exist then an error is
20 * thrown because we require this variable.
22 * This function should be used to initialise all required values
23 * in a script that are based on parameters. Usually it will be
25 * $id = required_param('id');
27 * @param string $varname the name of the parameter variable we want
28 * @param int $options a bit field that specifies any cleaning needed
31 function required_param($varname, $options=PARAM_CLEAN
) {
33 // detect_unchecked_vars addition
35 if (!empty($CFG->detect_unchecked_vars
)) {
36 global $UNCHECKED_VARS;
37 unset ($UNCHECKED_VARS->vars
[$varname]);
40 if (isset($_POST[$varname])) { // POST has precedence
41 $param = $_POST[$varname];
42 } else if (isset($_GET[$varname])) {
43 $param = $_GET[$varname];
45 error('A required parameter ('.$varname.') was missing');
48 return clean_param($param, $options);
52 * Returns a particular value for the named variable, taken from
53 * POST or GET, otherwise returning a given default.
55 * This function should be used to initialise all optional values
56 * in a script that are based on parameters. Usually it will be
58 * $name = optional_param('name', 'Fred');
60 * @param string $varname the name of the parameter variable we want
61 * @param mixed $default the default value to return if nothing is found
62 * @param int $options a bit field that specifies any cleaning needed
65 function optional_param($varname, $default=NULL, $options=PARAM_CLEAN
) {
67 // detect_unchecked_vars addition
69 if (!empty($CFG->detect_unchecked_vars
)) {
70 global $UNCHECKED_VARS;
71 unset ($UNCHECKED_VARS->vars
[$varname]);
74 if (isset($_POST[$varname])) { // POST has precedence
75 $param = $_POST[$varname];
76 } else if (isset($_GET[$varname])) {
77 $param = $_GET[$varname];
82 return clean_param($param, $options);
87 * Used by {@link optional_param()} and {@link required_param()} to
88 * clean the variables and/or cast to specific types, based on
91 * $course->format = clean_param($course->format, PARAM_ALPHA);
92 * $selectedgrade_item = clean_param($selectedgrade_item, PARAM_CLEAN);
100 * @uses PARAM_ALPHANUM
102 * @uses PARAM_ALPHATEXT
104 * @uses PARAM_SAFEDIR
105 * @uses PARAM_CLEANFILE
110 * @uses PARAM_LOCALURL
111 * @uses PARAM_CLEANHTML
112 * @param mixed $param the variable we are cleaning
113 * @param int $options a bit field that specifies the cleaning needed. This field is specified by combining PARAM_* definitions together with a logical or.
116 function clean_param($param, $options) {
120 if (is_array($param)) { // Let's loop
122 foreach ($param as $key => $value) {
123 $newparam[$key] = clean_param($value, $options);
129 return $param; // Return raw value
132 //this corrupts data - Sven
133 //if ((string)$param == (string)(int)$param) { // It's just an integer
134 // return (int)$param;
137 if ($options & PARAM_CLEAN
) {
138 // this breaks backslashes in user input
139 // $param = stripslashes($param); // Needed by kses to work fine
140 $param = clean_text($param); // Sweep for scripts, etc
141 // and this unnecessarily escapes quotes, etc in user input
142 // $param = addslashes($param); // Restore original request parameter slashes
145 if ($options & PARAM_INT
) {
146 $param = (int)$param; // Convert to integer
149 if ($options & PARAM_ALPHA
) { // Remove everything not a-z
150 $param = eregi_replace('[^a-zA-Z]', '', $param);
153 if ($options & PARAM_ALPHANUM
) { // Remove everything not a-zA-Z0-9
154 $param = eregi_replace('[^A-Za-z0-9]', '', $param);
157 if ($options & PARAM_ALPHAEXT
) { // Remove everything not a-zA-Z/_-
158 $param = eregi_replace('[^a-zA-Z/_-]', '', $param);
161 if ($options & PARAM_BOOL
) { // Convert to 1 or 0
162 $tempstr = strtolower($param);
163 if ($tempstr == 'on') {
165 } else if ($tempstr == 'off') {
168 $param = empty($param) ?
0 : 1;
172 if ($options & PARAM_NOTAGS
) { // Strip all tags completely
173 $param = strip_tags($param);
176 if ($options & PARAM_SAFEDIR
) { // Remove everything not a-zA-Z0-9_-
177 $param = eregi_replace('[^a-zA-Z0-9_-]', '', $param);
180 if ($options & PARAM_CLEANFILE
) { // allow only safe characters
181 $param = clean_filename($param);
184 if ($options & PARAM_FILE
) { // Strip all suspicious characters from filename
185 $param = ereg_replace('[[:cntrl:]]|[<>"`\|\':\\/]', '', $param);
186 $param = ereg_replace('\.\.+', '', $param);
192 if ($options & PARAM_PATH
) { // Strip all suspicious characters from file path
193 $param = str_replace('\\\'', '\'', $param);
194 $param = str_replace('\\"', '"', $param);
195 $param = str_replace('\\', '/', $param);
196 $param = ereg_replace('[[:cntrl:]]|[<>"`\|\':]', '', $param);
197 $param = ereg_replace('\.\.+', '', $param);
198 $param = ereg_replace('//+', '/', $param);
199 $param = ereg_replace('/(\./)+', '/', $param);
202 if ($options & PARAM_HOST
) { // allow FQDN or IPv4 dotted quad
203 preg_replace('/[^\.\d\w-]/','', $param ); // only allowed chars
204 // match ipv4 dotted quad
205 if (preg_match('/(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/',$param, $match)){
206 // confirm values are ok
210 ||
$match[4] > 255 ) {
211 // hmmm, what kind of dotted quad is this?
214 } elseif ( preg_match('/^[\w\d\.-]+$/', $param) // dots, hyphens, numbers
215 && !preg_match('/^[\.-]/', $param) // no leading dots/hyphens
216 && !preg_match('/[\.-]$/', $param) // no trailing dots/hyphens
218 // all is ok - $param is respected
225 if ($options & PARAM_URL
) { // allow safe ftp, http, mailto urls
227 include_once($CFG->dirroot
. 'lib/validateurlsyntax.php');
230 // Parameters to validateurlsyntax()
232 // s? scheme is optional
236 // E? mailto optional
237 // u- user section not allowed
238 // P- password not allowed
239 // a? address optional
240 // I? Numeric IP address optional (can use IP or domain)
241 // p- port not allowed -- restrict to default port
242 // f? "file" path section optional
243 // q? query section optional
244 // r? fragment (anchor) optional
246 if (!empty($param) && validateUrlSyntax($param, 's?H?S?F?E?u-P-a?I?p-f?q?r?')) {
247 // all is ok, param is respected
249 $param =''; // not really ok
251 $options ^
= PARAM_URL
; // Turn off the URL bit so that simple PARAM_URLs don't test true for PARAM_LOCALURL
254 if ($options & PARAM_LOCALURL
) {
255 // assume we passed the PARAM_URL test...
256 // allow http absolute, root relative and relative URLs within wwwroot
257 if (!empty($param)) {
258 if (preg_match(':^/:', $param)) {
259 // root-relative, ok!
260 } elseif (preg_match('/^'.preg_quote($CFG->wwwroot
, '/').'/i',$param)) {
261 // absolute, and matches our wwwroot
263 // relative - let's make sure there are no tricks
264 if (validateUrlSyntax($param, 's-u-P-a-p-f+q?r?')) {
273 if ($options & PARAM_CLEANHTML
) {
274 // $param = stripslashes($param); // Remove any slashes
275 $param = clean_text($param); // Sweep for scripts, etc
276 // $param = trim($param); // Sweep for scripts, etc
283 * Retrieves the list of plugins available in the $plugin
284 * directory. Defaults to 'mod'.
286 * NOTE: To get the list of enabled modules, do
287 * get_records('modules', 'enabled', true) instead.
291 function get_list_of_plugins($plugin='mod', $exclude='') {
294 static $plugincache = array();
295 $plugincachename = $plugin . "_" . $exclude;
297 if (isset($plugincache[$plugincachename])) {
298 $plugins = $plugincache[$plugincachename];
301 $basedir = opendir($CFG->dirroot
. $plugin);
302 while (false !== ($dir = readdir($basedir))) {
303 $firstchar = substr($dir, 0, 1);
304 if ($firstchar == '.' or $dir == 'CVS' or $dir == '_vti_cnf' or $dir == $exclude) {
307 if (filetype($CFG->dirroot
. $plugin .'/'. $dir) != 'dir') {
315 $plugincache[$plugincachename] = $plugins;
320 // Adds a function to the variables used to cycle through plugin extensions
321 // to actions on objects
322 function listen_for_event($object_type, $event, $function) {
325 $CFG->event_hooks
[$object_type][$event][] = $function;
329 function plugin_hook($object_type,$event,$object = null) {
333 if (!empty($CFG->event_hooks
['all']['all']) && is_array($CFG->event_hooks
['all']['all'])) {
334 foreach($CFG->event_hooks
['all']['all'] as $hook) {
335 $object = $hook($object_type,$event,$object);
338 if (!empty($CFG->event_hooks
[$object_type]['all']) && is_array($CFG->event_hooks
[$object_type]['all'])) {
339 foreach($CFG->event_hooks
[$object_type]['all'] as $hook) {
340 $object = $hook($object_type,$event,$object);
343 if (!empty($CFG->event_hooks
['all'][$event]) && is_array($CFG->event_hooks
['all'][$event])) {
344 foreach($CFG->event_hooks
['all'][$event] as $hook) {
345 $object = $hook($object_type,$event,$object);
348 if (!empty($CFG->event_hooks
[$object_type][$event]) && is_array($CFG->event_hooks
[$object_type][$event])) {
349 foreach($CFG->event_hooks
[$object_type][$event] as $hook) {
350 $object = $hook($object_type,$event,$object);
358 function report_session_error() {
359 global $CFG, $FULLME;
361 //clear session cookies
362 setcookie('ElggSession'.$CFG->sessioncookie
, '', time() - 3600, $CFG->cookiepath
);
363 setcookie('ElggSessionTest'.$CFG->sessioncookie
, '', time() - 3600, $CFG->cookiepath
);
364 //increment database error counters
365 //if (isset($CFG->session_error_counter)) {
366 // set_config('session_error_counter', 1 + $CFG->session_error_counter);
368 // set_config('session_error_counter', 1);
370 //called from setup.php, so gettext module hasn't been loaded yet
371 redirect($FULLME, 'A server error that affects your login session was detected. Please login again or restart your browser.', 5);
376 * For security purposes, this function will check that the currently
377 * given sesskey (passed as a parameter to the script or this function)
378 * matches that of the current user.
380 * @param string $sesskey optionally provided sesskey
383 // function confirm_sesskey($sesskey=NULL) {
386 // if (!empty($USER->ignoresesskey) || !empty($CFG->ignoresesskey)) {
390 // if (empty($sesskey)) {
391 // $sesskey = required_param('sesskey'); // Check script parameters
394 // if (!isset($USER->sesskey)) {
398 // return ($USER->sesskey === $sesskey);
403 * Makes sure that $USER->sesskey exists, if $USER itself exists. It sets a new sesskey
404 * if one does not already exist, but does not overwrite existing sesskeys. Returns the
405 * sesskey string if $USER exists, or boolean false if not.
417 if (empty($USER->sesskey
)) {
418 $USER->sesskey
= random_string(10);
421 return $USER->sesskey
;
426 * Send an email to a specified user
429 * @param user $user A {@link $USER} object
430 * @param user $from A {@link $USER} object
431 * @param string $subject plain text subject line of the email
432 * @param string $messagetext plain text version of the message
433 * @param string $messagehtml complete html version of the message (optional)
434 * @param string $attachment a file on the filesystem
435 * @param string $attachname the name of the file (extension indicates MIME)
436 * @param bool $usetrueaddress determines whether $from email address should
437 * be sent out. Will be overruled by user profile setting for maildisplay
438 * @return bool|string Returns "true" if mail was sent OK, "emailstop" if email
439 * was blocked by user and "false" if there was another sort of error.
441 function email_to_user($user, $from, $subject, $messagetext, $messagehtml='', $attachment='', $attachname='', $usetrueaddress=true, $repyto='', $replytoname='') {
444 $textlib = textlib_get_instance();
446 include_once($CFG->libdir
.'/phpmailer/class.phpmailer.php');
453 if (over_bounce_threshold($user)) {
454 error_log("User $user->id (".fullname($user).") is over bounce threshold! Not sending.");
457 */ // this doesn't exist right now, we may bring it in later though.
459 $mail = new phpmailer
;
461 $mail->Version
= 'Elgg '; // mailer version (should have $CFG->version on here but we don't have it yet)
462 $mail->PluginDir
= $CFG->libdir
.'/phpmailer/'; // plugin directory (eg smtp plugin)
465 $mail->CharSet
= 'UTF-8'; // everything is now uft8
467 if (empty($CFG->smtphosts
)) {
468 $mail->IsMail(); // use PHP mail() = sendmail
469 } else if ($CFG->smtphosts
== 'qmail') {
470 $mail->IsQmail(); // use Qmail system
472 $mail->IsSMTP(); // use SMTP directly
473 if ($CFG->debug
> 7) {
475 $mail->SMTPDebug
= true;
477 $mail->Host
= $CFG->smtphosts
; // specify main and backup servers
479 if ($CFG->smtpuser
) { // Use SMTP authentication
480 $mail->SMTPAuth
= true;
481 $mail->Username
= $CFG->smtpuser
;
482 $mail->Password
= $CFG->smtppass
;
486 /* not here yet, leave it in just in case.
487 // make up an email address for handling bounces
488 if (!empty($CFG->handlebounces)) {
489 $modargs = 'B'.base64_encode(pack('V',$user->ident)).substr(md5($user->email),0,16);
490 $mail->Sender = generate_email_processing_address(0,$modargs);
493 $mail->Sender = $CFG->sysadminemail;
496 $mail->Sender
= $CFG->sysadminemail
; // for elgg. delete if we change the above.
498 // TODO add a preference for maildisplay
499 if (is_string($from)) { // So we can pass whatever we want if there is need
500 $mail->From
= $CFG->noreplyaddress
;
501 $mail->FromName
= $from;
502 } else if (empty($from)) { // make stuff up
503 $mail->From
= $CFG->sysadminemail
;
504 $mail->FromName
= $CFG->sitename
.' '.__gettext('Administrator');
505 } else if ($usetrueaddress and !empty($from->maildisplay
)) {
506 $mail->From
= $from->email
;
507 $mail->FromName
= $from->name
;
509 $mail->From
= $CFG->noreplyaddress
;
510 $mail->FromName
= $from->name
;
511 if (empty($replyto)) {
512 $mail->AddReplyTo($CFG->noreplyaddress
,__gettext('Do not reply'));
516 if (!empty($replyto)) {
517 $mail->AddReplyTo($replyto,$replytoname);
520 $mail->Subject
= $textlib->substr(stripslashes($subject), 0, 900);
522 $mail->AddAddress($user->email
, $user->name
);
524 $mail->WordWrap
= 79; // set word wrap
526 if (!empty($from->customheaders
)) { // Add custom headers
527 if (is_array($from->customheaders
)) {
528 foreach ($from->customheaders
as $customheader) {
529 $mail->AddCustomHeader($customheader);
532 $mail->AddCustomHeader($from->customheaders
);
536 if (!empty($from->priority
)) {
537 $mail->Priority
= $from->priority
;
540 //TODO add a user preference for this. right now just send plaintext
541 $user->mailformat
= 0;
542 if ($messagehtml && $user->mailformat
== 1) { // Don't ever send HTML to users who don't want it
544 $mail->Encoding
= 'quoted-printable'; // Encoding to use
545 $mail->Body
= $messagehtml;
546 $mail->AltBody
= "\n$messagetext\n";
548 $mail->IsHTML(false);
549 $mail->Body
= "\n$messagetext\n";
552 if ($attachment && $attachname) {
553 if (ereg( "\\.\\." ,$attachment )) { // Security check for ".." in dir path
554 $mail->AddAddress($CFG->sysadminemail
,$CFG->sitename
.' '.__gettext('Administrator'));
555 $mail->AddStringAttachment('Error in attachment. User attempted to attach a filename with a unsafe name.', 'error.txt', '8bit', 'text/plain');
557 require_once($CFG->libdir
.'/filelib.php');
558 $mimetype = mimeinfo('type', $attachname);
559 $mail->AddAttachment($attachment, $attachname, 'base64', $mimetype);
564 // set_send_count($user); // later
567 mtrace('ERROR: '. $mail->ErrorInfo
);
573 * Returns an array with all the filenames in
574 * all subdirectories, relative to the given rootdir.
575 * If excludefile is defined, then that file/directory is ignored
576 * If getdirs is true, then (sub)directories are included in the output
577 * If getfiles is true, then files are included in the output
578 * (at least one of these must be true!)
580 * @param string $rootdir ?
581 * @param string $excludefile If defined then the specified file/directory is ignored
582 * @param bool $descend ?
583 * @param bool $getdirs If true then (sub)directories are included in the output
584 * @param bool $getfiles If true then files are included in the output
585 * @return array An array with all the filenames in
586 * all subdirectories, relative to the given rootdir
587 * @todo Finish documenting this function. Add examples of $excludefile usage.
589 function get_directory_list($rootdir, $excludefile='', $descend=true, $getdirs=false, $getfiles=true) {
593 if (!$getdirs and !$getfiles) { // Nothing to show
597 if (!is_dir($rootdir)) { // Must be a directory
601 if (!$dir = opendir($rootdir)) { // Can't open it for some reason
605 while (false !== ($file = readdir($dir))) {
606 $firstchar = substr($file, 0, 1);
607 if ($firstchar == '.' or $file == 'CVS' or $file == $excludefile) {
610 $fullfile = $rootdir .'/'. $file;
611 if (filetype($fullfile) == 'dir') {
616 $subdirs = get_directory_list($fullfile, $excludefile, $descend, $getdirs, $getfiles);
617 foreach ($subdirs as $subdir) {
618 $dirs[] = $file .'/'. $subdir;
621 } else if ($getfiles) {
633 * handy function to loop through an array of files and resolve any filename conflicts
634 * both in the array of filenames and for what is already on disk.
637 function resolve_filename_collisions($destination,$files,$format='%s_%d.%s') {
638 foreach ($files as $k => $f) {
639 if (check_potential_filename($destination,$f,$files)) {
640 $bits = explode('.', $f);
641 for ($i = 1; true; $i++
) {
642 $try = sprintf($format, $bits[0], $i, $bits[1]);
643 if (!check_potential_filename($destination,$try,$files)) {
654 * @used by resolve_filename_collisions
656 function check_potential_filename($destination,$filename,$files) {
657 if (file_exists($destination.'/'.$filename)) {
660 if (count(array_keys($files,$filename)) > 1) {
667 * Adds up all the files in a directory and works out the size.
669 * @param string $rootdir ?
670 * @param string $excludefile ?
672 * @todo Finish documenting this function
674 function get_directory_size($rootdir, $excludefile='') {
677 $textlib = textlib_get_instance();
679 // do it this way if we can, it's much faster
680 if (!empty($CFG->pathtodu
) && is_executable(trim($CFG->pathtodu
))) {
681 $command = trim($CFG->pathtodu
).' -sk --apparent-size '.escapeshellarg($rootdir);
682 exec($command,$output,$return);
683 if (is_array($output)) {
684 return get_real_size(intval($output[0]).'k'); // we told it to return k.
690 if (!is_dir($rootdir)) { // Must be a directory
694 if (!$dir = @opendir
($rootdir)) { // Can't open it for some reason
698 while (false !== ($file = readdir($dir))) {
699 $firstchar = $textlib->substr($file, 0, 1);
700 if ($firstchar == '.' or $file == 'CVS' or $file == $excludefile) {
703 $fullfile = $rootdir .'/'. $file;
704 if (filetype($fullfile) == 'dir') {
705 $size +
= get_directory_size($fullfile, $excludefile);
707 $size +
= filesize($fullfile);
716 * Converts numbers like 10M into bytes.
718 * @param mixed $size The size to be converted
721 function get_real_size($size=0) {
725 $scan['GB'] = 1073741824;
726 $scan['Gb'] = 1073741824;
727 $scan['G'] = 1073741824;
728 $scan['g'] = 1073741824;
729 $scan['MB'] = 1048576;
730 $scan['Mb'] = 1048576;
731 $scan['M'] = 1048576;
732 $scan['m'] = 1048576;
738 while (list($key) = each($scan)) {
739 if ((strlen($size)>strlen($key))&&(substr($size, strlen($size) - strlen($key))==$key)) {
740 $size = substr($size, 0, strlen($size) - strlen($key)) * $scan[$key];
748 * Converts bytes into display form
750 * @param string $size ?
752 * @staticvar string $gb Localized string for size in gigabytes
753 * @staticvar string $mb Localized string for size in megabytes
754 * @staticvar string $kb Localized string for size in kilobytes
755 * @staticvar string $b Localized string for size in bytes
756 * @todo Finish documenting this function. Verify return type.
758 function display_size($size) {
760 static $gb, $mb, $kb, $b;
763 $gb = __gettext('GB');
764 $mb = __gettext('MB');
765 $kb = __gettext('KB');
766 $b = __gettext('bytes');
769 if ($size >= 1073741824) {
770 $size = round($size / 1073741824 * 10) / 10 . $gb;
771 } else if ($size >= 1048576) {
772 $size = round($size / 1048576 * 10) / 10 . $mb;
773 } else if ($size >= 1024) {
774 $size = round($size / 1024 * 10) / 10 . $kb;
776 $size = $size .' '. $b;
782 * Convert high ascii characters into low ascii
783 * This code is from http://kalsey.com/2004/07/dirify_in_php/
786 function convert_high_ascii($s) {
788 "!\xc0!" => 'A', # A`
789 "!\xe0!" => 'a', # a`
790 "!\xc1!" => 'A', # A'
791 "!\xe1!" => 'a', # a'
792 "!\xc2!" => 'A', # A^
793 "!\xe2!" => 'a', # a^
794 "!\xc4!" => 'Ae', # A:
795 "!\xe4!" => 'ae', # a:
796 "!\xc3!" => 'A', # A~
797 "!\xe3!" => 'a', # a~
798 "!\xc8!" => 'E', # E`
799 "!\xe8!" => 'e', # e`
800 "!\xc9!" => 'E', # E'
801 "!\xe9!" => 'e', # e'
802 "!\xca!" => 'E', # E^
803 "!\xea!" => 'e', # e^
804 "!\xcb!" => 'Ee', # E:
805 "!\xeb!" => 'ee', # e:
806 "!\xcc!" => 'I', # I`
807 "!\xec!" => 'i', # i`
808 "!\xcd!" => 'I', # I'
809 "!\xed!" => 'i', # i'
810 "!\xce!" => 'I', # I^
811 "!\xee!" => 'i', # i^
812 "!\xcf!" => 'Ie', # I:
813 "!\xef!" => 'ie', # i:
814 "!\xd2!" => 'O', # O`
815 "!\xf2!" => 'o', # o`
816 "!\xd3!" => 'O', # O'
817 "!\xf3!" => 'o', # o'
818 "!\xd4!" => 'O', # O^
819 "!\xf4!" => 'o', # o^
820 "!\xd6!" => 'Oe', # O:
821 "!\xf6!" => 'oe', # o:
822 "!\xd5!" => 'O', # O~
823 "!\xf5!" => 'o', # o~
824 "!\xd8!" => 'Oe', # O/
825 "!\xf8!" => 'oe', # o/
826 "!\xd9!" => 'U', # U`
827 "!\xf9!" => 'u', # u`
828 "!\xda!" => 'U', # U'
829 "!\xfa!" => 'u', # u'
830 "!\xdb!" => 'U', # U^
831 "!\xfb!" => 'u', # u^
832 "!\xdc!" => 'Ue', # U:
833 "!\xfc!" => 'ue', # u:
834 "!\xc7!" => 'C', # ,C
835 "!\xe7!" => 'c', # ,c
836 "!\xd1!" => 'N', # N~
837 "!\xf1!" => 'n', # n~
840 $find = array_keys($HighASCII);
841 $replace = array_values($HighASCII);
842 $s = preg_replace($find,$replace,$s);
847 * Cleans a given filename by removing suspicious or troublesome characters
848 * Only these are allowed:
851 * @param string $string ?
854 function clean_filename($string) {
855 $string = convert_high_ascii($string);
856 $string = eregi_replace("\.\.+", '', $string);
857 $string = preg_replace('/[^\.a-zA-Z\d\_-]/','_', $string ); // only allowed chars
858 $string = eregi_replace("_+", '_', $string);
865 * Function to raise the memory limit to a new value.
866 * Will respect the memory limit if it is higher, thus allowing
867 * settings in php.ini, apache conf or command line switches
870 * The memory limit should be expressed with a string (eg:'64M')
872 * @param string $newlimit the new memory limit
875 function raise_memory_limit ($newlimit) {
877 if (empty($newlimit)) {
881 $cur = @ini_get
('memory_limit');
883 // if php is compiled without --enable-memory-limits
884 // apparently memory_limit is set to ''
888 return true; // unlimited mem!
890 $cur = get_real_size($cur);
893 $new = get_real_size($newlimit);
895 ini_set('memory_limit', $newlimit);
902 * Converts string to lowercase using most compatible function available.
904 * @param string $string The string to convert to all lowercase characters.
905 * @param string $encoding The encoding on the string.
907 * @todo Add examples of calling this function with/without encoding types
909 function elgg_strtolower ($string, $encoding='') {
910 $textlib = textlib_get_instance();
911 return $textlib->strtolower($string, $encoding?
$encoding:'utf-8');
917 * Given a simple array, this shuffles it up just like shuffle()
918 * Unlike PHP's shuffle() ihis function works on any machine.
920 * @param array $array The array to be rearranged
923 function swapshuffle($array) {
925 srand ((double) microtime() * 10000000);
926 $last = count($array) - 1;
927 for ($i=0;$i<=$last;$i++
) {
928 $from = rand(0,$last);
930 $array[$i] = $array[$from];
931 $array[$from] = $curr;
937 * Like {@link swapshuffle()}, but works on associative arrays
939 * @param array $array The associative array to be rearranged
942 function swapshuffle_assoc($array) {
945 $newkeys = swapshuffle(array_keys($array));
946 foreach ($newkeys as $newkey) {
947 $newarray[$newkey] = $array[$newkey];
953 * Given an arbitrary array, and a number of draws,
954 * this function returns an array with that amount
955 * of items. The indexes are retained.
957 * @param array $array ?
960 * @todo Finish documenting this function
962 function draw_rand_array($array, $draws) {
963 srand ((double) microtime() * 10000000);
967 $last = count($array);
969 if ($draws > $last) {
976 $keys = array_keys($array);
977 $rand = rand(0, $last);
979 $return[$keys[$rand]] = $array[$keys[$rand]];
980 unset($array[$keys[$rand]]);
990 * Function to check the passed address is within the passed subnet
992 * The parameter is a comma separated string of subnet definitions.
993 * Subnet strings can be in one of two formats:
994 * 1: xxx.xxx.xxx.xxx/xx
996 * Code for type 1 modified from user posted comments by mediator at
997 * {@link http://au.php.net/manual/en/function.ip2long.php}
999 * @param string $addr The address you are checking
1000 * @param string $subnetstr The string of subnet addresses
1003 function address_in_subnet($addr, $subnetstr) {
1005 $subnets = explode(',', $subnetstr);
1007 $addr = trim($addr);
1009 foreach ($subnets as $subnet) {
1010 $subnet = trim($subnet);
1011 if (strpos($subnet, '/') !== false) { /// type 1
1013 list($ip, $mask) = explode('/', $subnet);
1014 $mask = 0xffffffff << (32 - $mask);
1015 $found = ((ip2long($addr) & $mask) == (ip2long($ip) & $mask));
1018 $found = (strpos($addr, $subnet) === 0);
1030 * For outputting debugging info
1033 * @param string $string ?
1034 * @param string $eol ?
1035 * @todo Finish documenting this function
1037 function mtrace($string, $eol="\n", $sleep=0) {
1039 if (defined('STDOUT')) {
1040 fwrite(STDOUT
, $string.$eol);
1042 echo $string . $eol;
1047 //delay to keep message on user's screen in case of subsequent redirect
1053 //Replace 1 or more slashes or backslashes to 1 slash
1054 function cleardoubleslashes ($path) {
1055 return preg_replace('/(\/|\\\){1,}/','/',$path);
1061 * Returns most reliable client address
1063 * @return string The remote IP address
1065 function getremoteaddr() {
1066 if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
1067 return cleanremoteaddr($_SERVER['HTTP_CLIENT_IP']);
1069 if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
1070 return cleanremoteaddr($_SERVER['HTTP_X_FORWARDED_FOR']);
1072 if (!empty($_SERVER['REMOTE_ADDR'])) {
1073 return cleanremoteaddr($_SERVER['REMOTE_ADDR']);
1079 * Cleans a remote address ready to put into the log table
1081 function cleanremoteaddr($addr) {
1082 $originaladdr = $addr;
1084 // first get all things that look like IP addresses.
1085 if (!preg_match_all('/(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/',$addr,$matches,PREG_SET_ORDER
)) {
1088 $goodmatches = array();
1089 $lanmatches = array();
1090 foreach ($matches as $match) {
1092 // check to make sure it's not an internal address.
1093 // the following are reserved for private lans...
1094 // 10.0.0.0 - 10.255.255.255
1095 // 172.16.0.0 - 172.31.255.255
1096 // 192.168.0.0 - 192.168.255.255
1097 // 169.254.0.0 -169.254.255.255
1098 $bits = explode('.',$match[0]);
1099 if (count($bits) != 4) {
1100 // weird, preg match shouldn't give us it.
1103 if (($bits[0] == 10)
1104 ||
($bits[0] == 172 && $bits[1] >= 16 && $bits[1] <= 31)
1105 ||
($bits[0] == 192 && $bits[1] == 168)
1106 ||
($bits[0] == 169 && $bits[1] == 254)) {
1107 $lanmatches[] = $match[0];
1111 $goodmatches[] = $match[0];
1113 if (!count($goodmatches)) {
1114 // perhaps we have a lan match, it's probably better to return that.
1115 if (!count($lanmatches)) {
1118 return array_pop($lanmatches);
1121 if (count($goodmatches) == 1) {
1122 return $goodmatches[0];
1124 error_log("NOTICE: cleanremoteaddr gives us something funny: $originaladdr had ".count($goodmatches)." matches");
1125 // we need to return something, so
1126 return array_pop($goodmatches);
1130 * html_entity_decode is only supported by php 4.3.0 and higher
1131 * so if it is not predefined, define it here
1133 * @param string $string ?
1135 * @todo Finish documenting this function
1137 if(!function_exists('html_entity_decode')) {
1138 function html_entity_decode($string, $quote_style = ENT_COMPAT
, $charset = 'ISO-8859-1') {
1139 $trans_tbl = get_html_translation_table(HTML_ENTITIES
, $quote_style);
1140 $trans_tbl = array_flip($trans_tbl);
1141 return strtr($string, $trans_tbl);
1146 * The clone keyword is only supported from PHP 5 onwards.
1147 * The behaviour of $obj2 = $obj1 differs fundamentally
1148 * between PHP 4 and PHP 5. In PHP 4 a copy of $obj1 was
1149 * created, in PHP 5 $obj1 is referenced. To create a copy
1150 * in PHP 5 the clone keyword was introduced. This function
1151 * simulates this behaviour for PHP < 5.0.0.
1152 * See also: http://mjtsai.com/blog/2004/07/15/php-5-object-references/
1154 * Modified 2005-09-29 by Eloy (from Julian Sedding proposal)
1155 * Found a better implementation (more checks and possibilities) from PEAR:
1156 * http://cvs.php.net/co.php/pear/PHP_Compat/Compat/Function/clone.php
1158 * @param object $obj
1161 if(!check_php_version('5.0.0')) {
1162 // the eval is needed to prevent PHP 5 from getting a parse error!
1164 function clone($obj) {
1166 if (!is_object($obj)) {
1167 user_error(\'clone() __clone method called on non-object\', E_USER_WARNING);
1171 /// Use serialize/unserialize trick to deep copy the object
1172 $obj = unserialize(serialize($obj));
1174 /// If there is a __clone method call it on the "new" class
1175 if (method_exists($obj, \'__clone\')) {
1188 * @param string $a ?
1189 * @param string $b ?
1191 * @todo Finish documenting this function
1193 function microtime_diff($a, $b) {
1194 list($a_dec, $a_sec) = explode(' ', $a);
1195 list($b_dec, $b_sec) = explode(' ', $b);
1196 return $b_sec - $a_sec +
$b_dec - $a_dec;
1201 *** get_performance_info() pairs up with init_performance_info()
1202 *** loaded in setup.php. Returns an array with 'html' and 'txt'
1203 *** values ready for use, and each of the individual stats provided
1204 *** separately as well.
1207 function get_performance_info() {
1211 $info['html'] = ''; // holds userfriendly HTML representation
1212 $info['txt'] = me() . ' '; // holds log-friendly representation
1214 $info['realtime'] = microtime_diff($PERF->starttime
, microtime());
1216 $info['html'] .= '<span class="timeused">'.$info['realtime'].' secs</span> ';
1217 $info['txt'] .= 'time: '.$info['realtime'].'s ';
1219 if (function_exists('memory_get_usage')) {
1220 $info['memory_total'] = memory_get_usage();
1221 $info['memory_growth'] = memory_get_usage() - $PERF->startmemory
;
1222 $info['html'] .= '<span class="memoryused">RAM: '.display_size($info['memory_total']).'</span> ';
1223 $info['txt'] .= 'memory_total: '.$info['memory_total'].'B (' . display_size($info['memory_total']).') memory_growth: '.$info['memory_growth'].'B ('.display_size($info['memory_growth']).') ';
1226 $inc = get_included_files();
1227 //error_log(print_r($inc,1));
1228 $info['includecount'] = count($inc);
1229 $info['html'] .= '<span class="included">Included '.$info['includecount'].' files</span> ';
1230 $info['txt'] .= 'includecount: '.$info['includecount'].' ';
1232 if (!empty($PERF->dbqueries
)) {
1233 $info['dbqueries'] = $PERF->dbqueries
;
1234 $info['html'] .= '<span class="dbqueries">DB queries '.$info['dbqueries'].'</span> ';
1235 $info['txt'] .= 'dbqueries: '.$info['dbqueries'].' ';
1238 if (!empty($PERF->logwrites
)) {
1239 $info['logwrites'] = $PERF->logwrites
;
1240 $info['html'] .= '<span class="logwrites">Log writes '.$info['logwrites'].'</span> ';
1241 $info['txt'] .= 'logwrites: '.$info['logwrites'].' ';
1244 if (function_exists('posix_times')) {
1245 $ptimes = posix_times();
1247 foreach ($ptimes as $key => $val) {
1248 $info[$key] = $ptimes[$key] - $PERF->startposixtimes
[$key];
1250 $info['html'] .= "<span class=\"posixtimes\">ticks: $info[ticks] user: $info[utime] sys: $info[stime] cuser: $info[cutime] csys: $info[cstime]</span> ";
1251 $info['txt'] .= "ticks: $info[ticks] user: $info[utime] sys: $info[stime] cuser: $info[cutime] csys: $info[cstime] ";
1255 // Grab the load average for the last minute
1256 // /proc will only work under some linux configurations
1257 // while uptime is there under MacOSX/Darwin and other unices
1258 if (is_readable('/proc/loadavg') && $loadavg = @file
('/proc/loadavg')) {
1259 list($server_load) = explode(' ', $loadavg[0]);
1261 } else if ( function_exists('is_executable') && is_executable('/usr/bin/uptime') && $loadavg = `
/usr
/bin
/uptime`
) {
1262 if (preg_match('/load averages?: (\d+[\.:]\d+)/', $loadavg, $matches)) {
1263 $server_load = $matches[1];
1265 trigger_error('Could not parse uptime output!');
1268 if (!empty($server_load)) {
1269 $info['serverload'] = $server_load;
1270 $info['html'] .= '<span class="serverload">Load average: '.$info['serverload'].'</span> ';
1271 $info['txt'] .= 'serverload: '.$info['serverload'];
1275 $info['html'] = '<div class="performanceinfo">'.$info['html'].'</div>';
1279 if (!function_exists('file_get_contents')) {
1280 function file_get_contents($file) {
1281 $file = file($file);
1282 return $file ?
implode('', $file) : false;
1290 * Detect if an object or a class contains a given property
1291 * will take an actual object or the name of a class
1292 * @param mix $obj Name of class or real object to test
1293 * @param string $property name of property to find
1294 * @return bool true if property exists
1296 function object_property_exists( $obj, $property ) {
1297 if (is_string( $obj )) {
1298 $properties = get_class_vars( $obj );
1301 $properties = get_object_vars( $obj );
1303 return array_key_exists( $property, $properties );
1308 * Add quotes to HTML characters
1310 * Returns $var with HTML characters (like "<", ">", etc.) properly quoted.
1311 * This function is very similar to {@link p()}
1313 * @param string $var the string potentially containing HTML characters
1317 if ($var == '0') { // for integer 0, boolean false, string '0'
1320 return preg_replace("/&(#\d+);/iu", '&$1;', htmlspecialchars(stripslashes_safe($var), ENT_COMPAT
, 'utf-8'));
1324 * Add quotes to HTML characters
1326 * Prints $var with HTML characters (like "<", ">", etc.) properly quoted.
1327 * This function is very similar to {@link s()}
1329 * @param string $var the string potentially containing HTML characters
1338 * Ensure that a variable is set
1340 * Return $var if it is defined, otherwise return $default,
1341 * This function is very similar to {@link optional_variable()}
1343 * @param mixed $var the variable which may be unset
1344 * @param mixed $default the value to return if $var is unset
1347 function nvl(&$var, $default='') {
1349 return isset($var) ?
$var : $default;
1353 * Remove query string from url
1355 * Takes in a URL and returns it without the querystring portion
1357 * @param string $url the url which may have a query string attached
1360 function strip_querystring($url) {
1361 $textlib = textlib_get_instance();
1363 if ($commapos = $textlib->strpos($url, '?')) {
1364 return $textlib->substr($url, 0, $commapos);
1371 * Returns the URL of the HTTP_REFERER, less the querystring portion
1374 function get_referer() {
1376 return strip_querystring(nvl($_SERVER['HTTP_REFERER']));
1381 * Returns the name of the current script, WITH the querystring portion.
1382 * this function is necessary because PHP_SELF and REQUEST_URI and SCRIPT_NAME
1383 * return different things depending on a lot of things like your OS, Web
1384 * server, and the way PHP is compiled (ie. as a CGI, module, ISAPI, etc.)
1385 * <b>NOTE:</b> This function returns false if the global variables needed are not set.
1391 if (!empty($_SERVER['REQUEST_URI'])) {
1392 return $_SERVER['REQUEST_URI'];
1394 } else if (!empty($_SERVER['PHP_SELF'])) {
1395 if (!empty($_SERVER['QUERY_STRING'])) {
1396 return $_SERVER['PHP_SELF'] .'?'. $_SERVER['QUERY_STRING'];
1398 return $_SERVER['PHP_SELF'];
1400 } else if (!empty($_SERVER['SCRIPT_NAME'])) {
1401 if (!empty($_SERVER['QUERY_STRING'])) {
1402 return $_SERVER['SCRIPT_NAME'] .'?'. $_SERVER['QUERY_STRING'];
1404 return $_SERVER['SCRIPT_NAME'];
1406 } else if (!empty($_SERVER['URL'])) { // May help IIS (not well tested)
1407 if (!empty($_SERVER['QUERY_STRING'])) {
1408 return $_SERVER['URL'] .'?'. $_SERVER['QUERY_STRING'];
1410 return $_SERVER['URL'];
1413 notify('Warning: Could not find any of these web server variables: $REQUEST_URI, $PHP_SELF, $SCRIPT_NAME or $URL');
1419 * Like {@link me()} but returns a full URL
1423 function qualified_me() {
1427 if (!empty($CFG->wwwroot
)) {
1428 $url = parse_url($CFG->wwwroot
);
1431 if (!empty($url['host'])) {
1432 $hostname = $url['host'];
1433 } else if (!empty($_SERVER['SERVER_NAME'])) {
1434 $hostname = $_SERVER['SERVER_NAME'];
1435 } else if (!empty($_ENV['SERVER_NAME'])) {
1436 $hostname = $_ENV['SERVER_NAME'];
1437 } else if (!empty($_SERVER['HTTP_HOST'])) {
1438 $hostname = $_SERVER['HTTP_HOST'];
1439 } else if (!empty($_ENV['HTTP_HOST'])) {
1440 $hostname = $_ENV['HTTP_HOST'];
1442 notify('Warning: could not find the name of this server!');
1446 if (!empty($url['port'])) {
1447 $hostname .= ':'.$url['port'];
1448 } else if (!empty($_SERVER['SERVER_PORT'])) {
1449 if ($_SERVER['SERVER_PORT'] != 80 && $_SERVER['SERVER_PORT'] != 443) {
1450 $hostname .= ':'.$_SERVER['SERVER_PORT'];
1454 if (isset($_SERVER['HTTPS'])) {
1455 $protocol = ($_SERVER['HTTPS'] == 'on') ?
'https://' : 'http://';
1456 } else if (isset($_SERVER['SERVER_PORT'])) { # Apache2 does not export $_SERVER['HTTPS']
1457 $protocol = ($_SERVER['SERVER_PORT'] == '443') ?
'https://' : 'http://';
1459 $protocol = 'http://';
1462 $url_prefix = $protocol.$hostname;
1463 return $url_prefix . me();
1467 * Determine if a web referer is valid
1469 * Returns true if the referer is the same as the goodreferer. If
1470 * the referer to test is not specified, use {@link qualified_me()}.
1471 * If the admin has not set secure forms ($CFG->secureforms) then
1472 * this function returns true regardless of a match.
1475 * @param string $goodreferer the url to compare to referer
1478 function match_referer($goodreferer = '') {
1481 if (empty($CFG->secureforms
)) { // Don't bother checking referer
1485 if ($goodreferer == 'nomatch') { // Don't bother checking referer
1489 if (empty($goodreferer)) {
1490 $goodreferer = qualified_me();
1493 $referer = get_referer();
1495 return (($referer == $goodreferer) or ($referer == $CFG->wwwroot
) or ($referer == $CFG->wwwroot
.'index.php'));
1499 * Determine if there is data waiting to be processed from a form
1501 * Used on most forms in Moodle to check for data
1502 * Returns the data as an object, if it's found.
1503 * This object can be used in foreach loops without
1504 * casting because it's cast to (array) automatically
1506 * Checks that submitted POST data exists, and also
1507 * checks the referer against the given url (it uses
1508 * the current page if none was specified.
1511 * @param string $url the url to compare to referer for secure forms
1514 function data_submitted($url='') {
1519 if (empty($_POST)) {
1523 if (match_referer($url)) {
1524 return (object)$_POST;
1526 if ($CFG->debug
> 10) {
1527 notice('The form did not come from this page! (referer = '. get_referer() .')');
1535 * Moodle replacement for php stripslashes() function
1537 * The standard php stripslashes() removes ALL backslashes
1538 * even from strings - so C:\temp becomes C:temp - this isn't good.
1539 * This function should work as a fairly safe replacement
1540 * to be called on quoted AND unquoted strings (to be sure)
1542 * @param string the string to remove unsafe slashes from
1545 function stripslashes_safe($string) {
1547 $string = str_replace("\\'", "'", $string);
1548 $string = str_replace('\\"', '"', $string);
1549 $string = str_replace('\\\\', '\\', $string);
1554 * Recursive implementation of stripslashes()
1556 * This function will allow you to strip the slashes from a variable.
1557 * If the variable is an array or object, slashes will be stripped
1558 * from the items (or properties) it contains, even if they are arrays
1559 * or objects themselves.
1561 * @param mixed the variable to remove slashes from
1564 function stripslashes_recursive($var) {
1565 if(is_object($var)) {
1566 $properties = get_object_vars($var);
1567 foreach($properties as $property => $value) {
1568 $var->$property = stripslashes_recursive($value);
1571 else if(is_array($var)) {
1572 foreach($var as $property => $value) {
1573 $var[$property] = stripslashes_recursive($value);
1576 else if(is_string($var)) {
1577 $var = stripslashes($var);
1583 * This does a search and replace, ignoring case
1584 * This function is only used for versions of PHP older than version 5
1585 * which do not have a native version of this function.
1586 * Taken from the PHP manual, by bradhuizenga @ softhome.net
1588 * @param string $find the string to search for
1589 * @param string $replace the string to replace $find with
1590 * @param string $string the string to search through
1593 if (!function_exists('str_ireplace')) { /// Only exists in PHP 5
1594 function str_ireplace($find, $replace, $string) {
1595 $textlib = textlib_get_instance();
1597 if (!is_array($find)) {
1598 $find = array($find);
1601 if(!is_array($replace)) {
1602 if (!is_array($find)) {
1603 $replace = array($replace);
1605 // this will duplicate the string into an array the size of $find
1607 $rString = $replace;
1609 for ($i = 0; $i < $c; $i++
) {
1610 $replace[$i] = $rString;
1615 foreach ($find as $fKey => $fItem) {
1616 $between = explode($textlib->strtolower($fItem),$textlib->strtolower($string));
1618 foreach($between as $bKey => $bItem) {
1619 $between[$bKey] = $textlib->substr($string,$pos,$textlib->strlen($bItem));
1620 $pos +
= $textlib->strlen($bItem) +
$textlib->strlen($fItem);
1622 $string = implode($replace[$fKey],$between);
1629 * Locate the position of a string in another string
1631 * This function is only used for versions of PHP older than version 5
1632 * which do not have a native version of this function.
1633 * Taken from the PHP manual, by dmarsh @ spscc.ctc.edu
1635 * @param string $haystack The string to be searched
1636 * @param string $needle The string to search for
1637 * @param int $offset The position in $haystack where the search should begin.
1639 if (!function_exists('stripos')) { /// Only exists in PHP 5
1640 function stripos($haystack, $needle, $offset=0) {
1641 $textlib = textlib_get_instance();
1643 return $textlib->strpos($textlib->strtoupper($haystack), $textlib->strtoupper($needle), $offset);
1649 * Returns true if the current version of PHP is greater that the specified one.
1651 * @param string $version The version of php being tested.
1653 * @todo Finish documenting this function
1655 function check_php_version($version='4.1.0') {
1656 return (version_compare(phpversion(), $version) >= 0);
1661 * Checks to see if is a browser matches the specified
1662 * brand and is equal or better version.
1665 * @param string $brand The browser identifier being tested
1666 * @param int $version The version of the browser
1668 * @todo Finish documenting this function
1670 function check_browser_version($brand='MSIE', $version=5.5) {
1671 $agent = $_SERVER['HTTP_USER_AGENT'];
1673 if (empty($agent)) {
1679 case 'Gecko': /// Gecko based browsers
1681 if (substr_count($agent, 'Camino')) {
1682 // MacOS X Camino support
1683 $version = 20041110;
1686 // the proper string - Gecko/CCYYMMDD Vendor/Version
1687 // Faster version and work-a-round No IDN problem.
1688 if (preg_match("/Gecko\/([0-9]+)/i", $agent, $match)) {
1689 if ($match[1] > $version) {
1696 case 'MSIE': /// Internet Explorer
1698 if (strpos($agent, 'Opera')) { // Reject Opera
1701 $string = explode(';', $agent);
1702 if (!isset($string[1])) {
1705 $string = explode(' ', trim($string[1]));
1706 if (!isset($string[0]) and !isset($string[1])) {
1709 if ($string[0] == $brand and (float)$string[1] >= $version ) {
1721 * Set a variable's value depending on whether or not it already has a value.
1723 * If variable is set, set it to the set_value otherwise set it to the
1724 * unset_value. used to handle checkboxes when you are expecting them from
1727 * @param mixed $var Passed in by reference. The variable to check.
1728 * @param mixed $set_value The value to set $var to if $var already has a value.
1729 * @param mixed $unset_value The value to set $var to if $var does not already have a value.
1731 function checked(&$var, $set_value = 1, $unset_value = 0) {
1734 $var = $unset_value;
1741 * Prints the word "checked" if a variable is true, otherwise prints nothing,
1742 * used for printing the word "checked" in a checkbox form element.
1744 * @param boolean $var Variable to be checked for true value
1745 * @param string $true_value Value to be printed if $var is true
1746 * @param string $false_value Value to be printed if $var is false
1748 function frmchecked(&$var, $true_value = 'checked', $false_value = '') {
1758 * Prints a simple button to close a window
1760 function close_window_button($name='closewindow') {
1762 echo '<div style="text-align: center;">' . "\n";
1763 echo '<script type="text/javascript">' . "\n";
1765 echo "document.write('<form>');\n";
1766 echo "document.write('<input type=\"button\" onclick=\"self.close();\" value=\"".__gettext("Close this window")."\" />');\n";
1767 echo "document.write('<\/form>');\n";
1769 echo '</script>' . "\n";
1770 echo '<noscript>' . "\n";
1771 print_string($name);
1772 echo '</noscript>' . "\n";
1773 echo '</div>' . "\n";
1777 * Try and close the current window immediately using Javascript
1779 function close_window($delay=0) {
1780 echo '<script language="JavaScript" type="text/javascript">'."\n";
1785 echo 'self.close();'."\n";
1787 echo '</script>'."\n";
1793 * Given an array of value, creates a popup menu to be part of a form
1794 * $options["value"]["label"]
1796 * @param type description
1797 * @todo Finish documenting this function
1799 function choose_from_menu ($options, $name, $selected='', $nothing='choose', $script='',
1800 $nothingvalue='0', $return=false, $disabled=false, $tabindex=0) {
1802 if ($nothing == 'choose') {
1803 $nothing = __gettext('Choose') .'...';
1806 $attributes = ($script) ?
'onchange="'. $script .'"' : '';
1808 $attributes .= ' disabled="disabled"';
1812 $attributes .= ' tabindex="'.$tabindex.'"';
1815 $output = '<select id="menu'.$name.'" name="'. $name .'" '. $attributes .'>' . "\n";
1817 $output .= ' <option value="'. $nothingvalue .'"'. "\n";
1818 if ($nothingvalue === $selected) {
1819 $output .= ' selected="selected"';
1821 $output .= '>'. $nothing .'</option>' . "\n";
1823 if (!empty($options)) {
1824 foreach ($options as $value => $label) {
1825 $output .= ' <option value="'. $value .'"';
1826 if ($value === $selected) {
1827 $output .= ' selected="selected"';
1829 if ($label === '') {
1830 $output .= '>'. $value .'</option>' . "\n";
1832 $output .= '>'. $label .'</option>' . "\n";
1836 $output .= '</select>' . "\n";
1846 * Just like choose_from_menu, but takes a nested array (2 levels) and makes a dropdown menu
1847 * including option headings with the first level.
1849 function choose_from_menu_nested($options,$name,$selected='',$nothing='choose',$script = '',
1850 $nothingvalue=0,$return=false,$disabled=false,$tabindex=0) {
1852 if ($nothing == 'choose') {
1853 $nothing = __gettext('Choose') .'...';
1856 $attributes = ($script) ?
'onchange="'. $script .'"' : '';
1858 $attributes .= ' disabled="disabled"';
1862 $attributes .= ' tabindex="'.$tabindex.'"';
1865 $output = '<select id="menu'.$name.'" name="'. $name .'" '. $attributes .'>' . "\n";
1867 $output .= ' <option value="'. $nothingvalue .'"'. "\n";
1868 if ($nothingvalue === $selected) {
1869 $output .= ' selected="selected"';
1871 $output .= '>'. $nothing .'</option>' . "\n";
1873 if (!empty($options)) {
1874 foreach ($options as $section => $values) {
1875 $output .= ' <optgroup label="'.$section.'">'."\n";
1876 foreach ($values as $value => $label) {
1877 $output .= ' <option value="'. $value .'"';
1878 if ($value === $selected) {
1879 $output .= ' selected="selected"';
1881 if ($label === '') {
1882 $output .= '>'. $value .'</option>' . "\n";
1884 $output .= '>'. $label .'</option>' . "\n";
1887 $output .= ' </optgroup>'."\n";
1890 $output .= '</select>' . "\n";
1901 * Given an array of values, creates a group of radio buttons to be part of a form
1903 * @param array $options An array of value-label pairs for the radio group (values as keys)
1904 * @param string $name Name of the radiogroup (unique in the form)
1905 * @param string $checked The value that is already checked
1907 function choose_from_radio ($options, $name, $checked='') {
1909 static $idcounter = 0;
1915 $output = '<span class="radiogroup '.$name."\">\n";
1917 if (!empty($options)) {
1919 foreach ($options as $value => $label) {
1920 $htmlid = 'auto-rb'.sprintf('%04d', ++
$idcounter);
1921 $output .= ' <span class="radioelement '.$name.' rb'.$currentradio."\">";
1922 $output .= '<input name="'.$name.'" id="'.$htmlid.'" type="radio" value="'.$value.'"';
1923 if ($value == $checked) {
1924 $output .= ' checked="checked"';
1926 if ($label === '') {
1927 $output .= ' /> <label for="'.$htmlid.'">'. $value .'</label></span>' . "\n";
1929 $output .= ' /> <label for="'.$htmlid.'">'. $label .'</label></span>' . "\n";
1931 $currentradio = ($currentradio +
1) %
2;
1935 $output .= '</span>' . "\n";
1940 /** Display an standard html checkbox with an optional label
1942 * @param string $name The name of the checkbox
1943 * @param string $value The valus that the checkbox will pass when checked
1944 * @param boolean $checked The flag to tell the checkbox initial state
1945 * @param string $label The label to be showed near the checkbox
1946 * @param string $alt The info to be inserted in the alt tag
1948 function print_checkbox ($name, $value, $checked = true, $label = '', $alt = '', $script='',$return=false) {
1950 static $idcounter = 0;
1961 $strchecked = ' checked="checked"';
1964 $htmlid = 'auto-cb'.sprintf('%04d', ++
$idcounter);
1965 $output = '<span class="checkbox '.$name."\">";
1966 $output .= '<input name="'.$name.'" id="'.$htmlid.'" type="checkbox" value="'.$value.'" alt="'.$alt.'"'.$strchecked.' '.((!empty($script)) ?
' onclick="'.$script.'" ' : '').' />';
1967 if(!empty($label)) {
1968 $output .= ' <label for="'.$htmlid.'">'.$label.'</label>';
1970 $output .= '</span>'."\n";
1972 if (empty($return)) {
1980 /** Display an standard html text field with an optional label
1982 * @param string $name The name of the text field
1983 * @param string $value The value of the text field
1984 * @param string $label The label to be showed near the text field
1985 * @param string $alt The info to be inserted in the alt tag
1987 function print_textfield ($name, $value, $alt = '',$size=50,$maxlength= 0,$return=false) {
1989 static $idcounter = 0;
1999 if (!empty($maxlength)) {
2000 $maxlength = ' maxlength="'.$maxlength.'" ';
2003 $htmlid = 'auto-cb'.sprintf('%04d', ++
$idcounter);
2004 $output = '<span class="textfield '.$name."\">";
2005 $output .= '<input name="'.$name.'" id="'.$htmlid.'" type="text" value="'.$value.'" size="'.$size.'" '.$maxlength.' alt="'.$alt.'" />';
2007 $output .= '</span>'."\n";
2009 if (empty($return)) {
2019 * Validates an email to make sure it makes sense and adheres
2020 * to the email filter if it's set.
2022 * @param string $address The email address to validate.
2025 function validate_email($address) {
2029 if (ereg('^[-!#$%&\'*+\\./0-9=?A-Z^_`a-z{|}~]+'.
2031 '[-!#$%&\'*+\\/0-9=?A-Z^_`a-z{|}~]+\.'.
2032 '[-!#$%&\'*+\\./0-9=?A-Z^_`a-z{|}~]+$',
2035 if ($CFG->emailfilter
!= "") {
2036 $domain = substr($address,strpos($address,"@")+
1);
2037 if (substr_count($CFG->emailfilter
, $domain) == 0) {
2050 * Check for bad characters ?
2052 * @param string $string ?
2053 * @param int $allowdots ?
2054 * @todo Finish documenting this function - more detail needed in description as well as details on arguments
2056 function detect_munged_arguments($string, $allowdots=1) {
2057 if (substr_count($string, '..') > $allowdots) { // Sometimes we allow dots in references
2060 if (ereg('[\|\`]', $string)) { // check for other bad characters
2063 if (empty($string) or $string == '/') {
2073 * Just returns an array of text formats suitable for a popup menu
2075 * @uses FORMAT_MOODLE
2077 * @uses FORMAT_PLAIN
2078 * @uses FORMAT_MARKDOWN
2081 function format_text_menu() {
2083 return array (FORMAT_MOODLE
=> __gettext('Elgg auto-format'),
2084 FORMAT_HTML
=> __gettext('HTML format'),
2085 FORMAT_PLAIN
=> __gettext('Plain text format'),
2086 FORMAT_MARKDOWN
=> __gettext('Markdown format'));
2090 * Given text in a variety of format codings, this function returns
2091 * the text as safe HTML.
2094 * @uses FORMAT_MOODLE
2096 * @uses FORMAT_PLAIN
2098 * @uses FORMAT_MARKDOWN
2099 * @param string $text The text to be formatted. This is raw text originally from user input.
2100 * @param int $format Identifier of the text format to be used
2101 * (FORMAT_MOODLE, FORMAT_HTML, FORMAT_PLAIN, FORMAT_WIKI, FORMAT_MARKDOWN)
2102 * @param array $options ?
2103 * @param int $courseid ?
2105 * @todo Finish documenting this function
2107 function format_text($text, $format=FORMAT_MOODLE
, $options=NULL, $courseid=NULL ) {
2109 global $CFG, $course;
2111 if (!isset($options->noclean
)) {
2112 $options->noclean
=false;
2114 if (!isset($options->smiley
)) {
2115 $options->smiley
=true;
2117 if (!isset($options->filter
)) {
2118 $options->filter
=true;
2120 if (!isset($options->para
)) {
2121 $options->para
=true;
2123 if (!isset($options->newlines
)) {
2124 $options->newlines
=true;
2127 if (empty($courseid)) {
2128 if (!empty($course->id
)) { // An ugly hack for better compatibility
2129 $courseid = $course->id
;
2134 if (!empty($CFG->cachetext)) {
2135 $time = time() - $CFG->cachetext;
2136 $md5key = md5($text.'-'.$courseid.$options->noclean.$options->smiley.$options->filter.$options->para.$options->newlines);
2137 if ($cacheitem = get_record_select('cache_text', "md5key = '$md5key' AND timemodified > '$time'")) {
2138 return $cacheitem->formattedtext;
2141 */ // DISABLED - there is no cache_text - Penny
2143 $CFG->currenttextiscacheable
= true; // Default status - can be changed by any filter
2148 if (!empty($options->smiley
)) {
2149 replace_smilies($text);
2152 if (!isset($options->noclean
)) {
2153 $text = clean_text($text, $format, !empty($options->cleanuserfile
));
2156 if (!empty($options->filter
)) {
2157 $text = filter_text($text, $courseid);
2163 $text = rebuildnolinktag($text);
2164 $text = str_replace(' ', ' ', $text);
2165 $text = nl2br($text);
2169 // this format is deprecated
2170 $text = '<p>NOTICE: Wiki-like formatting has been removed from Moodle. You should not be seeing
2171 this message as all texts should have been converted to Markdown format instead.
2172 Please post a bug report to http://moodle.org/bugs with information about where you
2173 saw this message.</p>'.s($text);
2176 case FORMAT_MARKDOWN
:
2177 $text = markdown_to_html($text);
2178 if (!empty($options->smiley
)) {
2179 replace_smilies($text);
2181 if (empty($options->noclean
)) {
2182 $text = clean_text($text, $format);
2184 if (!empty($options->filter
)) {
2185 $text = filter_text($text, $courseid);
2189 default: // FORMAT_MOODLE or anything else
2190 $text = text_to_html($text, $options->smiley
, $options->para
, $options->newlines
);
2191 if (empty($options->noclean
)) {
2192 $text = clean_text($text, $format);
2194 if (!empty($options->filter
)) {
2195 $text = filter_text($text, $courseid);
2200 if (!empty($CFG->cachetext
) and $CFG->currenttextiscacheable
) {
2201 $newrecord->md5key
= $md5key;
2202 $newrecord->formattedtext
= $text;
2203 $newrecord->timemodified
= time();
2204 @insert_record
('cache_text', $newrecord);
2210 /** Converts the text format from the value to the 'internal'
2211 * name or vice versa. $key can either be the value or the name
2212 * and you get the other back.
2214 * @param mixed int 0-4 or string one of 'moodle','html','plain','markdown'
2215 * @return mixed as above but the other way around!
2217 function text_format_name( $key ) {
2219 $lookup[FORMAT_MOODLE
] = 'moodle';
2220 $lookup[FORMAT_HTML
] = 'html';
2221 $lookup[FORMAT_PLAIN
] = 'plain';
2222 $lookup[FORMAT_MARKDOWN
] = 'markdown';
2224 if (!is_numeric($key)) {
2225 $key = strtolower( $key );
2226 $value = array_search( $key, $lookup );
2229 if (isset( $lookup[$key] )) {
2230 $value = $lookup[ $key ];
2236 /** Given a simple string, this function returns the string
2237 * processed by enabled filters if $CFG->filterall is enabled
2239 * @param string $string The string to be filtered.
2240 * @param boolean $striplinks To strip any link in the result text.
2241 * @param int $courseid Current course as filters can, potentially, use it
2244 function format_string ($string, $striplinks = false, $courseid=NULL ) {
2246 global $CFG, $course;
2248 //We'll use a in-memory cache here to speed up repeated strings
2252 $md5 = md5($string.'<+>'.$striplinks);
2254 //Fetch from cache if possible
2255 if(isset($strcache[$md5])) {
2256 return $strcache[$md5];
2259 if (empty($courseid)) {
2260 if (!empty($course->id
)) { // An ugly hack for better compatibility
2261 $courseid = $course->id
; // (copied from format_text)
2265 if (!empty($CFG->filterall
)) {
2266 $string = filter_text($string, $courseid);
2269 if ($striplinks) { //strip links in string
2270 $string = preg_replace('/(<a[^>]+?>)(.+?)(<\/a>)/is','$2',$string);
2274 $strcache[$md5] = $string;
2280 * Given text in a variety of format codings, this function returns
2281 * the text as plain text suitable for plain email.
2283 * @uses FORMAT_MOODLE
2285 * @uses FORMAT_PLAIN
2287 * @uses FORMAT_MARKDOWN
2288 * @param string $text The text to be formatted. This is raw text originally from user input.
2289 * @param int $format Identifier of the text format to be used
2290 * (FORMAT_MOODLE, FORMAT_HTML, FORMAT_PLAIN, FORMAT_WIKI, FORMAT_MARKDOWN)
2293 function format_text_email($text, $format) {
2302 $text = wiki_to_html($text);
2303 /// This expression turns links into something nice in a text format. (Russell Jungwirth)
2304 /// From: http://php.net/manual/en/function.eregi-replace.php and simplified
2305 $text = eregi_replace('(<a [^<]*href=["|\']?([^ "\']*)["|\']?[^>]*>([^<]*)</a>)','\\3 [ \\2 ]', $text);
2306 return strtr(strip_tags($text), array_flip(get_html_translation_table(HTML_ENTITIES
)));
2310 return html_to_text($text);
2314 case FORMAT_MARKDOWN
:
2316 $text = eregi_replace('(<a [^<]*href=["|\']?([^ "\']*)["|\']?[^>]*>([^<]*)</a>)','\\3 [ \\2 ]', $text);
2317 return strtr(strip_tags($text), array_flip(get_html_translation_table(HTML_ENTITIES
)));
2323 * This function takes a string and examines it for HTML tags.
2324 * If tags are detected it passes the string to a helper function {@link cleanAttributes2()}
2325 * which checks for attributes and filters them for malicious content
2326 * 17/08/2004 :: Eamon DOT Costello AT dcu DOT ie
2328 * @param string $str The string to be examined for html tags
2331 function cleanAttributes($str){
2332 $result = preg_replace_callback(
2333 '%(<[^>]*(>|$)|>)%m', #search for html tags
2341 * This function takes a string with an html tag and strips out any unallowed
2342 * protocols e.g. javascript:
2343 * It calls ancillary functions in kses which are prefixed by kses
2344 * 17/08/2004 :: Eamon DOT Costello AT dcu DOT ie
2346 * @param array $htmlArray An array from {@link cleanAttributes()}, containing in its 1st
2347 * element the html to be cleared
2350 function cleanAttributes2($htmlArray){
2352 global $CFG, $ALLOWED_PROTOCOLS;
2353 require_once($CFG->libdir
.'/kses.php');
2355 $htmlTag = $htmlArray[1];
2356 if (substr($htmlTag, 0, 1) != '<') {
2357 return '>'; //a single character ">" detected
2359 if (!preg_match('%^<\s*(/\s*)?([a-zA-Z0-9]+)([^>]*)>?$%', $htmlTag, $matches)) {
2360 return ''; // It's seriously malformed
2362 $slash = trim($matches[1]); //trailing xhtml slash
2363 $elem = $matches[2]; //the element name
2364 $attrlist = $matches[3]; // the list of attributes as a string
2366 $attrArray = kses_hair($attrlist, $ALLOWED_PROTOCOLS);
2369 foreach ($attrArray as $arreach) {
2370 $attStr .= ' '.strtolower($arreach['name']).'="'.$arreach['value'].'" ';
2373 // Remove last space from attribute list
2374 $attStr = rtrim($attStr);
2377 if (preg_match('%/\s*$%', $attrlist)) {
2378 $xhtml_slash = ' /';
2380 return '<'. $slash . $elem . $attStr . $xhtml_slash .'>';
2384 * Replaces all known smileys in the text with image equivalents
2387 * @param string $text Passed by reference. The string to search for smily strings.
2390 function replace_smilies(&$text) {
2394 /// this builds the mapping array only once
2395 static $runonce = false;
2396 static $e = array();
2397 static $img = array();
2398 static $emoticons = array(
2404 'V-.' => 'thoughtful',
2405 ':-P' => 'tongueout',
2408 '8-)' => 'wideeyes',
2415 '8-o' => 'surprise',
2416 'P-|' => 'blackeye',
2423 if ($runonce == false) { /// After the first time this is not run again
2424 foreach ($emoticons as $emoticon => $image){
2425 $alttext = get_string($image, 'pix');
2428 $img[] = '<img alt="'. $alttext .'" width="15" height="15" src="'. $CFG->pixpath
.'/s/'. $image .'.gif" />';
2433 // Exclude from transformations all the code inside <script> tags
2434 // Needed to solve Bug 1185. Thanks to jouse 2001 detecting it. :-)
2435 // Based on code from glossary fiter by Williams Castillo.
2438 // Detect all the <script> zones to take out
2439 $excludes = array();
2440 preg_match_all('/<script language(.+?)<\/script>/is',$text,$list_of_excludes);
2442 // Take out all the <script> zones from text
2443 foreach (array_unique($list_of_excludes[0]) as $key=>$value) {
2444 $excludes['<+'.$key.'+>'] = $value;
2447 $text = str_replace($excludes,array_keys($excludes),$text);
2450 /// this is the meat of the code - this is run every time
2451 $text = str_replace($e, $img, $text);
2453 // Recover all the <script> zones to text
2455 $text = str_replace(array_keys($excludes),$excludes,$text);
2460 * Given plain text, makes it into HTML as nicely as possible.
2461 * May contain HTML tags already
2464 * @param string $text The string to convert.
2465 * @param boolean $smiley Convert any smiley characters to smiley images?
2466 * @param boolean $para If true then the returned string will be wrapped in paragraph tags
2467 * @param boolean $newlines If true then lines newline breaks will be converted to HTML newline breaks.
2471 function text_to_html($text, $smiley=true, $para=true, $newlines=true) {
2476 /// Remove any whitespace that may be between HTML tags
2477 $text = eregi_replace(">([[:space:]]+)<", "><", $text);
2479 /// Remove any returns that precede or follow HTML tags
2480 $text = eregi_replace("([\n\r])<", " <", $text);
2481 $text = eregi_replace(">([\n\r])", "> ", $text);
2483 convert_urls_into_links($text);
2485 /// Make returns into HTML newlines.
2487 $text = nl2br($text);
2490 /// Turn smileys into images.
2492 replace_smilies($text);
2495 /// Wrap the whole thing in a paragraph tag if required
2497 return '<p>'.$text.'</p>';
2504 * Given Markdown formatted text, make it into XHTML using external function
2507 * @param string $text The markdown formatted text to be converted.
2508 * @return string Converted text
2510 function markdown_to_html($text) {
2513 require_once($CFG->libdir
.'/markdown.php');
2515 return Markdown($text);
2519 * Given HTML text, make it into plain text using external function
2522 * @param string $html The text to be converted.
2525 function html_to_text($html) {
2529 require_once($CFG->libdir
.'/html2text.php');
2531 return html2text($html);
2535 * Given some text this function converts any URLs it finds into HTML links
2537 * @param string $text Passed in by reference. The string to be searched for urls.
2539 function convert_urls_into_links(&$text) {
2540 /// Make lone URLs into links. eg http://moodle.com/
2541 $text = eregi_replace("([[:space:]]|^|\(|\[)([[:alnum:]]+)://([^[:space:]]*)([[:alnum:]#?/&=])",
2542 "\\1<a href=\"\\2://\\3\\4\" target=\"_blank\">\\2://\\3\\4</a>", $text);
2544 /// eg www.moodle.com
2545 $text = eregi_replace("([[:space:]]|^|\(|\[)www\.([^[:space:]]*)([[:alnum:]#?/&=])",
2546 "\\1<a href=\"http://www.\\2\\3\" target=\"_blank\">www.\\2\\3</a>", $text);
2552 * This function will highlight search words in a given string
2553 * It cares about HTML and will not ruin links. It's best to use
2554 * this function after performing any conversions to HTML.
2555 * Function found here: http://forums.devshed.com/t67822/scdaa2d1c3d4bacb4671d075ad41f0854.html
2557 * @param string $needle The string to search for
2558 * @param string $haystack The string to search for $needle in
2559 * @param int $case ?
2561 * @todo Finish documenting this function
2563 function highlight($needle, $haystack, $case=0,
2564 $left_string='<span class="highlight">', $right_string='</span>') {
2565 if (empty($needle)) {
2569 //$list_of_words = eregi_replace("[^-a-zA-Z0-9&.']", " ", $needle); // bug 3101
2570 $list_of_words = $needle;
2571 $list_array = explode(' ', $list_of_words);
2572 for ($i=0; $i<sizeof($list_array); $i++
) {
2573 if (strlen($list_array[$i]) == 1) {
2574 $list_array[$i] = '';
2577 $list_of_words = implode(' ', $list_array);
2578 $list_of_words_cp = $list_of_words;
2580 preg_match_all('/<(.+?)>/is',$haystack,$list_of_words);
2582 foreach (array_unique($list_of_words[0]) as $key=>$value) {
2583 $final['<|'.$key.'|>'] = $value;
2586 $haystack = str_replace($final,array_keys($final),$haystack);
2587 $list_of_words_cp = eregi_replace(' +', '|', $list_of_words_cp);
2589 if ($list_of_words_cp{0}=='|') {
2590 $list_of_words_cp{0} = '';
2592 if ($list_of_words_cp{strlen($list_of_words_cp)-1}=='|') {
2593 $list_of_words_cp{strlen($list_of_words_cp)-1}='';
2596 $list_of_words_cp = trim($list_of_words_cp);
2598 if ($list_of_words_cp) {
2600 $list_of_words_cp = "(". $list_of_words_cp .")";
2603 $haystack = eregi_replace("$list_of_words_cp", "$left_string"."\\1"."$right_string", $haystack);
2605 $haystack = ereg_replace("$list_of_words_cp", "$left_string"."\\1"."$right_string", $haystack);
2608 $haystack = str_replace(array_keys($final),$final,$haystack);
2614 * This function will highlight instances of $needle in $haystack
2615 * It's faster that the above function and doesn't care about
2618 * @param string $needle The string to search for
2619 * @param string $haystack The string to search for $needle in
2622 function highlightfast($needle, $haystack) {
2623 $textlib = textlib_get_instance();
2625 $parts = explode($textlib->strtolower($needle), $textlib->strtolower($haystack));
2629 foreach ($parts as $key => $part) {
2630 $parts[$key] = $textlib->substr($haystack, $pos, $textlib->strlen($part));
2631 $pos +
= $textlib->strlen($part);
2633 $parts[$key] .= '<span class="highlight">'.$textlib->substr($haystack, $pos, $textlib->strlen($needle)).'</span>';
2634 $pos +
= $textlib->strlen($needle);
2637 return (join('', $parts));
2641 * Print a link to continue on to another page.
2644 * @param string $link The url to create a link to.
2646 function print_continue($link) {
2651 $link = $_SERVER['HTTP_REFERER'];
2654 echo '<div class="continuebutton">';
2655 print_single_button($link, NULL, __gettext('Continue'), 'post', $CFG->framename
);
2660 * Print a message in a standard themed box.
2662 * @param string $message ?
2663 * @param string $align ?
2664 * @param string $width ?
2665 * @param string $color ?
2666 * @param int $padding ?
2667 * @param string $class ?
2668 * @todo Finish documenting this function
2670 function print_simple_box($message, $align='', $width='', $color='', $padding=5, $class='generalbox', $id='') {
2671 print_simple_box_start($align, $width, $color, $padding, $class, $id);
2672 echo stripslashes_safe($message);
2673 print_simple_box_end();
2677 * Print the top portion of a standard themed box.
2679 * @param string $align ?
2680 * @param string $width ?
2681 * @param string $color ?
2682 * @param int $padding ?
2683 * @param string $class ?
2684 * @todo Finish documenting this function
2686 function print_simple_box_start($align='', $width='', $color='', $padding=5, $class='generalbox', $id='') {
2689 $color = 'bgcolor="'. $color .'"';
2692 $align = 'align="'. $align .'"';
2695 $width = 'width="'. $width .'"';
2698 $id = 'id="'. $id .'"';
2700 $class = trim($class);
2701 $classcontent = preg_replace('/(\s+|$)/','content ', $class);
2703 echo "<table $align $width $id class=\"$class\" border=\"0\" cellpadding=\"$padding\" cellspacing=\"0\">".
2704 "<tr><td $color class=\"$classcontent\">";
2708 * Print the end portion of a standard themed box.
2710 function print_simple_box_end() {
2711 echo '</td></tr></table>';
2715 * Print a self contained form with a single submit button.
2717 * @param string $link ?
2718 * @param array $options ?
2719 * @param string $label ?
2720 * @param string $method ?
2721 * @todo Finish documenting this function
2723 function print_single_button($link, $options, $label='OK', $method='get', $target='_self') {
2724 echo '<div class="singlebutton">';
2725 echo '<form action="'. $link .'" method="'. $method .'" target="'.$target.'">';
2727 foreach ($options as $name => $value) {
2728 echo '<input type="hidden" name="'. $name .'" value="'. $value .'" />';
2731 echo '<input type="submit" value="'. $label .'" /></form></div>';
2735 * Print a png image.
2737 * @param string $url ?
2738 * @param int $sizex ?
2739 * @param int $sizey ?
2740 * @param boolean $returnstring ?
2741 * @param string $parameters ?
2742 * @todo Finish documenting this function
2744 function print_png($url, $sizex, $sizey, $returnstring, $parameters='alt=""') {
2748 if (!isset($recentIE)) {
2749 $recentIE = check_browser_version('MSIE', '5.0');
2752 if ($recentIE) { // work around the HORRIBLE bug IE has with alpha transparencies
2753 $output .= '<img src="'. $CFG->pixpath
.'/spacer.gif" width="'. $sizex .'" height="'. $sizey .'"'.
2754 ' border="0" class="png" style="width: '. $sizex .'px; height: '. $sizey .'px; '.
2755 ' filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='.
2756 "'$url', sizingMethod='scale') ".
2757 ' '. $parameters .' />';
2759 $output .= '<img src="'. $url .'" border="0" width="'. $sizex .'" height="'. $sizey .'" '.
2760 ' '. $parameters .' />';
2763 if ($returnstring) {
2771 * Print a nicely formatted table.
2773 * @param array $table is an object with several properties.
2774 * <ul<li>$table->head - An array of heading names.
2775 * <li>$table->align - An array of column alignments
2776 * <li>$table->size - An array of column sizes
2777 * <li>$table->wrap - An array of "nowrap"s or nothing
2778 * <li>$table->data[] - An array of arrays containing the data.
2779 * <li>$table->width - A percentage of the page
2780 * <li>$table->cellpadding - Padding on each cell
2781 * <li>$table->cellspacing - Spacing between cells
2784 * @todo Finish documenting this function
2786 function print_table($table) {
2788 if (isset($table->align
)) {
2789 foreach ($table->align
as $key => $aa) {
2791 $align[$key] = ' align="'. $aa .'"';
2797 if (isset($table->size
)) {
2798 foreach ($table->size
as $key => $ss) {
2800 $size[$key] = ' width="'. $ss .'"';
2806 if (isset($table->wrap
)) {
2807 foreach ($table->wrap
as $key => $ww) {
2809 $wrap[$key] = ' nowrap="nowrap" ';
2816 if (empty($table->width
)) {
2817 $table->width
= '80%';
2820 if (empty($table->cellpadding
)) {
2821 $table->cellpadding
= '5';
2824 if (empty($table->cellspacing
)) {
2825 $table->cellspacing
= '1';
2828 if (empty($table->class)) {
2829 $table->class = 'generaltable';
2832 $tableid = empty($table->id
) ?
'' : 'id="'.$table->id
.'"';
2834 print_simple_box_start('center', $table->width
, '#ffffff', 0);
2835 echo '<table width="100%" border="0" align="center" ';
2836 echo " cellpadding=\"$table->cellpadding\" cellspacing=\"$table->cellspacing\" class=\"$table->class\" $tableid>\n";
2840 if (!empty($table->head
)) {
2841 $countcols = count($table->head
);
2843 foreach ($table->head
as $key => $heading) {
2845 if (!isset($size[$key])) {
2848 if (!isset($align[$key])) {
2851 echo '<th valign="top" '. $align[$key].$size[$key] .' nowrap="nowrap" class="header c'.$key.'">'. $heading .'</th>';
2856 if (!empty($table->data
)) {
2858 foreach ($table->data
as $key => $row) {
2859 $oddeven = $oddeven ?
0 : 1;
2860 echo '<tr class="r'.$oddeven.'">'."\n";
2861 if ($row == 'hr' and $countcols) {
2862 echo '<td colspan="'. $countcols .'"><div class="tabledivider"></div></td>';
2863 } else { /// it's a normal row of data
2864 foreach ($row as $key => $item) {
2865 if (!isset($size[$key])) {
2868 if (!isset($align[$key])) {
2871 if (!isset($wrap[$key])) {
2874 echo '<td '. $align[$key].$size[$key].$wrap[$key] .' class="cell c'.$key.'">'. $item .'</td>';
2880 echo '</table>'."\n";
2881 print_simple_box_end();
2887 * Prints form items with the names $day, $month and $year
2890 * @param int $month ?
2891 * @param int $year ?
2892 * @param int $currenttime A default timestamp in GMT
2893 * @todo Finish documenting this function
2895 function print_date_selector($day, $month, $year, $currenttime=0) {
2897 if (!$currenttime) {
2898 $currenttime = time();
2900 $currentdate = usergetdate($currenttime);
2902 for ($i=1; $i<=31; $i++
) {
2905 for ($i=1; $i<=12; $i++
) {
2906 $months[$i] = userdate(gmmktime(12,0,0,$i,1,2000), "%B");
2908 for ($i=2000; $i<=2010; $i++
) {
2911 choose_from_menu($days, $day, $currentdate['mday'], '');
2912 choose_from_menu($months, $month, $currentdate['mon'], '');
2913 choose_from_menu($years, $year, $currentdate['year'], '');
2917 *Prints form items with the names $hour and $minute
2920 * @param ? $minute ?
2921 * @param $currenttime A default timestamp in GMT
2922 * @param int $step ?
2923 * @todo Finish documenting this function
2925 function print_time_selector($hour, $minute, $currenttime=0, $step=5 ,$return=false) {
2927 if (!$currenttime) {
2928 $currenttime = time();
2930 $currentdate = usergetdate($currenttime);
2932 $currentdate['minutes'] = ceil($currentdate['minutes']/$step)*$step;
2934 for ($i=0; $i<=23; $i++
) {
2935 $hours[$i] = sprintf("%02d",$i);
2937 for ($i=0; $i<=59; $i+
=$step) {
2938 $minutes[$i] = sprintf("%02d",$i);
2941 return choose_from_menu($hours, $hour, $currentdate['hours'], '','','',$return)
2942 .choose_from_menu($minutes, $minute, $currentdate['minutes'], '','','',$return);
2946 *Returns an A link tag
2950 * @param $extrattr Extra attribs for the A tag
2953 function a_href($url, $str, $extrattr='') {
2954 $str = htmlspecialchars($str, ENT_COMPAT
, 'utf-8');
2955 return "<a href=\"$url\" $extrattr >$str</a>";
2959 *Returns an A link tag using __gettext()
2962 * @param $str for __gettext()
2963 * @param $extrattr Extra attribs for the A tag
2966 function a_hrefg($url, $str, $extrattr='') {
2967 $str = htmlspecialchars(__gettext($str), ENT_COMPAT
, 'utf-8');
2968 return "<a href=\"$url\" $extrattr >$str</a>";
2972 * Print an error page displaying an error message.
2973 * Old method, don't call directly in new code - use print_error instead.
2978 * @param string $message The message to display to the user about the error.
2979 * @param string $link The url where the user will be prompted to continue. If no url is provided the user will be directed to the site index page.
2981 function error ($message, $link='') {
2982 global $CFG, $SESSION;
2984 @header
('HTTP/1.0 404 Not Found');
2986 print_header(__gettext('Error'));
2989 $message = clean_text($message); // In case nasties are in here
2991 print_simple_box($message, 'center', '', '#FFBBBB', 5, 'errorbox');
2994 if ( !empty($SESSION->fromurl
) ) {
2995 $link = $SESSION->fromurl
;
2996 unset($SESSION->fromurl
);
2998 $link = $CFG->wwwroot
;
3001 print_continue($link);
3003 for ($i=0;$i<512;$i++
) { // Padding to help IE work with 404
3010 * Print an error page displaying an error message. New method - use this for new code.
3014 * @param string $string The name of the string from error.php to print
3015 * @param string $link The url where the user will be prompted to continue. If no url is provided the user will be directed to the site index page.
3017 function print_error ($string, $link='') {
3019 $string = get_string($string, 'error');
3020 error($string, $link);
3026 * Print a message and exit.
3029 * @param string $message ?
3030 * @param string $link ?
3031 * @todo Finish documenting this function
3033 function notice ($message, $link='') {
3036 $message = clean_text($message);
3037 $link = clean_text($link);
3040 if (!empty($_SERVER['HTTP_REFERER'])) {
3041 $link = $_SERVER['HTTP_REFERER'];
3043 $link = $CFG->wwwroot
;
3048 print_simple_box($message, 'center', '50%', '', '20', 'noticebox');
3049 print_continue($link);
3050 print_footer(get_site());
3055 * Print a message along with "Yes" and "No" links for the user to continue.
3057 * @param string $message The text to display
3058 * @param string $linkyes The link to take the user to if they choose "Yes"
3059 * @param string $linkno The link to take the user to if they choose "No"
3061 function notice_yesno ($message, $linkyes, $linkno) {
3065 $message = clean_text($message);
3066 $linkyes = clean_text($linkyes);
3067 $linkno = clean_text($linkno);
3069 print_simple_box_start('center', '60%', '', 5, 'noticebox', 'notice');
3070 echo '<p align="center">'. $message .'</p>';
3071 echo '<table align="center" cellpadding="20"><tr><td>';
3072 print_single_button($linkyes, NULL, __gettext('Yes'), 'post', $CFG->framename
);
3074 print_single_button($linkno, NULL, __gettext('No'), 'post', $CFG->framename
);
3075 echo '</td></tr></table>';
3076 print_simple_box_end();
3080 * Redirects the user to another page, after printing a notice
3082 * @param string $url The url to take the user to
3083 * @param string $message The text message to display to the user about the redirect, if any
3084 * @param string $delay How long before refreshing to the new page at $url?
3085 * @todo '&' needs to be encoded into '&' for XHTML compliance,
3086 * however, this is not true for javascript. Therefore we
3087 * first decode all entities in $url (since we cannot rely on)
3088 * the correct input) and then encode for where it's needed
3089 * echo "<script type='text/javascript'>alert('Redirect $url');</script>";
3091 function redirect($url, $message='', $delay='0') {
3093 $url = clean_text($url);
3094 $message = clean_text($message);
3096 $url = htmlspecialchars_decode($url, ENT_COMPAT
); // for php < 5.1.0 this is defined in elgglib.php
3097 $url = str_replace(array("\n", "\r"), '', $url); // some more cleaning
3098 $encodedurl = htmlspecialchars($url, ENT_COMPAT
, 'utf-8');
3100 if (empty($message)) {
3101 echo '<meta http-equiv="refresh" content="'. $delay .'; url='. $encodedurl .'" />';
3102 echo '<script type="text/javascript">'. "\n" .'<!--'. "\n". "location.replace('$url');". "\n". '//-->'. "\n". '</script>'; // To cope with Mozilla bug
3105 if (empty($delay)) {
3106 $delay = 3; // There's no point having a message with no delay
3108 print_header('', '', '', '', '<meta http-equiv="refresh" content="'. $delay .'; url='. $encodedurl .'" />');
3109 echo '<div style="text-align: center;">';
3110 echo '<p>'. $message .'</p>';
3111 //called from setup.php, so gettext module hasn't been loaded yet
3112 if (function_exists("__gettext")) {
3113 $continue = __gettext('Continue');
3115 $continue = 'Continue';
3117 echo '<p>( <a href="'. $encodedurl .'">'. $continue .'</a> )</p>';
3121 <script type
="text/javascript">
3124 function redirect() {
3125 document
.location
.replace('<?php echo $url ?>');
3127 setTimeout("redirect()", <?php
echo ($delay * 1000) ?
>);
3137 * Print a bold message in an optional color.
3139 * @param string $message The message to print out
3140 * @param string $style Optional style to display message text in
3141 * @param string $align Alignment option
3143 function notify ($message, $style='notifyproblem', $align='center') {
3145 if ($style == 'green') {
3146 $style = 'notifysuccess'; // backward compatible with old color system
3149 $message = clean_text($message);
3151 echo '<div class="'.$style.'" align="'. $align .'">'. $message .'</div>'."<br />\n";
3156 * This function is used to rebuild the <nolink> tag because some formats (PLAIN and WIKI)
3157 * will transform it to html entities
3159 * @param string $text Text to search for nolink tag in
3162 function rebuildnolinktag($text) {
3164 $text = preg_replace('/<(\/*nolink)>/i','<$1>',$text);
3171 * Adjust the list of allowed tags based on $CFG->allowobjectembed and user roles (admin)
3173 function adjust_allowed_tags() {
3175 global $CFG, $ALLOWED_TAGS;
3177 if (!empty($CFG->allowobjectembed
)) {
3178 $ALLOWED_TAGS .= '<embed><object><param>';
3184 * This function makes the return value of ini_get consistent if you are
3185 * setting server directives through the .htaccess file in apache.
3186 * Current behavior for value set from php.ini On = 1, Off = [blank]
3187 * Current behavior for value set from .htaccess On = On, Off = Off
3188 * Contributed by jdell @ unr.edu
3190 * @param string $ini_get_arg ?
3192 * @todo Finish documenting this function
3194 function ini_get_bool($ini_get_arg) {
3195 $temp = ini_get($ini_get_arg);
3197 if ($temp == '1' or strtolower($temp) == 'on') {
3204 * Generate and return a random string of the specified length.
3206 * @param int $length The length of the string to be created.
3209 function random_string ($length=15) {
3210 $pool = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
3211 $pool .= 'abcdefghijklmnopqrstuvwxyz';
3212 $pool .= '0123456789';
3213 $poollen = strlen($pool);
3214 mt_srand ((double) microtime() * 1000000);
3216 for ($i = 0; $i < $length; $i++
) {
3217 $string .= substr($pool, (mt_rand()%
($poollen)), 1);
3222 // Fills user information
3223 function init_user_var($user) {
3227 $user->loggedin
= true;
3228 $user->site
= $CFG->wwwroot
; // for added security, store the site in the session
3229 $user->sesskey
= random_string(10);
3230 $user->sessionIP
= md5(getremoteaddr()); // Store the current IP in the session
3231 // backwards compatibility (TODO this will have to go eventually)
3232 fill_legacy_user_session($user);
3238 // Authentication Function
3239 // Returns true or false
3240 function authenticate_account($username,$password) {
3244 if (empty($CFG->auth
)) {
3245 $CFG->auth
= 'internal';
3247 if (!file_exists($CFG->dirroot
. 'auth/' . $CFG->auth
. '/lib.php')) {
3248 $CFG->auth
= 'internal';
3251 require_once($CFG->dirroot
. 'auth/' . $CFG->auth
. '/lib.php');
3253 // Module authentication function
3254 $function = $CFG->auth
.'_authenticate_user_login';
3256 // Does the function exist
3257 if (!function_exists($function)) {
3258 print 'Error: function '.$function.' not found in auth/' . $CFG->auth
. '/lib.php';
3262 if (!$user = $function($username,$password)) {
3267 if (user_flag_get("banned", $user->ident
)) { // this needs to change.
3272 $messages[] = __gettext("You have been banned from the system!");
3276 // Set Persistent Cookie
3277 $rememberme = optional_param('remember',0);
3278 if (!empty($rememberme)) {
3279 remember_login($user->ident
);
3283 $USER = init_user_var($user);
3287 // Attempts to get login from a cookie
3288 function cookied_login() {
3290 if((!empty($_COOKIE[AUTH_COOKIE
])) && $ticket = md5($_COOKIE[AUTH_COOKIE
])) {
3291 if ($user = get_record('users','code',$ticket)) {
3294 /*** TODO: Create Proper Abstraction Interface - don't use file binding -- ugh ***/
3295 if (!user_flag_get("banned",$USER->ident
)) {
3296 $USER = init_user_var($USER);
3300 $messages[] = __gettext("You have been banned from the system!");
3308 * elgg doesn't have a 'login' page yet, but it will so this can stay here for now
3310 function require_login() {
3311 global $USER, $SESSION,$FULLME;
3313 // Check to see if there's a persistent cookie
3316 // First check that the user is logged in to the site.
3317 if (empty($USER->loggedin
) ||
$USER->site
!= $CFG->wwwroot
) {
3318 $SESSION->wantsurl
= $FULLME;
3319 if (!empty($_SERVER['HTTP_REFERER'])) {
3320 $SESSION->fromurl
= $_SERVER['HTTP_REFERER'];
3323 redirect($CFG->wwwroot
.'login/index.php');
3327 // Make sure current IP matches the one for this session (if required)
3328 if (!empty($CFG->tracksessionip
)) {
3329 if ($USER->sessionIP
!= md5(getremoteaddr())) {
3330 error(__gettext('Sorry, but your IP number seems to have changed from when you first logged in. This security feature prevents crackers stealing your identity while logged in to this site. Normal users should not be seeing this message - please ask the site administrator for help.'));
3334 // Make sure the USER has a sesskey set up. Used for checking script parameters.
3341 function remember_login($id) {
3347 if (!defined("SECRET_SALT")) {
3348 define("SECRET_SALT", "SECRET_SALT");
3350 $ticket = md5(SECRET_SALT
. $id . time());
3351 $md5ticket = md5($ticket);
3353 // Update MD5 of authticket
3354 $user->code
= $md5ticket;
3356 update_record('users',$user);
3358 setcookie(AUTH_COOKIE
, $ticket, time()+AUTH_COOKIE_LENGTH
, $CFG->cookiepath
);
3360 $messages[] = __gettext("The system will remember you and automatically log you in next time.");
3365 // Returns whether the user is logged in or not;
3366 // if not logged in, checks for persistent cookie
3367 function isloggedin() {
3369 if (empty($USER->ident
) && empty($USER->loggedin
)) {
3372 return (!empty($USER->ident
) && !empty($USER->loggedin
));
3375 function get_string($s) {
3376 return __gettext($s);
3379 function print_header() {
3380 $args = func_get_args();
3384 function print_footer() {
3385 $args = func_get_args();
3389 function clean_text($text, $format=FORMAT_MOODLE
) {
3391 global $ALLOWED_TAGS;
3399 /// Remove tags that are not allowed
3400 $text = strip_tags($text, $ALLOWED_TAGS);
3402 /// Add some breaks into long strings of
3403 $text = preg_replace('/(( ){10}) /', '\\1 ', $text);
3405 /// Clean up embedded scripts and , using kses
3406 $text = cleanAttributes($text);
3408 /// Remove script events
3409 $text = eregi_replace("([^a-z])language([[:space:]]*)=", "\\1Xlanguage=", $text);
3410 $text = eregi_replace("([^a-z])on([a-z]+)([[:space:]]*)=", "\\1Xon\\2=", $text);
3417 * Set a key in global configuration
3419 * Set a key/value pair in both this session's {@link $CFG} global variable
3420 * and in the 'config' database table for future sessions.
3422 * Can also be used to update keys for plugin-scoped configs in config_plugin table.
3423 * In that case it doesn't affect $CFG.
3425 * @param string $name the key to set
3426 * @param string $value the value to set
3430 function set_config($name, $value) {
3431 /// No need for get_config because they are usually always available in $CFG
3435 $CFG->$name = $value; // So it's defined for this invocation at least
3437 if (get_field('datalists', 'name', 'name', $name)) {
3438 return set_field('datalists', 'value', $value, 'name', $name);
3440 $config->name
= $name;
3441 $config->value
= $value;
3442 return insert_record('datalists', $config);
3447 * Get configuration values from the global config table
3448 * or the config_plugins table.
3450 * If called with no parameters it will do the right thing
3451 * generating $CFG safely from the database without overwriting
3454 * @param string $name
3456 * @return hash-like object or single value
3459 function get_config($name=NULL) {
3463 if (!empty($name)) { // the user is asking for a specific value
3464 return get_record('datalists', 'name', $name);
3467 // this was originally in setup.php
3468 if ($configs = get_records('datalists')) {
3469 $localcfg = (array)$CFG;
3470 foreach ($configs as $config) {
3471 if (!isset($localcfg[$config->name
])) {
3472 $localcfg[$config->name
] = $config->value
;
3474 if ($localcfg[$config->name
] != $config->value
) {
3475 // complain if the DB has a different
3476 // value than config.php does
3477 error_log("\$CFG->{$config->name} in config.php ({$localcfg[$config->name]}) overrides database setting ({$config->value})");
3482 $localcfg = (object)$localcfg;
3485 // preserve $CFG if DB returns nothing or error
3491 function guest_user() {
3492 $user = new stdClass();
3495 $user->username
= '';
3499 $user->icon_quota
= 0;
3504 function fill_legacy_user_session($user = NULL) {
3506 if (!$user ||
$user == NULL) {
3507 $user = guest_user();
3510 /// Fills up all legacy user session data
3511 /// This function provides backward compatibility
3512 $_SESSION['userid'] = (int) $user->ident
;
3513 $_SESSION['username'] = $user->username
;
3514 $_SESSION['name'] = stripslashes($user->name
);
3515 $_SESSION['email'] = stripslashes($user->email
);
3516 $iconid = (int) $user->icon
;
3517 if ($iconid == -1) {
3518 $_SESSION['icon'] = "default.png";
3520 $icon = get_record('icons','ident',$iconid);
3521 $_SESSION['icon'] = $icon->filename
;
3523 $_SESSION['icon_quota'] = (int) $user->icon_quota
;
3527 * Replace function htmlspecialchars_decode()
3530 * @package PHP_Compat
3531 * @link http://php.net/function.htmlspecialchars_decode
3532 * @author Aidan Lister <aidan@php.net>
3533 * @version $Revision: 1.3 $
3535 * @require PHP 4.0.0 (user_error)
3537 if (!function_exists('htmlspecialchars_decode')) {
3538 function htmlspecialchars_decode($string, $quote_style = null)
3541 if (!is_scalar($string)) {
3542 user_error('htmlspecialchars_decode() expects parameter 1 to be string, ' .
3543 gettype($string) . ' given', E_USER_WARNING
);
3547 if (!is_int($quote_style) && $quote_style !== null) {
3548 user_error('htmlspecialchars_decode() expects parameter 2 to be integer, ' .
3549 gettype($quote_style) . ' given', E_USER_WARNING
);
3554 $from = array('&', '<', '>');
3555 $to = array('&', '<', '>');
3557 // The function does not behave as documented
3558 // This matches the actual behaviour of the function
3559 if ($quote_style & ENT_COMPAT ||
$quote_style & ENT_QUOTES
) {
3567 return str_replace($from, $to, $string);
3573 * Returns the maximum size for uploading files.
3575 * There are five possible upload limits:
3576 * 1. in Apache using LimitRequestBody (no way of checking or changing this)
3577 * 2. in php.ini for 'upload_max_filesize' (can not be changed inside PHP)
3578 * 3. in .htaccess for 'upload_max_filesize' (can not be changed inside PHP)
3579 * 4. in php.ini for 'post_max_size' (can not be changed inside PHP)
3580 * 5. by the limitations on the current situation (eg file quota)
3582 * The last one is passed to this function as an argument (in bytes).
3583 * Anything defined as 0 is ignored.
3584 * The smallest of all the non-zero numbers is returned.
3586 * @param int $maxbytes Current maxbytes (in bytes)
3587 * @return int The maximum size for uploading files.
3588 * @todo Finish documenting this function
3590 function get_max_upload_file_size($maxbytes=0) {
3593 if (! $filesize = ini_get('upload_max_filesize')) {
3594 if (!empty($CFG->absmaxuploadsize
)) {
3595 $filesize = $CFG->absmaxuploadsize
;
3600 $minimumsize = get_real_size($filesize);
3602 if ($postsize = ini_get('post_max_size')) {
3603 $postsize = get_real_size($postsize);
3604 if ($postsize < $minimumsize) {
3605 $minimumsize = $postsize;
3609 if ($maxbytes and $maxbytes < $minimumsize) {
3610 $minimumsize = $maxbytes;
3613 return $minimumsize;
3616 function remove_dir($dir, $content_only=false) {
3617 // if content_only=true then delete all but
3618 // the directory itself
3620 $handle = opendir($dir);
3621 while (false!==($item = readdir($handle))) {
3622 if($item != '.' && $item != '..') {
3623 if(is_dir($dir.'/'.$item)) {
3624 remove_dir($dir.'/'.$item);
3626 unlink($dir.'/'.$item);
3631 if ($content_only) {
3637 //Function to check if a directory exists
3638 //and, optionally, create it
3639 function check_dir_exists($dir,$create=false) {
3649 $status = mkdir ($dir,$CFG->directorypermissions
);
3655 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3656 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3657 //This functions are used to copy any file or directory ($from_file)
3658 //to a new file or directory ($to_file). It works recursively and
3659 //mantains file perms.
3660 //I've copied it from: http://www.php.net/manual/en/function.copy.php
3661 //Little modifications done
3663 function copy_file ($from_file,$to_file) {
3667 if (is_file($from_file)) {
3669 if (copy($from_file,$to_file)) {
3670 chmod($to_file,$CFG->filepermissions
);
3675 else if (is_dir($from_file)) {
3676 return copy_dir($from_file,$to_file);
3683 function copy_dir($from_file,$to_file) {
3687 if (!is_dir($to_file)) {
3689 $status = mkdir($to_file,$CFG->directorypermissions
);
3691 $dir = opendir($from_file);
3692 while ($file=readdir($dir)) {
3693 if ($file=="." ||
$file=="..") {
3696 $status = copy_file ("$from_file/$file","$to_file/$file");
3703 function zip_files ($originalfiles, $destination) {
3704 //Zip an array of files/dirs to a destination zip file
3705 //Both parameters must be FULL paths to the files/dirs
3709 //Extract everything from destination
3710 $path_parts = pathinfo(cleardoubleslashes($destination));
3711 $destpath = $path_parts["dirname"]; //The path of the zip file
3712 $destfilename = $path_parts["basename"]; //The name of the zip file
3713 $extension = $path_parts["extension"]; //The extension of the file
3716 if (empty($destfilename)) {
3720 //If no extension, add it
3721 if (empty($extension)) {
3723 $destfilename = $destfilename.'.'.$extension;
3726 //Check destination path exists
3727 if (!is_dir($destpath)) {
3731 //Check destination path is writable. TODO!!
3733 //Clean destination filename
3734 $destfilename = clean_filename($destfilename);
3736 //Now check and prepare every file
3740 foreach ($originalfiles as $file) { //Iterate over each file
3741 //Check for every file
3742 $tempfile = cleardoubleslashes($file); // no doubleslashes!
3743 //Calculate the base path for all files if it isn't set
3744 if ($origpath === NULL) {
3745 $origpath = rtrim(cleardoubleslashes(dirname($tempfile)), "/");
3747 //See if the file is readable
3748 if (!is_readable($tempfile)) { //Is readable
3751 //See if the file/dir is in the same directory than the rest
3752 if (rtrim(cleardoubleslashes(dirname($tempfile)), "/") != $origpath) {
3755 //Add the file to the array
3756 $files[] = $tempfile;
3759 //Everything is ready:
3760 // -$origpath is the path where ALL the files to be compressed reside (dir).
3761 // -$destpath is the destination path where the zip file will go (dir).
3762 // -$files is an array of files/dirs to compress (fullpath)
3763 // -$destfilename is the name of the zip file (without path)
3765 //print_object($files); //Debug
3767 if (empty($CFG->zip
)) { // Use built-in php-based zip function
3769 include_once("$CFG->libdir/pclzip/pclzip.lib.php");
3770 $archive = new PclZip(cleardoubleslashes("$destpath/$destfilename"));
3771 if (($list = $archive->create($files, PCLZIP_OPT_REMOVE_PATH
,$origpath) == 0)) {
3772 notice($archive->errorInfo(true));
3776 } else { // Use external zip program
3779 foreach ($files as $filetozip) {
3780 $filestozip .= escapeshellarg(basename($filetozip));
3783 //Construct the command
3784 $separator = strtoupper(substr(PHP_OS
, 0, 3)) === 'WIN' ?
' &' : ' ;';
3785 $command = 'cd '.escapeshellarg($origpath).$separator.
3786 escapeshellarg($CFG->zip
).' -r '.
3787 escapeshellarg(cleardoubleslashes("$destpath/$destfilename")).' '.$filestozip;
3788 //All converted to backslashes in WIN
3789 if (strtoupper(substr(PHP_OS
, 0, 3)) === 'WIN') {
3790 $command = str_replace('/','\\',$command);
3797 function unzip_file ($zipfile, $destination = '', $showstatus = true) {
3798 //Unzip one zip file to a destination dir
3799 //Both parameters must be FULL paths
3800 //If destination isn't specified, it will be the
3801 //SAME directory where the zip file resides.
3805 //Extract everything from zipfile
3806 $path_parts = pathinfo(cleardoubleslashes($zipfile));
3807 $zippath = $path_parts["dirname"]; //The path of the zip file
3808 $zipfilename = $path_parts["basename"]; //The name of the zip file
3809 $extension = $path_parts["extension"]; //The extension of the file
3812 if (empty($zipfilename)) {
3816 //If no extension, error
3817 if (empty($extension)) {
3822 $zipfile = cleardoubleslashes($zipfile);
3824 //Check zipfile exists
3825 if (!file_exists($zipfile)) {
3829 //If no destination, passed let's go with the same directory
3830 if (empty($destination)) {
3831 $destination = $zippath;
3834 //Clear $destination
3835 $destpath = rtrim(cleardoubleslashes($destination), "/");
3837 //Check destination path exists
3838 if (!is_dir($destpath)) {
3842 //Check destination path is writable. TODO!!
3844 //Everything is ready:
3845 // -$zippath is the path where the zip file resides (dir)
3846 // -$zipfilename is the name of the zip file (without path)
3847 // -$destpath is the destination path where the zip file will uncompressed (dir)
3849 if (empty($CFG->unzip
)) { // Use built-in php-based unzip function
3851 include_once("$CFG->libdir/pclzip/pclzip.lib.php");
3852 $archive = new PclZip(cleardoubleslashes("$zippath/$zipfilename"));
3853 if (!$list = $archive->extract(PCLZIP_OPT_PATH
, $destpath,
3854 PCLZIP_CB_PRE_EXTRACT
, 'unzip_cleanfilename')) {
3855 notice($archive->errorInfo(true));
3859 } else { // Use external unzip program
3861 $separator = strtoupper(substr(PHP_OS
, 0, 3)) === 'WIN' ?
' &' : ' ;';
3862 $redirection = strtoupper(substr(PHP_OS
, 0, 3)) === 'WIN' ?
'' : ' 2>&1';
3864 $command = 'cd '.escapeshellarg($zippath).$separator.
3865 escapeshellarg($CFG->unzip
).' -o '.
3866 escapeshellarg(cleardoubleslashes("$zippath/$zipfilename")).' -d '.
3867 escapeshellarg($destpath).$redirection;
3868 //All converted to backslashes in WIN
3869 if (strtoupper(substr(PHP_OS
, 0, 3)) === 'WIN') {
3870 $command = str_replace('/','\\',$command);
3872 Exec($command,$list);
3875 //Display some info about the unzip execution
3877 unzip_show_status($list,$destpath);
3883 function unzip_cleanfilename ($p_event, &$p_header) {
3884 //This function is used as callback in unzip_file() function
3885 //to clean illegal characters for given platform and to prevent directory traversal.
3886 //Produces the same result as info-zip unzip.
3887 $p_header['filename'] = ereg_replace('[[:cntrl:]]', '', $p_header['filename']); //strip control chars first!
3888 $p_header['filename'] = ereg_replace('\.\.+', '', $p_header['filename']); //directory traversal protection
3889 if (strtoupper(substr(PHP_OS
, 0, 3)) === 'WIN') {
3890 $p_header['filename'] = ereg_replace('[:*"?<>|]', '_', $p_header['filename']); //replace illegal chars
3891 $p_header['filename'] = ereg_replace('^([a-zA-Z])_', '\1:', $p_header['filename']); //repair drive letter
3893 //Add filtering for other systems here
3894 // BSD: none (tested)
3898 $p_header['filename'] = cleardoubleslashes($p_header['filename']); //normalize the slashes/backslashes
3903 function unzip_show_status ($list,$removepath) {
3904 //This function shows the results of the unzip execution
3905 //depending of the value of the $CFG->zip, results will be
3906 //text or an array of files.
3910 if (empty($CFG->unzip
)) { // Use built-in php-based zip function
3911 $strname = get_string("name");
3912 $strsize = get_string("size");
3913 $strmodified = get_string("modified");
3914 $strstatus = get_string("status");
3915 echo "<table cellpadding=\"4\" cellspacing=\"2\" border=\"0\" width=\"640\">";
3916 echo "<tr><th class=\"header\" align=\"left\">$strname</th>";
3917 echo "<th class=\"header\" align=\"right\">$strsize</th>";
3918 echo "<th class=\"header\" align=\"right\">$strmodified</th>";
3919 echo "<th class=\"header\" align=\"right\">$strstatus</th></tr>";
3920 foreach ($list as $item) {
3922 $item['filename'] = str_replace(cleardoubleslashes($removepath).'/', "", $item['filename']);
3923 print_cell("left", $item['filename']);
3924 if (! $item['folder']) {
3925 print_cell("right", display_size($item['size']));
3927 echo "<td> </td>";
3929 $filedate = userdate($item['mtime'], get_string("strftimedatetime"));
3930 print_cell("right", $filedate);
3931 print_cell("right", $item['status']);
3936 } else { // Use external zip program
3937 print_simple_box_start("center");
3939 foreach ($list as $item) {
3940 echo str_replace(cleardoubleslashes($removepath.'/'), '', $item).'<br />';
3943 print_simple_box_end();
3947 function isadmin($userid=0) {
3950 static $admins, $nonadmins;
3952 if (!isset($admins)) {
3954 $nonadmins = array();
3957 if (empty($userid)) {
3958 if (empty($USER)) { // maybe not logged in
3961 $userid = (int) $USER->ident
;
3965 if (in_array($userid, $admins)) {
3967 } else if (in_array($userid, $nonadmins)) {
3969 } else if (user_flag_get('admin', $userid)) {
3970 $admins[] = $userid;
3973 $nonadmins[] = $userid;
3981 function get_admins() {
3983 return get_records_sql('SELECT u.* FROM '.$CFG->prefix
.'users u
3984 JOIN '.$CFG->prefix
.'user_flags uf ON u.ident = uf.user_id
3985 WHERE flag = ?',array('admin'));
3989 function get_admin() {
3991 return get_record_sql('SELECT u.* FROM '.$CFG->prefix
.'users u
3992 JOIN '.$CFG->prefix
.'user_flags uf ON u.ident = uf.user_id
3993 WHERE flag = ? ORDER BY ident',array('admin'),true);
3998 // cli_die($str) - a perlish die()
4000 // this function call will exit with a warning and an exit code
4001 // that clearly indicates that something went wrong.
4003 // We shouldn't need this, but due to PHP's web-centric heritage,
4004 // die()/exit() cant print a warnign _and_ set a non-success exit
4005 // code. Silly thing -- disregarding POSIX and friends doesn't get
4007 function cli_die ($str, $code) {
4008 trigger_error($str);
4015 // Take a comma-separated string of keywords and create the relevant tag entries
4016 // in the database. Returns a cleaned comma-separated keyword string.
4017 function insert_tags_from_string ($string, $tagtype, $ref, $access, $owner) {
4020 $owner = (int) $owner;
4021 $tagtype = trim($tagtype);
4022 $access = trim($access);
4023 $string = trim($string);
4026 $string = str_replace("\n", "", $string);
4027 $string = str_replace("\r", "", $string);
4029 $keyword_list = explode(",", $string);
4030 $keyword_list = array_unique($keyword_list);
4031 sort($keyword_list);
4032 if (sizeof($keyword_list) > 0) {
4033 foreach($keyword_list as $key => $list_item) {
4034 $list_item = trim($list_item);
4039 $keywords .= $list_item;
4041 $t->tagtype
= $tagtype;
4042 $t->access
= $access;
4043 $t->tag
= $list_item;
4046 insert_record('tags', $t);
4056 // return the "this is restricted" text for a given access value
4057 // functionised to reduce code duplication
4058 function get_access_description ($accessvalue) {
4060 if ($accessvalue != "PUBLIC") {
4061 if ($accessvalue == "LOGGED_IN") {
4062 $title = "[" . __gettext("Logged in users") . "] ";
4063 } else if (substr_count($accessvalue, "user") > 0) {
4064 $title = "[" . __gettext("Private") . "] ";
4066 $title = "[" . __gettext("Restricted") . "] ";
4075 // Activate URLs - turns any URLs found into links
4076 function activate_urls ($str) {
4078 // Function for URL autodiscovery
4083 // lift all links, images and image maps
4085 "'<a[^>]*>.*?</a>'si",
4086 "'<map[^>]*>.*?</map>'si",
4087 "'<script[^>]*>.*?</script>'si",
4088 "'<style[^>]*>.*?</style>'si",
4092 foreach($url_tags as $url_tag)
4094 preg_match_all($url_tag, $str, $matches, PREG_SET_ORDER
);
4095 foreach($matches as $match)
4097 $key = "<" . md5($match[0]) . ">";
4099 $replace[] = $match[0];
4103 $str = str_replace($replace, $search, $str);
4105 // indicate where urls end if they have these trailing special chars
4106 $sentinals = array("/&(quot|#34);/i", // Replace html entities
4110 "/&(iexcl|#161);/i",
4112 "/&(pound|#163);/i",
4113 "/&(copy|#169);/i");
4115 $str = preg_replace($sentinals, "<marker>\\0", $str);
4119 preg_replace( "|\w{3,10}://[\w\.\-_]+(:\d+)?[^\s\"\'<>\(\)\{\}]*|",
4120 "<a href=\"\\0\">[".__gettext("Click to view link") . "]</a>", $str );
4122 $str = str_replace("<marker>", '', $str);
4123 return str_replace($search, $replace, $str);