3 * FusionForge miscellaneous utils
5 * Copyright 1999-2001, VA Linux Systems, Inc.
6 * Copyright 2009-2010, Roland Mas
7 * Copyright 2009-2010, Franck Villaume - Capgemini
8 * Copyright 2010, Thorsten Glaser <t.glaser@tarent.de>
9 * Copyright (C) 2010-2011 Alain Peyrat - Alcatel-Lucent
11 * This file is part of FusionForge. FusionForge is free software;
12 * you can redistribute it and/or modify it under the terms of the
13 * GNU General Public License as published by the Free Software
14 * Foundation; either version 2 of the Licence, or (at your option)
17 * FusionForge is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License along
23 * with FusionForge; if not, write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 * htpasswd_apr1_md5($plainpasswd) - generate htpasswd md5 format password
30 * From http://www.php.net/manual/en/function.crypt.php#73619
32 function htpasswd_apr1_md5($plainpasswd) {
33 $salt = substr(str_shuffle("abcdefghijklmnopqrstuvwxyz0123456789"), 0, 8);
34 $len = strlen($plainpasswd);
35 $text = $plainpasswd.'$apr1$'.$salt;
36 $bin = pack("H32", md5($plainpasswd.$salt.$plainpasswd));
38 for($i = $len; $i > 0; $i -= 16) { $text .= substr($bin, 0, min(16, $i)); }
39 for($i = $len; $i > 0; $i >>= 1) { $text .= ($i & 1) ? chr(0) : $plainpasswd{0}; }
40 $bin = pack("H32", md5($text));
41 for($i = 0; $i < 1000; $i++) {
42 $new = ($i & 1) ? $plainpasswd : $bin;
43 if ($i % 3) $new .= $salt;
44 if ($i % 7) $new .= $plainpasswd;
45 $new .= ($i & 1) ? $bin : $plainpasswd;
46 $bin = pack("H32", md5($new));
48 for ($i = 0; $i < 5; $i++) {
52 $tmp = $bin[$i].$bin[$k].$bin[$j].$tmp;
54 $tmp = chr(0).chr(0).$bin[11].$tmp;
55 $tmp = strtr(strrev(substr(base64_encode($tmp), 2)),
56 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
57 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
58 return "$"."apr1"."$".$salt."$".$tmp;
62 * is_utf8($string) - utf-8 detection
64 * From http://www.php.net/manual/en/function.mb-detect-encoding.php#85294
66 function is_utf8($str) {
70 for($i=0; $i<$len; $i++){
73 if(($c >= 254)) return false;
74 elseif($c >= 252) $bits=6;
75 elseif($c >= 248) $bits=5;
76 elseif($c >= 240) $bits=4;
77 elseif($c >= 224) $bits=3;
78 elseif($c >= 192) $bits=2;
80 if(($i+$bits) > $len) return false;
84 if($b < 128 || $b > 191) return false;
93 * removeCRLF() - remove any Carriage Return-Line Feed from a string.
94 * That function is useful to remove the possibility of a CRLF Injection when sending mail
95 * All the data that we will send should be passed through that function
97 * @param string The string that we want to empty from any CRLF
99 function util_remove_CRLF($str) {
100 return strtr($str, "\015\012", ' ');
105 * util_check_fileupload() - determines if a filename is appropriate for upload
107 * @param array The uploaded file as returned by getUploadedFile()
109 function util_check_fileupload($filename) {
111 /* Empty file is a valid file.
112 This is because this function should be called
113 unconditionally at the top of submit action processing
114 and many forms have optional file upload. */
115 if ($filename == 'none' || $filename == '') {
119 /* This should be enough... */
120 if (!is_uploaded_file($filename)) {
123 /* ... but we'd rather be paranoic */
124 if (strstr($filename, '..')) {
127 if (!is_file($filename)) {
130 if (!file_exists($filename)) {
133 if ((dirname($filename) != '/tmp') &&
134 (dirname($filename) != "/var/tmp")) {
141 * util_check_url() - determines if given URL is valid.
143 * Currently, test is very basic, only the protocol is
144 * checked, allowed values are: http, https, ftp.
146 * @param string The URL
147 * @return boolean true if valid, false if not valid.
149 function util_check_url($url) {
150 return (preg_match('/^(http|https|ftp):\/\//', $url) > 0);
154 * util_send_message() - Send email
155 * This function should be used in place of the PHP mail() function
157 * @param string The email recipients address
158 * @param string The email subject
159 * @param string The body of the email message
160 * @param string The optional email sender address. Defaults to 'noreply@'
161 * @param string The addresses to blind-carbon-copy this message
162 * @param string The optional email sender name. Defaults to ''
163 * @param boolean Whether to send plain text or html email
166 function util_send_message($to,$subject,$body,$from='',$BCC='',$sendername='',$extra_headers='',$send_html_email=false) {
170 $to='noreply@'.forge_get_config('web_host');
173 $from='noreply@'.forge_get_config('web_host');
177 $charset = _('UTF-8');
183 if ($extra_headers) {
184 $body2 .= $extra_headers."\n";
187 "\nFrom: ".util_encode_mailaddr($from,$sendername,$charset);
188 if (forge_get_config('bcc_all_emails') != '') {
189 $BCC.=",".forge_get_config('bcc_all_emails');
192 $body2 .= "\nBCC: $BCC";
194 $send_html_email?$type="html":$type="plain";
195 $body2 .= "\n".util_encode_mimeheader("Subject", $subject, $charset).
196 "\nContent-type: text/$type; charset=$charset".
198 util_convert_body($body, $charset);
200 if (!forge_get_config('sendmail_path')){
201 $sys_sendmail_path="/usr/sbin/sendmail";
204 $handle = popen(forge_get_config('sendmail_path')." -f'$from' -t -i", 'w');
205 fwrite ($handle, $body2);
210 * util_encode_mailaddr() - Encode email address to MIME format
212 * @param string The email address
213 * @param string The email's owner name
214 * @param string The converting charset
217 function util_encode_mailaddr($email,$name,$charset) {
218 if (function_exists('mb_convert_encoding') && trim($name) != "") {
219 $name = "=?".$charset."?B?".
220 base64_encode(mb_convert_encoding(
221 $name,$charset,"UTF-8")).
225 return $name." <".$email."> ";
229 * util_encode_mimeheader() - Encode mimeheader
231 * @param string The name of the header (e.g. "Subject")
232 * @param string The email subject
233 * @param string The converting charset (like ISO-2022-JP)
234 * @return string The MIME encoded subject
237 function util_encode_mimeheader($headername,$str,$charset) {
238 if (function_exists('mb_internal_encoding') &&
239 function_exists('mb_encode_mimeheader')) {
240 $x = mb_internal_encoding();
241 mb_internal_encoding("UTF-8");
242 $y = mb_encode_mimeheader($headername . ": " . $str,
244 mb_internal_encoding($x);
248 if (!function_exists('mb_convert_encoding')) {
249 return $headername . ": " . $str;
252 return $headername . ": " . "=?".$charset."?B?".
253 base64_encode(mb_convert_encoding(
254 $str,$charset,"UTF-8")).
259 * util_convert_body() - Convert body of the email message
261 * @param string The body of the email message
262 * @param string The charset of the email message
263 * @return string The converted body of the email message
266 function util_convert_body($str,$charset) {
267 if (!function_exists('mb_convert_encoding') || $charset == 'UTF-8') {
271 return mb_convert_encoding($str,$charset,"UTF-8");
274 function util_send_jabber($to,$subject,$body) {
275 if (!forge_get_config('use_jabber')) {
278 $JABBER = new Jabber();
279 if (!$JABBER->Connect()) {
280 echo '<br />Unable to connect';
283 //$JABBER->SendAuth();
284 //$JABBER->AccountRegistration();
285 if (!$JABBER->SendAuth()) {
286 echo '<br />Auth Failure';
287 $JABBER->Disconnect();
289 //or die("Couldn't authenticate!");
291 $JABBER->SendPresence(NULL, NULL, "online");
293 $body=htmlspecialchars($body);
294 $to_arr=explode(',',$to);
295 for ($i=0; $i<count($to_arr); $i++) {
297 //echo '<br />Sending Jabbers To: '.$to_arr[$i];
298 if (!$JABBER->SendMessage($to_arr[$i], "normal", NULL, array("body" => $body,"subject"=>$subject))) {
299 echo '<br />Error Sending to '.$to_arr[$i];
304 $JABBER->CruiseControl(2);
305 $JABBER->Disconnect();
309 * util_handle_message() - a convenience wrapper which sends messages
310 * to either a jabber account or email account or both, depending on
313 * @param array array of user_id's from the user table
314 * @param string subject of the message
315 * @param string the message body
316 * @param string a comma-separated list of email address
317 * @param string a comma-separated list of jabber address
318 * @param string From header
320 function util_handle_message($id_arr,$subject,$body,$extra_emails='',$extra_jabbers='',$from='') {
323 if (count($id_arr) < 1) {
326 $res = db_query_params ('SELECT user_id,jabber_address,email,jabber_only FROM users WHERE user_id = ANY ($1)',
327 array (db_int_array_to_any_clause ($id_arr))) ;
328 $rows = db_numrows($res) ;
330 for ($i=0; $i<$rows; $i++) {
331 if (db_result($res, $i, 'user_id') == 100) {
332 // Do not send messages to "Nobody"
336 // Build arrays of the jabber address
338 if (db_result($res,$i,'jabber_address')) {
339 $address['jabber_address'][]=db_result($res,$i,'jabber_address');
340 if (db_result($res,$i,'jabber_only') != 1) {
341 $address['email'][]=db_result($res,$i,'email');
344 $address['email'][]=db_result($res,$i,'email');
347 if (isset ($address['email']) && count($address['email']) > 0) {
348 $extra_emails=implode($address['email'],',').',' . $extra_emails;
350 if (isset ($address['jabber_address']) && count($address['jabber_address']) > 0) {
351 $extra_jabbers=implode($address['jabber_address'],',').','.$extra_jabbers;
355 util_send_message('',$subject,$body,$from,$extra_emails);
357 if ($extra_jabbers) {
358 util_send_jabber($extra_jabbers,$subject,$body);
363 * util_unconvert_htmlspecialchars() - Unconverts a string converted with htmlspecialchars()
365 * @param string The string to unconvert
366 * @returns The unconverted string
369 function util_unconvert_htmlspecialchars($string) {
370 if (strlen($string) < 1) {
373 //$trans = get_html_translation_table(HTMLENTITIES, ENT_QUOTES);
374 $trans = get_html_translation_table(HTML_ENTITIES);
375 $trans = array_flip ($trans);
376 $str = strtr ($string, $trans);
382 * util_result_columns_to_assoc() - Takes a result set and turns the column pair into an associative array
384 * @param string The result set ID
385 * @param int The column key
386 * @param int The optional column value
387 * @returns An associative array
390 function util_result_columns_to_assoc($result, $col_key=0, $col_val=1) {
391 $rows=db_numrows($result);
395 for ($i=0; $i<$rows; $i++) {
396 $arr[db_result($result,$i,$col_key)]=db_result($result,$i,$col_val);
405 * util_result_column_to_array() - Takes a result set and turns the optional column into an array
407 * @param int The result set ID
408 * @param int The column
412 function &util_result_column_to_array($result, $col=0) {
414 Takes a result set and turns the optional column into
417 $rows=db_numrows($result);
421 for ($i=0; $i<$rows; $i++) {
422 $arr[$i]=db_result($result,$i,$col);
431 * util_wrap_find_space() - Find the first space in a string
433 * @param string The string in which to find the space (must be UTF8!)
434 * @param int The number of characters to wrap - Default is 80
435 * @returns The position of the first space
438 function util_wrap_find_space($string,$wrap) {
445 //find the first space starting at $start
446 $pos=@strpos($string,' ',$start);
448 //if that space is too far over, go back and start more to the left
449 if (($pos > ($wrap+5)) || !$pos) {
451 $start=($wrap-($try*5));
452 //if we've gotten so far left , just truncate the line
455 $code = ord(substr($string,$wrap,1));
458 //Here is single byte character
459 //or head of multi byte character
462 //Do not break multi byte character
477 * util_line_wrap() - Automatically linewrap text
479 * @param string The text to wrap
480 * @param int The number of characters to wrap - Default is 80
481 * @param string The line break to use - Default is '\n'
482 * @returns The wrapped text
485 function util_line_wrap ($text, $wrap = 80, $break = "\n") {
486 $paras = explode("\n", $text);
490 while ($i < count($paras)) {
491 if (strlen($paras[$i]) <= $wrap) {
492 $result[] = $paras[$i];
495 $pos=util_wrap_find_space($paras[$i],$wrap);
497 $result[] = substr($paras[$i], 0, $pos);
499 $new = trim(substr($paras[$i], $pos, strlen($paras[$i]) - $pos));
502 $pos=util_wrap_find_space($paras[$i],$wrap);
508 return implode($break, $result);
512 * util_make_links() - Turn URL's into HREF's.
514 * @param string The URL
515 * @returns The HREF'ed URL
518 function util_make_links ($data='') {
522 $lines = explode("\n",$data);
524 while ( list ($key,$line) = each ($lines)) {
525 // When we come here, we usually have form input
526 // encoded in entities. Our aim is to NOT include
527 // angle brackets in the URL
528 // (RFC2396; http://www.w3.org/Addressing/URL/5.1_Wrappers.html)
529 $line = str_replace('>', "\1", $line);
530 $line = preg_replace( "/([ \t]|^)www\./i", " http://www.", $line);
531 $text = preg_replace( "/([[:alnum:]]+):\/\/([^[:space:]<\1]*)([[:alnum:]#?\/&=])/i",
532 "<a href=\"\\1://\\2\\3\" target=\"_new\">\\1://\\2\\3</a>", $line);
533 $text = preg_replace(
534 "/([[:space:]]|^)(([a-z0-9_]|\\-|\\.)+@([^[:space:]]*)([[:alnum:]-]))/i",
535 "\\1<a href=\"mailto:\\2\" target=\"_new\">\\2</a>",
538 $text = str_replace("\1", '>', $text);
545 * show_priority_colors_key() - Show the priority colors legend
548 function show_priority_colors_key() {
549 echo '<p /><strong> '._('Priority Colors').':</strong><br />
551 <table border="0"><tr>';
553 for ($i=1; $i<6; $i++) {
555 <td class="priority'.$i.'">'.$i.'</td>';
557 echo '</tr></table>';
561 * utils_buildcheckboxarray() - Build a checkbox array
563 * @param int Number of options to be in the array
564 * @param string The name of the checkboxes
565 * @param array An array of boxes to be pre-checked
568 function utils_buildcheckboxarray($options,$name,$checked_array) {
569 $option_count=count($options);
570 $checked_count=count($checked_array);
572 for ($i=1; $i<=$option_count; $i++) {
574 <br /><input type="checkbox" name="'.$name.'" value="'.$i.'"';
575 for ($j=0; $j<$checked_count; $j++) {
576 if ($i == $checked_array[$j]) {
580 echo '> '.$options[$i];
585 * utils_requiredField() - Adds the required field marker
587 * @return a string holding the HTML to mark a required field
589 function utils_requiredField() {
590 return '<span class="requiredfield">*</span>';
594 * GraphResult() - Takes a database result set and builds a graph.
595 * The first column should be the name, and the second column should be the values
596 * Be sure to include HTL_Graphs.php before using this function
598 * @author Tim Perdue tperdue@valinux.com
599 * @param int The databse result set ID
600 * @param string The title of the graph
603 function GraphResult($result, $title) {
604 $rows=db_numrows($result);
606 if ((!$result) || ($rows < 1)) {
612 for ($j=0; $j<db_numrows($result); $j++) {
613 if (db_result($result, $j, 0) != '' && db_result($result, $j, 1) != '' ) {
614 $names[$j]= db_result($result, $j, 0);
615 $values[$j]= db_result($result, $j, 1);
620 This is another function detailed below
622 GraphIt($names,$values,$title);
627 * GraphIt() - Build a graph
629 * @author Tim Perdue tperdue@valinux.com
630 * @param array An array of names
631 * @param array An array of values
632 * @param string The title of the graph
635 function GraphIt($name_string, $value_string, $title) {
638 $counter=count($name_string);
641 Can choose any color you wish
645 for ($i = 0; $i < $counter; $i++) {
646 $bars[$i]=$HTML->COLOR_LTBACK1;
649 $counter=count($value_string);
652 Figure the max_value passed in, so scale can be determined
657 for ($i = 0; $i < $counter; $i++) {
658 if ($value_string[$i] > $max_value) {
659 $max_value=$value_string[$i];
663 if ($max_value < 1) {
668 I want my graphs all to be 800 pixels wide, so that is my divisor
671 $scale=(400/$max_value);
674 I create a wrapper table around the graph that holds the title
680 echo $GLOBALS['HTML']->listTableTop ($title_arr);
683 Create an associate array to pass in. I leave most of it blank
712 This is the actual call to the HTML_Graphs class
715 html_graph($name_string,$value_string,$bars,$vals);
719 <!-- end outer graph table -->';
720 echo $GLOBALS['HTML']->listTableBottom();
724 * ShowResultSet() - Show a generic result set
725 * Very simple, plain way to show a generic result set
727 * @param int The result set ID
728 * @param string The title of the result set
729 * @param bool The option to turn URL's into links
730 * @param bool The option to display headers
731 * @param array The db field name -> label mapping
732 * @param array Don't display these cols
735 function ShowResultSet($result,$title='',$linkify=false,$displayHeaders=true,$headerMapping=array(), $excludedCols=array()) {
736 global $group_id,$HTML;
739 $rows = db_numrows($result);
740 $cols = db_numfields($result);
742 echo '<table border="0" width="100%">';
744 /* Create the headers */
745 $headersCellData = array();
746 $colsToKeep = array();
747 for ($i=0; $i < $cols; $i++) {
748 $fieldName = db_fieldname($result, $i);
749 if(in_array($fieldName, $excludedCols)) {
753 if(isset($headerMapping[$fieldName])) {
754 if(is_array($headerMapping[$fieldName])) {
755 $headersCellData[] = $headerMapping[$fieldName];
757 $headersCellData[] = array($headerMapping[$fieldName]);
761 $headersCellData[] = array($fieldName);
765 /* Create the title */
766 if(strlen($title) > 0) {
767 $titleCellData = array();
768 $titleCellData[] = array($title, 'colspan="'.count($headersCellData).'"');
769 echo $HTML->multiTableRow('', $titleCellData, TRUE);
772 /* Display the headers */
773 if($displayHeaders) {
774 echo $HTML->multiTableRow('', $headersCellData, TRUE);
777 /* Create the rows */
778 for ($j = 0; $j < $rows; $j++) {
779 echo '<tr '. $HTML->boxGetAltRowStyle($j) . '>';
780 for ($i = 0; $i < $cols; $i++) {
781 if(in_array($i, $colsToKeep)) {
782 if ($linkify && $i == 0) {
783 $link = '<a href="'.getStringFromServer('PHP_SELF').'?';
785 if ($linkify == "bug_cat") {
786 $link .= 'group_id='.$group_id.'&bug_cat_mod=y&bug_cat_id='.db_result($result, $j, 'bug_category_id').'">';
787 } else if($linkify == "bug_group") {
788 $link .= 'group_id='.$group_id.'&bug_group_mod=y&bug_group_id='.db_result($result, $j, 'bug_group_id').'">';
789 } else if($linkify == "patch_cat") {
790 $link .= 'group_id='.$group_id.'&patch_cat_mod=y&patch_cat_id='.db_result($result, $j, 'patch_category_id').'">';
791 } else if($linkify == "support_cat") {
792 $link .= 'group_id='.$group_id.'&support_cat_mod=y&support_cat_id='.db_result($result, $j, 'support_category_id').'">';
793 } else if($linkify == "pm_project") {
794 $link .= 'group_id='.$group_id.'&project_cat_mod=y&project_cat_id='.db_result($result, $j, 'group_project_id').'">';
796 $link = $linkend = '';
799 $link = $linkend = '';
801 echo '<td>'.$link . db_result($result, $j, $i) . $linkend.'</td>';
813 * validate_email() - Validate an email address
815 * @param string The address string to validate
816 * @returns true on success/false on error
819 function validate_email ($address) {
820 if ( preg_match( "/^[-!#$%&\'*+\\.\/0-9=?A-Z^_`a-z{|}~]+@[-!#$%&\'*+\\/0-9=?A-Z^_`a-z{|}~]+\.[-!#$%&\'*+\\.\/0-9=?A-Z^_`a-z{|}~]+$/", $address) ) {
828 * validate_emails() - Validate a list of e-mail addresses
830 * @param string E-mail list
831 * @param char Separator
832 * @returns array Array of invalid e-mail addresses (if empty, all addresses are OK)
834 function validate_emails ($addresses, $separator=',') {
835 if (strlen($addresses) == 0) return array();
837 $emails = explode($separator, $addresses);
840 if (is_array($emails)) {
841 foreach ($emails as $email) {
842 $email = trim($email); // This is done so we can validate lists like "a@b.com, c@d.com"
843 if (!validate_email($email)) $ret[] = $email;
852 * util_is_valid_filename() - Verifies whether a file has a valid filename
854 * @param string The file to verify
855 * @returns true on success/false on error
858 function util_is_valid_filename ($file) {
860 $invalidchars = preg_replace("/[-A-Z0-9+_\. ~]/i","",$file);
862 if (!empty($invalidchars)) {
865 if (strstr($file,'..')) {
874 * valid_hostname() - Validates a hostname string to make sure it doesn't contain invalid characters
876 * @param string The optional hostname string
877 * @returns true on success/false on failur
880 function valid_hostname ($hostname = "xyz") {
883 $invalidchars = preg_replace("/[-A-Z0-9\.]/i","",$hostname);
885 if (!empty($invalidchars)) {
889 //double dot, starts with a . or -
890 if ( preg_match("/\.\./",$hostname) || preg_match("/^\./",$hostname) || preg_match("/^\-/",$hostname) ) {
894 $multipoint = explode(".",$hostname);
896 if (!(is_array($multipoint)) || ((count($multipoint) - 1) < 1)) {
906 * human_readable_bytes() - Translates an integer representing bytes to a human-readable format.
908 * Format file size in a human-readable way
909 * such as "xx Megabytes" or "xx Mo"
911 * @author Andrea Paleni <andreaSPAMLESS_AT_SPAMLESScriticalbit.com>
913 * @param int bytes is the size
914 * @param bool base10 enable base 10 representation, otherwise
915 * default base 2 is used
916 * @param int round number of fractional digits
917 * @param array labels strings associated to each 2^10 or
918 * 10^3(base10==true) multiple of base units
920 function human_readable_bytes ($bytes, $base10=false, $round=0, $labels=array(' bytes', ' KB', ' MB', ' GB')) {
921 if ($bytes <= 0 || !is_array($labels) || (count($labels) <= 0)) {
924 $step = $base10 ? 3 : 10;
925 $base = $base10 ? 10 : 2;
926 $log = (int)(log10($bytes)/log10($base));
928 foreach ($labels as $p=>$lab) {
933 if ($lab == " MB" or $lab == " GB") {
936 $text = round($bytes/pow($base,$pow),$round).$lab;
943 * ls - lists a specified directory and returns an array of files
944 * @param string the path of the directory to list
945 * @param boolean whether to filter out directories and illegal filenames
946 * @return array array of file names.
948 function &ls($dir,$filter=false) {
951 if (is_dir($dir) && ($h = opendir($dir))) {
952 while (($f = readdir($h)) !== false) {
956 if (!util_is_valid_filename($f) ||
957 !is_file($dir . "/" . $f))
968 * readfile_chunked() - replacement for readfile
970 * @param string The file path
971 * @param bool Whether to return bytes served or just a bool
974 function readfile_chunked($filename, $returnBytes=true) {
975 $chunksize = 1*(1024*1024); // 1MB chunks
979 $handle = fopen($filename, 'rb');
980 if ($handle === false) {
985 while (!feof($handle)) {
986 $buffer = fread($handle, $chunksize);
991 $byteCounter += strlen($buffer);
995 $status = fclose($handle);
996 if ($returnBytes && $status) {
997 return $byteCounter; // return num. bytes delivered like readfile() does.
1003 * util_is_root_dir() - Checks if a directory points to the root dir
1004 * @param string Directory
1007 function util_is_root_dir($dir) {
1008 return !preg_match('/[^\\/]/',$dir);
1012 * util_is_dot_or_dotdot() - Checks if a directory points to . or ..
1013 * @param string Directory
1016 function util_is_dot_or_dotdot($dir) {
1017 return preg_match('/^\.\.?$/',trim($dir, '/'));
1021 * util_containts_dot_or_dotdot() - Checks if a directory containts . or ..
1022 * @param string Directory
1025 function util_containts_dot_or_dotdot($dir) {
1026 foreach (explode('/', $dir) as $sub_dir) {
1027 if (util_is_dot_or_dotdot($sub_dir))
1035 * util_secure_filename() - Returns a secured file name
1036 * @param string Filename
1037 * @return string Filename
1039 function util_secure_filename($file) {
1040 $f = preg_replace("/[^-A-Z0-9_\.]/i", '', $file);
1041 if (util_containts_dot_or_dotdot($f))
1042 $f = preg_replace("/\./", '_', $f);
1049 * util_strip_accents() - Remove accents from given text.
1050 * @param string Text
1053 function util_strip_accents($text) {
1054 return iconv ('UTF-8', 'US-ASCII//TRANSLIT', $text) ;
1058 * Constructs the forge's URL prefix out of forge_get_config('url_prefix')
1062 function normalized_urlprefix () {
1063 $prefix = forge_get_config('url_prefix') ;
1064 $prefix = preg_replace ("/^\//", "", $prefix) ;
1065 $prefix = preg_replace ("/\/$/", "", $prefix) ;
1066 $prefix = "/$prefix/" ;
1067 if ($prefix == '//')
1073 * Construct full URL from a relative path
1075 * @param string $path
1076 * @return string URL
1078 function util_make_url ($path) {
1079 if (forge_get_config('use_ssl')) {
1081 $url .= forge_get_config('web_host') ;
1082 if (forge_get_config('https_port') != 443) {
1083 $url .= ":".forge_get_config('https_port') ;
1087 $url .= forge_get_config('web_host') ;
1088 if (forge_get_config('http_port') != 80) {
1089 $url .= ":".forge_get_config('http_port') ;
1092 $url .= util_make_uri ($path) ;
1097 * Construct proper (relative) URI (prepending prefix)
1099 * @param string $path
1100 * @return string URI
1102 function util_make_uri ($path) {
1103 $path = preg_replace ('/^\//', '', $path) ;
1104 $uri = normalized_urlprefix () ;
1109 function util_make_link ($path, $text, $extra_params=false, $absolute=false) {
1111 if (is_array($extra_params)) {
1112 foreach ($extra_params as $key => $value) {
1113 $ep .= "$key=\"$value\" ";
1117 return '<a ' . $ep . 'href="' . $path . '">' . $text . '</a>' ;
1119 return '<a ' . $ep . 'href="' . util_make_uri($path) . '">' . $text . '</a>' ;
1124 * Create an HTML link to a user's profile page
1126 * @param string $username
1127 * @param int $user_id
1128 * @param string $text
1131 function util_make_link_u ($username, $user_id,$text) {
1132 return '<a href="' . util_make_url_u ($username, $user_id) . '">' . $text . '</a>' ;
1136 * Display username with link to a user's profile page
1137 * and icon face if possible.
1139 * @param string $username
1140 * @param int $user_id
1141 * @param string $text
1142 * @param string $size
1145 function util_display_user($username, $user_id,$text, $size='xs') {
1146 $hook_params = array();
1147 $hook_params['username'] = $username;
1148 $hook_params['user_id'] = $user_id;
1149 $hook_params['user_link'] = '';
1150 plugin_hook_by_reference("user_link_with_tooltip", $hook_params);
1151 if($hook_params['user_link'] != ''){
1152 return $hook_params['user_link'];
1155 $params = array('user_id' => $user_id, 'size' => $size, 'content' => '');
1156 plugin_hook_by_reference('user_logo', $params);
1157 $url = '<a href="' . util_make_url_u ($username, $user_id) . '">' . $text . '</a>';
1158 if ($params['content']) {
1159 return $params['content'].$url.'<div class="new_line"></div>';
1165 * Create URL for user's profile page
1167 * @param string $username
1168 * @param int $user_id
1169 * @return string URL
1171 function util_make_url_u ($username, $user_id) {
1172 if (isset ($GLOBALS['sys_noforcetype']) && $GLOBALS['sys_noforcetype']) {
1173 return util_make_url ("/developer/?user_id=$user_id");
1175 return util_make_url ("/users/$username/");
1180 * Create a HTML link to a project's page
1181 * @param string $groupame
1182 * @param int $group_id
1183 * @param string $text
1186 function util_make_link_g ($groupame, $group_id,$text) {
1187 return '<a href="' . util_make_url_g ($groupame, $group_id) . '">' . $text . '</a>' ;
1191 * Create URL for a project's page
1193 * @param string $groupame
1194 * @param int $group_id
1197 function util_make_url_g ($groupame, $group_id) {
1198 if (isset ($GLOBALS['sys_noforcetype']) && $GLOBALS['sys_noforcetype']) {
1199 return util_make_url ("/project/?group_id=$group_id");
1201 return util_make_url ("/projects/$groupame/");
1205 function util_ensure_value_in_set ($value, $set) {
1206 if (in_array ($value, $set)) {
1213 function check_email_available($group, $email, &$response) {
1214 // Check if a mailing list with same name already exists
1215 $mlFactory = new MailingListFactory($group);
1216 if (!$mlFactory || !is_object($mlFactory) || $mlFactory->isError()) {
1217 $response .= $mlFactory->getErrorMessage();
1220 $mlArray = $mlFactory->getMailingLists();
1221 if ($mlFactory->isError()) {
1222 $response .= $mlFactory->getErrorMessage();
1225 for ($j = 0; $j < count($mlArray); $j++) {
1226 $currentList =& $mlArray[$j];
1227 if ($email == $currentList->getName()) {
1228 $response .= _('Error: a mailing list with the same email address already exists.');
1233 // Check if a forum with same name already exists
1234 $ff = new ForumFactory($group);
1235 if (!$ff || !is_object($ff) || $ff->isError()) {
1236 $response .= $ff->getErrorMessage();
1239 $farr = $ff->getForums();
1240 $prefix = $group->getUnixName() . '-';
1241 for ($j = 0; $j < count($farr); $j++) {
1242 if (is_object($farr[$j])) {
1243 if ($email == $prefix . $farr[$j]->getName()) {
1244 $response .= _('Error: a forum with the same email address already exists.');
1250 // Email is available
1254 function use_javascript($js) {
1255 return $GLOBALS['HTML']->addJavascript($js);
1258 function use_stylesheet($css, $media='') {
1259 return $GLOBALS['HTML']->addStylesheet($css, $media);
1262 // array_replace_recursive only appeared in PHP 5.3.0
1263 if (!function_exists('array_replace_recursive')) {
1264 function array_replace_recursive ($a1, $a2) {
1267 if (!is_array ($a2)) {
1271 foreach ($a2 as $k => $v) {
1272 if (!is_array ($v) ||
1273 !isset ($result[$k]) || !is_array ($result[$k])) {
1277 $result[$k] = array_replace_recursive ($result[$k],
1285 // json_encode only appeared in PHP 5.2.0
1286 if (!function_exists('json_encode')) {
1287 require_once $gfcommon.'include/minijson.php' ;
1288 function json_encode ($a1) {
1289 return minijson_encode ($a1) ;
1293 /* returns an integer from http://forge/foo/bar.php/123 or false */
1294 function util_path_info_last_numeric_component() {
1295 if (!isset($_SERVER['PATH_INFO']))
1299 foreach (str_split($_SERVER['PATH_INFO']) as $x) {
1303 } else if ($ok == false) {
1304 ; /* need reset using slash */
1305 } else if ((ord($x) >= 48) && (ord($x) <= 57)) {
1306 $rv = $rv * 10 + ord($x) - 48;
1316 function get_cvs_binary_version () {
1317 $string = `cvs --version 2>/dev/null | grep ^Concurrent.Versions.System.*client/server` ;
1318 if (preg_match ('/^Concurrent Versions System .CVS. 1.11.[0-9]*/', $string)) {
1320 } elseif (preg_match ('/^Concurrent Versions System .CVS. 1.12.[0-9]*/', $string)) {
1327 /* get a backtrace as string */
1328 function debug_string_backtrace() {
1330 debug_print_backtrace();
1331 $trace = ob_get_contents();
1334 // Remove first item from backtrace as it's this function
1335 // which is redundant.
1336 $trace = preg_replace('/^#0\s+' . __FUNCTION__ . "[^\n]*\n/", '',
1339 // Renumber backtrace items.
1340 $trace = preg_replace('/^#(\d+)/me', '\'#\' . ($1 - 1)', $trace);
1345 function util_ini_get_bytes($id) {
1346 $val = trim(ini_get($id));
1347 $last = strtolower($val[strlen($val)-1]);
1359 function util_get_maxuploadfilesize() {
1360 $postmax = util_ini_get_bytes('post_max_size');
1361 $maxfile = util_ini_get_bytes('upload_max_filesize');
1363 $postfile = (int)(($postmax * 3) / 4);
1365 if ($postfile < $maxfile)
1366 $postfile = $maxfile;
1371 function util_randbytes($num=6) {
1372 $f = fopen("/dev/urandom", "rb");
1373 $b = fread($f, $num);
1376 if (strlen($b) != $num)
1377 exit_error(_('Internal Error'),
1378 _('Could not read from random device'));
1383 /* maximum: 2^31 - 1 due to PHP weakness */
1384 function util_randnum($min=0,$max=32767) {
1385 $ta = unpack("L", util_randbytes(4));
1386 $n = $ta[1] & 0x7FFFFFFF;
1387 $v = $n % (1 + $max - $min);
1391 // sys_get_temp_dir() is only available for PHP >= 5.2.1
1392 if ( !function_exists('sys_get_temp_dir')) {
1393 function sys_get_temp_dir() {
1394 if ($temp=getenv('TMP')) return $temp;
1395 if ($temp=getenv('TEMP')) return $temp;
1396 if ($temp=getenv('TMPDIR')) return $temp;
1403 // c-file-style: "bsd"