[0004212] Work Order Entry: fixed error when voided WO refence is reused.
[fa-stable.git] / includes / main.inc
1 <?php
2 /**********************************************************************
3     Copyright (C) FrontAccounting, LLC.
4         Released under the terms of the GNU General Public License, GPL, 
5         as published by the Free Software Foundation, either version 3 
6         of the License, or (at your option) any later version.
7     This program is distributed in the hope that it will be useful,
8     but WITHOUT ANY WARRANTY; without even the implied warranty of
9     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
10     See the License here <http://www.gnu.org/licenses/gpl-3.0.html>.
11 ***********************************************************************/
12 include_once($path_to_root . "/includes/db/connect_db.inc");
13
14 include_once($path_to_root . "/admin/db/transactions_db.inc");
15 include_once($path_to_root . "/includes/types.inc");
16 include_once($path_to_root . "/includes/references.inc");
17 include_once($path_to_root . "/includes/db/comments_db.inc");
18 include_once($path_to_root . "/includes/db/sql_functions.inc");
19 include_once($path_to_root . "/includes/db/audit_trail_db.inc");
20
21 include_once($path_to_root . "/admin/db/users_db.inc");
22 include_once($path_to_root . "/includes/ui/ui_view.inc");
23 include_once($path_to_root . "/includes/ui/ui_controls.inc");
24
25 $page_nested = -1;
26 // static js files path
27 $js_path = $path_to_root.'/js/';
28 // standard external js scripts included in all files
29 $js_static = array('JsHttpRequest.js', 'behaviour.js', 'utils.js', 'inserts.js');
30 // additional js source included in header
31 $js_lib = $js_userlib = array();
32
33 function page($title, $no_menu=false, $is_index=false, $onload="", $js="", $script_only=false, $css='')
34 {
35
36         global $path_to_root, $page_security, $page_nested;
37
38         if (++$page_nested) return;
39
40         $hide_menu = $no_menu;
41
42         include_once($path_to_root . "/includes/page/header.inc");
43
44         page_header($title, $no_menu, $is_index, $onload, $js, $css);
45         check_page_security($page_security);
46 //      error_box();
47         if($script_only) {
48                 echo '<noscript>';
49                 echo display_heading(_('This page is usable only with javascript enabled browsers.'));
50                 echo '</noscript>';
51                 div_start('_page_body', null, true);
52         } else {
53                 div_start('_page_body'); // whole page content for ajax reloading
54         }
55 }
56
57 function end_page($no_menu=false, $is_index=false, $final_screen=false, $type_no=0, $trans_no=0)
58 {
59         global $path_to_root, $page_nested;
60
61         if ($page_nested-- > 0) return;
62
63         if (!$is_index && function_exists('hyperlink_back'))
64                 hyperlink_back(true, $no_menu, $type_no, $trans_no, $final_screen);
65         div_end();      // end of _page_body section
66
67         include_once($path_to_root . "/includes/page/footer.inc");
68         page_footer($no_menu, $is_index);
69 }
70
71 function css_files_ensure_init() {
72         global $css_files, $path_to_root;
73
74         if (!isset($css_files))
75         {
76                 $theme = user_theme();
77                 $css_files = array();
78                 $css_files[] = $path_to_root . "/themes/$theme/default.css";
79         }
80 }
81
82 function add_css_file($filename)
83 {
84         global $css_files;
85         css_files_ensure_init();
86         $css_files[] = $filename;
87 }
88
89 function cache_js_file($fpath, $text) 
90 {
91         global $SysPrefs;
92
93         if (!$SysPrefs->go_debug) $text = js_compress($text);
94
95     $file = force_open($fpath);
96         if (!$file) return false;
97         if (!fwrite($file, $text)) return false;
98         return fclose($file);
99
100 }
101
102 /*
103         Open file for writing with creration of subfolders if needed.
104 */
105 function force_open($fname)
106 {
107         $file = pathinfo($fname);
108
109         $path = $fname[0] == '/' ? '/' : '';
110         $tree = explode('/', $file['dirname']);
111         foreach($tree as $level) {
112                 $path .= $level;
113                 if (!file_exists($path)) {
114                         if (!mkdir($path)) {
115                                 return null;
116                         }
117                 }
118                 $path .= '/';
119         }
120         return fopen($fname, 'w');
121 }
122
123 function add_js_file($filename) 
124 {
125           global $js_static;
126
127           $search = array_search($filename, $js_static);
128           if ($search === false || $search === null) // php>4.2.0 returns null
129                 $js_static[] = $filename;       
130 }
131
132 function add_js_ufile($filename) 
133 {
134           global $js_userlib;
135
136           $search = array_search($filename, $js_userlib);
137           if ($search === false || $search === null) // php>4.2.0 returns null
138                 $js_userlib[] = $filename;
139 }
140
141 function add_js_source($text) 
142 {
143           global $js_lib;
144
145           $search = array_search($text, $js_lib);
146           if ($search === false || $search === null) // php>4.2.0 returns null
147                 $js_lib[] = $text;
148 }
149
150 /**
151  * Compresses the Javascript code for more efficient delivery.
152  * copyright (c) 2005 by Jared White & J. Max Wilson
153  * http://www.xajaxproject.org
154  * Added removing comments from output.
155  * Warning: Fails on RegExp with quotes - use new RegExp() in this case.
156  */
157 function js_compress($sJS)
158 {
159         //remove windows cariage returns
160         $sJS = str_replace("\r","",$sJS);
161         
162         //array to store replaced literal strings
163         $literal_strings = array();
164         
165         //explode the string into lines
166         $lines = explode("\n",$sJS);
167         //loop through all the lines, building a new string at the same time as removing literal strings
168         $clean = "";
169         $inComment = false;
170         $literal = "";
171         $inQuote = false;
172         $escaped = false;
173         $quoteChar = "";
174         
175         for($i=0;$i<count($lines);$i++)
176         {
177                 $line = $lines[$i];
178                 $inNormalComment = false;
179         
180                 //loop through line's characters and take out any literal strings, replace them with ___i___ where i is the index of this string
181                 $len = strlen($line);
182                 for($j=0;$j<$len;$j++)
183                 {
184                         $c = $line[$j];         // this is _really_ faster than subst
185                         $d = $c.$line[$j+1];
186         
187                         //look for start of quote
188                         if(!$inQuote && !$inComment)
189                         {
190                                 //is this character a quote or a comment
191                                 if(($c=="\"" || $c=="'") && !$inComment && !$inNormalComment)
192                                 {
193                                         $inQuote = true;
194                                         $inComment = false;
195                                         $escaped = false;
196                                         $quoteChar = $c;
197                                         $literal = $c;
198                                 }
199                                 else if($d=="/*" && !$inNormalComment)
200                                 {
201                                         $inQuote = false;
202                                         $inComment = true;
203                                         $escaped = false;
204                                         $quoteChar = $d;
205                                         $literal = $d;  
206                                         $j++;   
207                                 }
208                                 else if($d=="//") //ignore string markers that are found inside comments
209                                 {
210                                         $inNormalComment = true;
211                                         $clean .= $c;
212                                 }
213                                 else
214                                 {
215                                         $clean .= $c;
216                                 }
217                         }
218                         else //allready in a string so find end quote
219                         {
220                                 if($c == $quoteChar && !$escaped && !$inComment)
221                                 {
222                                         $inQuote = false;
223                                         $literal .= $c;
224         
225                                         //subsitute in a marker for the string
226                                         $clean .= "___" . count($literal_strings) . "___";
227         
228                                         //push the string onto our array
229                                         array_push($literal_strings,$literal);
230         
231                                 }
232                                 else if($inComment && $d=="*/")
233                                 {
234                                         $inComment = false;
235                                         $literal .= $d;
236         
237                                         //subsitute in a marker for the string
238                                         $clean .= "___" . count($literal_strings) . "___";
239         
240                                         //push the string onto our array
241                                         array_push($literal_strings,$literal);
242         
243                                         $j++;
244                                 }
245                                 else if($c == "\\" && !$escaped)
246                                         $escaped = true;
247                                 else
248                                         $escaped = false;
249         
250                                 $literal .= $c;
251                         }
252                 }
253                 if($inComment) $literal .= "\n";
254                 $clean .= "\n";
255         }
256         //explode the clean string into lines again
257         $lines = explode("\n",$clean);
258         
259         //now process each line at a time
260         for($i=0;$i<count($lines);$i++)
261         {
262                 $line = $lines[$i];
263         
264                 //remove comments
265                 $line = preg_replace("/\/\/(.*)/","",$line);
266         
267                 //strip leading and trailing whitespace
268                 $line = trim($line);
269         
270                 //remove all whitespace with a single space
271                 $line = preg_replace("/\s+/"," ",$line);
272         
273                 //remove any whitespace that occurs after/before an operator
274                 $line = preg_replace("/\s*([!\}\{;,&=\|\-\+\*\/\)\(:])\s*/","\\1",$line);
275         
276                 $lines[$i] = $line;
277         }
278         
279         //implode the lines
280         $sJS = implode("\n",$lines);
281         
282         //make sure there is a max of 1 \n after each line
283         $sJS = preg_replace("/[\n]+/","\n",$sJS);
284         
285         //strip out line breaks that immediately follow a semi-colon
286         $sJS = preg_replace("/;\n/",";",$sJS);
287         
288         //curly brackets aren't on their own
289         $sJS = preg_replace("/[\n]*\{[\n]*/","{",$sJS);
290         
291         //finally loop through and replace all the literal strings:
292         for($i=0;$i<count($literal_strings);$i++) {
293             if (strpos($literal_strings[$i],"/*")!==false) 
294                 $literal_strings[$i]= '';
295                 $sJS = str_replace("___".$i."___",$literal_strings[$i],$sJS);
296         }
297         return $sJS;
298 }
299
300 /*
301         Check if file can be updated, restoring subdirectories 
302         if needed. Returns 1 when no confilcts, -1 when file exists and is writable
303 */
304 function check_write($path)
305 {
306         if ($path == ''//|| $path == '.' || $path == '..'
307         ) return 0;
308
309         return is_writable($path) ? (is_dir($path) ? 1 : -1) 
310                 : (is_file($path) ? 0 : ($path == '.' || $path == '..' ? 0 : check_write(dirname($path))));
311 }
312
313 /*
314         Copies set of files. When $strict is set
315         also removes files from the $to which 
316         does not exists in $from directory but arelisted in $flist.
317 */
318 function copy_files($flist, $from, $to, $strict=false)
319 {
320         foreach ($flist as $file) {
321                 if (file_exists($from.'/'.$file)) {
322                         if (!copy_file($file, $from, $to))
323                                 return false;
324                 } else if ($strict) {
325                                 unlink($to.'/'.$file);
326                 }
327         }
328         return true;
329 }
330
331 /*
332         Copies file from base to target directory, restoring subdirectories 
333         if needed.
334 */
335 function copy_file($file, $from, $to)
336 {
337
338         if (!is_dir(dirname($file=='.' ? $to : ($to.'/'.$file)))) {
339                 if (!copy_file(dirname($file), null, $to))
340                         return false;
341         }
342         if (!$from) {
343         //              error_log( 'dodanie katalogu '.$to.'/'.$file);
344                 return @mkdir($file=='.' ? $to : ($to.'/'.$file));
345         }
346         else {
347         //              error_log( 'skopiowanie '.$to.'/'.$file);
348                 return @copy($from.'/'.$file, $to.'/'.$file);
349         }
350 }
351 /*
352         Search for file, looking first for company specific version, then for 
353         version provided by any extension module, finally in main FA directory.
354         Also adds include path for any related files, and sets $local_path_to_root 
355         to enable local translation domains.
356         
357         Returns found file path or null.
358 */
359 function find_custom_file($rep)
360 {
361         global $installed_extensions, $path_to_root, $local_path_to_root;
362
363         // customized per company version
364         $path = company_path();
365         $file = $path.$rep;
366         if (file_exists($file)) {
367                 // add local include path
368                 $local_path_to_root = $path;
369                 set_include_path(dirname($file).PATH_SEPARATOR.get_include_path());
370                 return $file;
371         }
372         // file added by active extension modules
373         if (count($installed_extensions) > 0)
374         {
375                 $extensions = $installed_extensions;
376                 foreach ($extensions as $ext)
377                         if (($ext['active'] && $ext['type'] == 'extension')) {
378                                 $path = $path_to_root.'/'.$ext['path'];
379                                 $file = $path.$rep;
380                                 if (file_exists($file)) {
381                                         set_include_path($path.PATH_SEPARATOR.get_include_path());
382                                         $local_path_to_root = $path;
383                                         return $file;
384                                 }
385                         }
386         }
387         // standard location
388         $file = $path_to_root.$rep;
389         if (file_exists($file))
390                 return $file;
391
392         return null;
393 }
394 /*
395         
396         Protect against directory traversal.
397         Changes all not POSIX compatible chars to underscore.
398 */
399 function clean_file_name($filename) {
400     $filename = str_replace(chr(0), '', $filename);
401     return preg_replace('/[^a-zA-Z0-9.\-_]/', '_', $filename);
402 }
403
404 /*
405         Simple random password generator.
406 */
407 function generate_password()
408 {
409         if (PHP_VERSION >= '5.3')
410                 $bytes = openssl_random_pseudo_bytes(8, $cstrong);
411         else
412                 $bytes = sprintf("08%x", mt_rand(0,0xffffffff));
413
414         return  base64_encode($bytes);
415 }
416
417 if (!function_exists('array_fill_keys')) // since 5.2
418 {
419         function array_fill_keys($keys, $value)
420         {
421                 return (object)array_combine($keys, array_fill(count($keys), $value));
422         }
423 }
424
425 /*
426         This function aims to generate cryptographically strong random identifier.
427         Result identifier has length 4[strength/8/3] 
428 */
429 function random_id($strength = 128)
430 {
431         $n = ceil($strength/8);
432
433         if (function_exists('openssl_random_pseudo_bytes'))
434                 $bin = openssl_random_pseudo_bytes($n, $cstrong);       // openssl on php 5.3 and up
435         else if (file_exists('/dev/urandom'))
436                 $bin = file_get_contents('/dev/urandom', false, null, -1, $n);  // linux std random device
437         else {
438                 $bin = '';
439                 for($i=0; $i < $n; $i++)
440                         $bin .= chr(mt_rand(0, 255));   // Mersene Twister generator
441         }
442         $id = strtr(base64_encode($bin), '+/=', '-_x'); // see RFC 4648 Section 5
443
444         return $id;
445 }