Passed
Push — master ( 65bdac...4e88da )
by Alxarafe
32:38
created

DolUtils2::get_next_value()   F

Complexity

Conditions 112
Paths > 20000

Size

Total Lines 454
Code Lines 271

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 112
eloc 271
nc 4147440
nop 11
dl 0
loc 454
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
/* Copyright (C) 2008-2011  Laurent Destailleur         <[email protected]>
3
 * Copyright (C) 2008-2012  Regis Houssin               <[email protected]>
4
 * Copyright (C) 2008       Raphael Bertrand (Resultic) <[email protected]>
5
 * Copyright (C) 2014-2016  Marcos García               <[email protected]>
6
 * Copyright (C) 2015       Ferran Marcet               <[email protected]>
7
 * Copyright (C) 2015-2016  Raphaël Doursenaud          <[email protected]>
8
 * Copyright (C) 2017       Juanjo Menent               <[email protected]>
9
 *
10
 * This program is free software; you can redistribute it and/or modify
11
 * it under the terms of the GNU General Public License as published by
12
 * the Free Software Foundation; either version 3 of the License, or
13
 * (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 * GNU General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU General Public License
21
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22
 * or see http://www.gnu.org/
23
 */
24
namespace Alixar\Helpers;
25
26
/**
27
 *	\file			htdocs/core/lib/functions2.lib.php
28
 *	\brief			A set of functions for Dolibarr
29
 *					This file contains all rare functions.
30
 */
31
32
// Enable this line to trace path when function is called.
33
//print xdebug_print_function_stack('Functions2.lib was called');exit;
34
35
class DolUtils2
36
{
37
38
    /**
39
 * Same function than javascript unescape() function but in PHP.
40
 *
41
 * @param 	string	$source		String to decode
42
 * @return	string				Unescaped string
43
 */
44
function jsUnEscape($source)
45
{
46
    $decodedStr = "";
47
    $pos = 0;
48
    $len = strlen($source);
49
    while ($pos < $len) {
50
        $charAt = substr($source, $pos, 1);
51
        if ($charAt == '%') {
52
            $pos++;
53
            $charAt = substr($source, $pos, 1);
54
            if ($charAt == 'u') {
55
                // we got a unicode character
56
                $pos++;
57
                $unicodeHexVal = substr($source, $pos, 4);
58
                $unicode = hexdec($unicodeHexVal);
59
                $entity = "&#". $unicode . ';';
60
                $decodedStr .= utf8_encode($entity);
61
                $pos += 4;
62
            }
63
            else {
64
                // we have an escaped ascii character
65
                $hexVal = substr($source, $pos, 2);
66
                $decodedStr .= chr(hexdec($hexVal));
67
                $pos += 2;
68
            }
69
        } else {
70
            $decodedStr .= $charAt;
71
            $pos++;
72
        }
73
    }
74
    return dol_html_entity_decode($decodedStr, ENT_COMPAT);
75
}
76
77
78
/**
79
 * Return list of modules directories. We detect directories that contains a subdirectory /core/modules
80
 * We discard directory modules that contains 'disabled' into their name.
81
 *
82
 * @param	string	$subdir		Sub directory (Example: '/mailings')
83
 * @return	array				Array of directories that can contains module descriptors
84
 */
85
function dolGetModulesDirs($subdir='')
86
{
87
    global $conf;
88
89
    $modulesdir=array();
90
91
    foreach ($conf->file->dol_document_root as $type => $dirroot)
92
    {
93
        // Default core/modules dir
94
        if ($type === 'main') {
95
            $modulesdir[$dirroot . '/core/modules' . $subdir . '/'] = $dirroot . '/core/modules' . $subdir . '/';
96
        }
97
98
        // Scan dir from external modules
99
        $handle=@opendir($dirroot);
100
        if (is_resource($handle))
101
        {
102
            while (($file = readdir($handle))!==false)
103
            {
104
                if (preg_match('/disabled/',$file)) continue;   // We discard module if it contains disabled into name.
105
106
                if (is_dir($dirroot.'/'.$file) && substr($file, 0, 1) <> '.' && substr($file, 0, 3) <> 'CVS' && $file != 'includes')
107
                {
108
                    if (is_dir($dirroot . '/' . $file . '/core/modules'.$subdir.'/'))
109
                    {
110
                        $modulesdir[$dirroot . '/' . $file . '/core/modules'.$subdir.'/'] = $dirroot . '/' . $file . '/core/modules'.$subdir.'/';
111
                    }
112
                }
113
            }
114
            closedir($handle);
115
        }
116
    }
117
    return $modulesdir;
118
}
119
120
121
/**
122
 *  Try to guess default paper format according to language into $langs
123
 *
124
 *	@param		Translate	$outputlangs		Output lang to use to autodetect output format if setup not done
125
 *	@return		string							Default paper format code
126
 */
127
function dol_getDefaultFormat(Translate $outputlangs = null)
0 ignored issues
show
Bug introduced by
The type Alixar\Helpers\Translate was not found. Did you mean Translate? If so, make sure to prefix the type with \.
Loading history...
128
{
129
    global $langs;
130
131
    $selected='EUA4';
132
    if (!$outputlangs) {
133
    	$outputlangs=$langs;
134
    }
135
136
    if ($outputlangs->defaultlang == 'ca_CA') $selected='CAP4';        // Canada
137
    if ($outputlangs->defaultlang == 'en_US') $selected='USLetter';    // US
138
    return $selected;
139
}
140
141
/**
142
 *  Output content of a file $filename in version of current language (otherwise may use an alternate language)
143
 *
144
 *  @param	Translate	$langs          Object language to use for output
145
 *  @param  string		$filename       Relative filename to output
146
 *  @param  int			$searchalt      1=Search also in alternative languages
147
 *	@return	boolean						true if OK, false if KO
148
 */
149
function dol_print_file($langs,$filename,$searchalt=0)
150
{
151
    global $conf;
152
153
    // Test if file is in lang directory
154
    foreach($langs->dir as $searchdir)
155
    {
156
        $formfile=($searchdir."/langs/".$langs->defaultlang."/".$filename);
157
        dol_syslog('functions2::dol_print_file search file '.$formfile, LOG_DEBUG);
158
        if (is_readable($formfile))
159
        {
160
            $content=file_get_contents($formfile);
161
            $isutf8=utf8_check($content);
162
            if (! $isutf8 && $conf->file->character_set_client == 'UTF-8') print utf8_encode($content);
163
            elseif ($isutf8 && $conf->file->character_set_client == 'ISO-8859-1') print utf8_decode($content);
164
            else print $content;
165
            return true;
166
        }
167
        else dol_syslog('functions2::dol_print_file not found', LOG_DEBUG);
168
169
        if ($searchalt) {
170
            // Test si fichier dans repertoire de la langue alternative
171
            if ($langs->defaultlang != "en_US") $formfilealt = $searchdir."/langs/en_US/".$filename;
172
            else $formfilealt = $searchdir."/langs/fr_FR/".$filename;
173
            dol_syslog('functions2::dol_print_file search alt file '.$formfilealt, LOG_DEBUG);
174
            //print 'getcwd='.getcwd().' htmlfilealt='.$formfilealt.' X '.file_exists(getcwd().'/'.$formfilealt);
175
            if (is_readable($formfilealt))
176
            {
177
                $content=file_get_contents($formfilealt);
178
                $isutf8=utf8_check($content);
179
                if (! $isutf8 && $conf->file->character_set_client == 'UTF-8') print utf8_encode($content);
180
                elseif ($isutf8 && $conf->file->character_set_client == 'ISO-8859-1') print utf8_decode($content);
181
                else print $content;
182
                return true;
183
            }
184
            else dol_syslog('functions2::dol_print_file not found', LOG_DEBUG);
185
        }
186
    }
187
188
    return false;
189
}
190
191
/**
192
 *	Show informations on an object
193
 *  TODO Move this into html.formother
194
 *
195
 *	@param	object	$object			Objet to show
196
 *  @param  int     $usetable       Output into a table
197
 *	@return	void
198
 */
199
function dol_print_object_info($object, $usetable=0)
200
{
201
    global $langs, $db;
202
203
    // Load translation files required by the page
204
    $langs->loadLangs(array('other', 'admin'));
205
206
    include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
207
208
    $deltadateforserver=getServerTimeZoneInt('now');
209
    $deltadateforclient=((int) $_SESSION['dol_tz'] + (int) $_SESSION['dol_dst']);
210
    //$deltadateforcompany=((int) $_SESSION['dol_tz'] + (int) $_SESSION['dol_dst']);
211
    $deltadateforuser=round($deltadateforclient-$deltadateforserver);
212
    //print "x".$deltadateforserver." - ".$deltadateforclient." - ".$deltadateforuser;
213
214
    if ($usetable) print '<table class="border centpercent">';
215
216
    // Import key
217
    if (! empty($object->import_key))
218
    {
219
        if ($usetable) print '<tr><td class="titlefield">';
220
        print $langs->trans("ImportedWithSet");
221
        if ($usetable) print '</td><td>';
222
        else print ': ';
223
        print $object->import_key;
224
        if ($usetable) print '</td></tr>';
225
        else print '<br>';
226
    }
227
228
    // User creation (old method using already loaded object and not id is kept for backward compatibility)
229
    if (! empty($object->user_creation) || ! empty($object->user_creation_id))
230
    {
231
        if ($usetable) print '<tr><td class="titlefield">';
232
        print $langs->trans("CreatedBy");
233
        if ($usetable) print '</td><td>';
234
        else print ': ';
235
        if (is_object($object->user_creation))
236
        {
237
        	if ($object->user_creation->id) print $object->user_creation->getNomUrl(1, '', 0, 0, 0);
238
        	else print $langs->trans("Unknown");
239
        }
240
        else
241
        {
242
            $userstatic=new User($db);
0 ignored issues
show
Bug introduced by
The type Alixar\Helpers\User was not found. Did you mean User? If so, make sure to prefix the type with \.
Loading history...
243
            $userstatic->fetch($object->user_creation_id ? $object->user_creation_id : $object->user_creation);
244
            if ($userstatic->id) print $userstatic->getNomUrl(1, '', 0, 0, 0);
245
        	else print $langs->trans("Unknown");
246
        }
247
        if ($usetable) print '</td></tr>';
248
        else print '<br>';
249
    }
250
251
    // Date creation
252
    if (! empty($object->date_creation))
253
    {
254
        if ($usetable) print '<tr><td class="titlefield">';
255
        print $langs->trans("DateCreation");
256
        if ($usetable) print '</td><td>';
257
        else print ': ';
258
        print dol_print_date($object->date_creation, 'dayhour');
259
        if ($deltadateforuser) print ' '.$langs->trans("CurrentHour").' &nbsp; / &nbsp; '.dol_print_date($object->date_creation+($deltadateforuser*3600),"dayhour").' &nbsp;'.$langs->trans("ClientHour");
260
        if ($usetable) print '</td></tr>';
261
        else print '<br>';
262
    }
263
264
    // User change (old method using already loaded object and not id is kept for backward compatibility)
265
    if (! empty($object->user_modification) || ! empty($object->user_modification_id))
266
    {
267
        if ($usetable) print '<tr><td class="titlefield">';
268
        print $langs->trans("ModifiedBy");
269
        if ($usetable) print '</td><td>';
270
        else print ': ';
271
        if (is_object($object->user_modification))
272
        {
273
        	if ($object->user_modification->id) print $object->user_modification->getNomUrl(1, '', 0, 0, 0);
274
        	else print $langs->trans("Unknown");
275
        }
276
        else
277
        {
278
            $userstatic=new User($db);
279
            $userstatic->fetch($object->user_modification_id ? $object->user_modification_id : $object->user_modification);
280
            if ($userstatic->id) print $userstatic->getNomUrl(1, '', 0, 0, 0);
281
        	else print $langs->trans("Unknown");
282
        }
283
        if ($usetable) print '</td></tr>';
284
        else print '<br>';
285
    }
286
287
    // Date change
288
    if (! empty($object->date_modification))
289
    {
290
        if ($usetable) print '<tr><td class="titlefield">';
291
        print $langs->trans("DateLastModification");
292
        if ($usetable) print '</td><td>';
293
        else print ': ';
294
        print dol_print_date($object->date_modification, 'dayhour');
295
        if ($deltadateforuser) print ' '.$langs->trans("CurrentHour").' &nbsp; / &nbsp; '.dol_print_date($object->date_modification+($deltadateforuser*3600),"dayhour").' &nbsp;'.$langs->trans("ClientHour");
296
        if ($usetable) print '</td></tr>';
297
        else print '<br>';
298
    }
299
300
    // User validation (old method using already loaded object and not id is kept for backward compatibility)
301
    if (! empty($object->user_validation) || ! empty($object->user_validation_id))
302
    {
303
        if ($usetable) print '<tr><td class="titlefield">';
304
        print $langs->trans("ValidatedBy");
305
        if ($usetable) print '</td><td>';
306
        else print ': ';
307
        if (is_object($object->user_validation))
308
        {
309
            if ($object->user_validation->id) print $object->user_validation->getNomUrl(1, '', 0, 0, 0);
310
        	else print $langs->trans("Unknown");
311
        }
312
        else
313
        {
314
            $userstatic=new User($db);
315
            $userstatic->fetch($object->user_validation_id ? $object->user_validation_id : $object->user_validation);
316
			if ($userstatic->id) print $userstatic->getNomUrl(1, '', 0, 0, 0);
317
        	else print $langs->trans("Unknown");
318
        }
319
        if ($usetable) print '</td></tr>';
320
        else print '<br>';
321
    }
322
323
    // Date validation
324
    if (! empty($object->date_validation))
325
    {
326
        if ($usetable) print '<tr><td class="titlefield">';
327
        print $langs->trans("DateValidation");
328
        if ($usetable) print '</td><td>';
329
        else print ': ';
330
        print dol_print_date($object->date_validation, 'dayhour');
331
        if ($deltadateforuser) print ' '.$langs->trans("CurrentHour").' &nbsp; / &nbsp; '.dol_print_date($object->date_validation+($deltadateforuser*3600),"dayhour").' &nbsp;'.$langs->trans("ClientHour");
332
        if ($usetable) print '</td></tr>';
333
        else print '<br>';
334
    }
335
336
    // User approve (old method using already loaded object and not id is kept for backward compatibility)
337
    if (! empty($object->user_approve) || ! empty($object->user_approve_id))
338
    {
339
        if ($usetable) print '<tr><td class="titlefield">';
340
        print $langs->trans("ApprovedBy");
341
        if ($usetable) print '</td><td>';
342
        else print ': ';
343
        if (is_object($object->user_approve))
344
        {
345
            if ($object->user_approve->id) print $object->user_approve->getNomUrl(1, '', 0, 0, 0);
346
        	else print $langs->trans("Unknown");
347
        }
348
        else
349
        {
350
            $userstatic=new User($db);
351
            $userstatic->fetch($object->user_approve_id ? $object->user_approve_id : $object->user_approve);
352
			if ($userstatic->id) print $userstatic->getNomUrl(1, '', 0, 0, 0);
353
        	else print $langs->trans("Unknown");
354
        }
355
        if ($usetable) print '</td></tr>';
356
        else print '<br>';
357
    }
358
359
    // Date approve
360
    if (! empty($object->date_approve))
361
    {
362
        if ($usetable) print '<tr><td class="titlefield">';
363
        print $langs->trans("DateApprove");
364
        if ($usetable) print '</td><td>';
365
        else print ': ';
366
        print dol_print_date($object->date_approve, 'dayhour');
367
        if ($deltadateforuser) print ' '.$langs->trans("CurrentHour").' &nbsp; / &nbsp; '.dol_print_date($object->date_approve+($deltadateforuser*3600),"dayhour").' &nbsp;'.$langs->trans("ClientHour");
368
        if ($usetable) print '</td></tr>';
369
        else print '<br>';
370
    }
371
372
    // User approve
373
    if (! empty($object->user_approve_id2))
374
    {
375
        if ($usetable) print '<tr><td class="titlefield">';
376
        print $langs->trans("ApprovedBy");
377
        if ($usetable) print '</td><td>';
378
        else print ': ';
379
        $userstatic=new User($db);
380
        $userstatic->fetch($object->user_approve_id2);
381
        if ($userstatic->id) print $userstatic->getNomUrl(1, '', 0, 0, 0);
382
        else print $langs->trans("Unknown");
383
        if ($usetable) print '</td></tr>';
384
        else print '<br>';
385
    }
386
387
    // Date approve
388
    if (! empty($object->date_approve2))
389
    {
390
        if ($usetable) print '<tr><td class="titlefield">';
391
        print $langs->trans("DateApprove2");
392
        if ($usetable) print '</td><td>';
393
        else print ': ';
394
        print dol_print_date($object->date_approve2, 'dayhour');
395
        if ($deltadateforuser) print ' '.$langs->trans("CurrentHour").' &nbsp; / &nbsp; '.dol_print_date($object->date_approve2+($deltadateforuser*3600),"dayhour").' &nbsp;'.$langs->trans("ClientHour");
396
        if ($usetable) print '</td></tr>';
397
        else print '<br>';
398
    }
399
400
    // User close
401
    if (! empty($object->user_cloture))
402
    {
403
        if ($usetable) print '<tr><td class="titlefield">';
404
        print $langs->trans("ClosedBy");
405
        if ($usetable) print '</td><td>';
406
        else print ': ';
407
        if (is_object($object->user_cloture))
408
        {
409
			if ($object->user_cloture->id) print $object->user_cloture->getNomUrl(1, '', 0, 0, 0);
410
        	else print $langs->trans("Unknown");
411
        }
412
        else
413
        {
414
            $userstatic=new User($db);
415
            $userstatic->fetch($object->user_cloture);
416
			if ($userstatic->id) print $userstatic->getNomUrl(1, '', 0, 0, 0);
417
        	else print $langs->trans("Unknown");
418
        }
419
        if ($usetable) print '</td></tr>';
420
        else print '<br>';
421
    }
422
423
    // Date close
424
    if (! empty($object->date_cloture))
425
    {
426
        if ($usetable) print '<tr><td class="titlefield">';
427
        print $langs->trans("DateClosing");
428
        if ($usetable) print '</td><td>';
429
        else print ': ';
430
        print dol_print_date($object->date_cloture, 'dayhour');
431
        if ($deltadateforuser) print ' '.$langs->trans("CurrentHour").' &nbsp; / &nbsp; '.dol_print_date($object->date_cloture+($deltadateforuser*3600),"dayhour").' &nbsp;'.$langs->trans("ClientHour");
432
        if ($usetable) print '</td></tr>';
433
        else print '<br>';
434
    }
435
436
    // User conciliate
437
    if (! empty($object->user_rappro))
438
    {
439
        if ($usetable) print '<tr><td class="titlefield">';
440
        print $langs->trans("ConciliatedBy");
441
        if ($usetable) print '</td><td>';
442
        else print ': ';
443
        if (is_object($object->user_rappro))
444
        {
445
			if ($object->user_rappro->id) print $object->user_rappro->getNomUrl(1, '', 0, 0, 0);
446
        	else print $langs->trans("Unknown");
447
        }
448
        else
449
        {
450
            $userstatic=new User($db);
451
            $userstatic->fetch($object->user_rappro);
452
			if ($userstatic->id) print $userstatic->getNomUrl(1, '', 0, 0, 0);
453
        	else print $langs->trans("Unknown");
454
        }
455
        if ($usetable) print '</td></tr>';
456
        else print '<br>';
457
    }
458
459
    // Date conciliate
460
    if (! empty($object->date_rappro))
461
    {
462
        if ($usetable) print '<tr><td class="titlefield">';
463
        print $langs->trans("DateConciliating");
464
        if ($usetable) print '</td><td>';
465
        else print ': ';
466
        print dol_print_date($object->date_rappro, 'dayhour');
467
        if ($deltadateforuser) print ' '.$langs->trans("CurrentHour").' &nbsp; / &nbsp; '.dol_print_date($object->date_rappro+($deltadateforuser*3600),"dayhour").' &nbsp;'.$langs->trans("ClientHour");
468
        if ($usetable) print '</td></tr>';
469
        else print '<br>';
470
    }
471
472
    // Date send
473
    if (! empty($object->date_envoi))
474
    {
475
        if ($usetable) print '<tr><td class="titlefield">';
476
        print $langs->trans("DateLastSend");
477
        if ($usetable) print '</td><td>';
478
        else print ': ';
479
        print dol_print_date($object->date_envoi, 'dayhour');
480
        if ($deltadateforuser) print ' '.$langs->trans("CurrentHour").' &nbsp; / &nbsp; '.dol_print_date($object->date_envoi+($deltadateforuser*3600),"dayhour").' &nbsp;'.$langs->trans("ClientHour");
481
        if ($usetable) print '</td></tr>';
482
        else print '<br>';
483
    }
484
485
    if ($usetable) print '</table>';
486
}
487
488
489
/**
490
 *	Return an email formatted to include a tracking id
491
 *  For example  [email protected] becom [email protected]
492
 *
493
 *	@param	string	$email       	Email address (Ex: "[email protected]", "John Do <[email protected]>")
494
 *	@param	string	$trackingid    	Tracking id (Ex: thi123 for thirdparty with id 123)
495
 *	@return string     			    Return email tracker string
496
 */
497
function dolAddEmailTrackId($email, $trackingid)
498
{
499
	$tmp=explode('@',$email);
500
	return $tmp[0].'+'.$trackingid.'@'.(isset($tmp[1])?$tmp[1]:'');
501
}
502
503
/**
504
 *	Return true if email has a domain name that can't be resolved
505
 *
506
 *	@param	string	$mail       Email address (Ex: "[email protected]", "John Do <[email protected]>")
507
 *	@return boolean     		True if domain email is OK, False if KO
508
 */
509
function isValidMailDomain($mail)
510
{
511
    list($user, $domain) = explode("@", $mail, 2);
512
    if (checkdnsrr($domain, "MX"))
513
    {
514
        return true;
515
    }
516
    else
517
    {
518
        return false;
519
    }
520
}
521
522
/**
523
 *	Url string validation
524
 *  <http[s]> :// [user[:pass]@] hostname [port] [/path] [?getquery] [anchor]
525
 *
526
 *	@param	string	$url		Url
527
 *  @param  int		$http		1: verify http is provided, 0: not verify http
528
 *  @param  int		$pass		1: verify user and pass is provided, 0: not verify user and pass
529
 *  @param  int		$port		1: verify port is provided, 0: not verify port
530
 *  @param  int		$path		1: verify a path is provided "/" or "/..." or "/.../", 0: not verify path
531
 *  @param  int		$query		1: verify query is provided, 0: not verify query
532
 *  @param  int		$anchor		1: verify anchor is provided, 0: not verify anchor
533
 *	@return int					1=Check is OK, 0=Check is KO
534
 */
535
function isValidUrl($url,$http=0,$pass=0,$port=0,$path=0,$query=0,$anchor=0)
536
{
537
    $ValidUrl = 0;
538
    $urlregex = '';
539
540
    // SCHEME
541
    if ($http) $urlregex .= "^(http:\/\/|https:\/\/)";
542
543
    // USER AND PASS
544
    if ($pass) $urlregex .= "([a-z0-9+!*(),;?&=\$_.-]+(\:[a-z0-9+!*(),;?&=\$_.-]+)?@)";
545
546
    // HOSTNAME OR IP
547
    //$urlregex .= "[a-z0-9+\$_-]+(\.[a-z0-9+\$_-]+)*";  // x allowed (ex. http://localhost, http://routerlogin)
548
    //$urlregex .= "[a-z0-9+\$_-]+(\.[a-z0-9+\$_-]+)+";  // x.x
549
    $urlregex .= "([a-z0-9+\$_\\\:-])+(\.[a-z0-9+\$_-][a-z0-9+\$_-]+)*";  // x ou x.xx (2 x ou plus)
550
    //use only one of the above
551
552
    // PORT
553
    if ($port) $urlregex .= "(\:[0-9]{2,5})";
554
    // PATH
555
    if ($path) $urlregex .= "(\/([a-z0-9+\$_-]\.?)+)*\/";
556
    // GET Query
557
    if ($query) $urlregex .= "(\?[a-z+&\$_.-][a-z0-9;:@\/&%=+\$_.-]*)";
558
    // ANCHOR
559
    if ($anchor) $urlregex .= "(#[a-z_.-][a-z0-9+\$_.-]*)$";
560
561
    // check
562
    if (preg_match('/'.$urlregex.'/i', $url))
563
    {
564
        $ValidUrl = 1;
565
    }
566
    //print $urlregex.' - '.$url.' - '.$ValidUrl;
567
568
    return $ValidUrl;
569
}
570
571
/**
572
 *	Clean an url string
573
 *
574
 *	@param	string	$url		Url
575
 *	@param  integer	$http		1 = keep both http:// and https://, 0: remove http:// but not https://
576
 *	@return string				Cleaned url
577
 */
578
function clean_url($url,$http=1)
579
{
580
    // Fixed by Matelli (see http://matelli.fr/showcases/patchs-dolibarr/fix-cleaning-url.html)
581
    // To include the minus sign in a char class, we must not escape it but put it at the end of the class
582
    // Also, there's no need of escape a dot sign in a class
583
    if (preg_match('/^(https?:[\\/]+)?([0-9A-Z.-]+\.[A-Z]{2,4})(:[0-9]+)?/i',$url,$regs))
584
    {
585
        $proto=$regs[1];
586
        $domain=$regs[2];
587
        $port=isset($regs[3])?$regs[3]:'';
588
        //print $url." -> ".$proto." - ".$domain." - ".$port;
589
        //$url = dol_string_nospecial(trim($url));
590
        $url = trim($url);
591
592
        // Si http: defini on supprime le http (Si https on ne supprime pas)
593
        $newproto=$proto;
594
        if ($http==0)
595
        {
596
            if (preg_match('/^http:[\\/]+/i',$url))
597
            {
598
                $url = preg_replace('/^http:[\\/]+/i','',$url);
599
                $newproto = '';
600
            }
601
        }
602
603
        // On passe le nom de domaine en minuscule
604
        $CleanUrl = preg_replace('/^'.preg_quote($proto.$domain,'/').'/i', $newproto.strtolower($domain), $url);
605
606
        return $CleanUrl;
607
    }
608
    else return $url;
609
}
610
611
612
613
/**
614
 * 	Returns an email value with obfuscated parts.
615
 *
616
 * 	@param 		string		$mail				Email
617
 * 	@param 		string		$replace			Replacement character (defaul: *)
618
 * 	@param 		int			$nbreplace			Number of replacement character (default: 8)
619
 * 	@param 		int			$nbdisplaymail		Number of character unchanged (default: 4)
620
 * 	@param 		int			$nbdisplaydomain	Number of character unchanged of domain (default: 3)
621
 * 	@param 		bool		$displaytld			Display tld (default: true)
622
 * 	@return		string							Return email with hidden parts or '';
623
 */
624
function dolObfuscateEmail($mail, $replace="*", $nbreplace=8, $nbdisplaymail=4, $nbdisplaydomain=3, $displaytld=true)
625
{
626
	if(!isValidEmail($mail))return '';
627
	$tab = explode('@', $mail);
628
	$tab2 = explode('.',$tab[1]);
629
	$string_replace = '';
630
	$mail_name = $tab[0];
631
	$mail_domaine = $tab2[0];
632
	$mail_tld = '';
633
634
	$nbofelem = count($tab2);
635
	for($i=1; $i < $nbofelem && $displaytld; $i++)
636
	{
637
		$mail_tld .= '.'.$tab2[$i];
638
	}
639
640
	for($i=0; $i < $nbreplace; $i++){
641
		$string_replace .= $replace;
642
	}
643
644
	if(strlen($mail_name) > $nbdisplaymail){
645
		$mail_name = substr($mail_name, 0, $nbdisplaymail);
646
	}
647
648
	if(strlen($mail_domaine) > $nbdisplaydomain){
649
		$mail_domaine = substr($mail_domaine, strlen($mail_domaine)-$nbdisplaydomain);
650
	}
651
652
	return $mail_name . $string_replace . $mail_domaine . $mail_tld;
653
}
654
655
656
/**
657
 * 	Return lines of an html table from an array
658
 * 	Used by array2table function only
659
 *
660
 * 	@param	array	$data		Array of data
661
 * 	@param	string	$troptions	Options for tr
662
 * 	@param	string	$tdoptions	Options for td
663
 * 	@return	string
664
 */
665
function array2tr($data,$troptions='',$tdoptions='')
666
{
667
    $text = '<tr '.$troptions.'>' ;
668
    foreach($data as $key => $item){
669
        $text.= '<td '.$tdoptions.'>'.$item.'</td>' ;
670
    }
671
    $text.= '</tr>' ;
672
    return $text ;
673
}
674
675
/**
676
 * 	Return an html table from an array
677
 *
678
 * 	@param	array	$data			Array of data
679
 * 	@param	int		$tableMarkup	Table markup
680
 * 	@param	string	$tableoptions	Options for table
681
 * 	@param	string	$troptions		Options for tr
682
 * 	@param	string	$tdoptions		Options for td
683
 * 	@return	string
684
 */
685
function array2table($data,$tableMarkup=1,$tableoptions='',$troptions='',$tdoptions='')
686
{
687
    $text='' ;
688
    if($tableMarkup) $text = '<table '.$tableoptions.'>' ;
689
    foreach($data as $key => $item){
690
        if(is_array($item)){
691
            $text.=array2tr($item,$troptions,$tdoptions);
692
        } else {
693
            $text.= '<tr '.$troptions.'>' ;
694
            $text.= '<td '.$tdoptions.'>'.$key.'</td>' ;
695
            $text.= '<td '.$tdoptions.'>'.$item.'</td>' ;
696
            $text.= '</tr>' ;
697
        }
698
    }
699
    if($tableMarkup) $text.= '</table>' ;
700
    return $text ;
701
}
702
703
/**
704
 * Return last or next value for a mask (according to area we should not reset)
705
 *
706
 * @param   DoliDB		$db				Database handler
0 ignored issues
show
Bug introduced by
The type Alixar\Helpers\DoliDB was not found. Did you mean DoliDB? If so, make sure to prefix the type with \.
Loading history...
707
 * @param   string		$mask			Mask to use
708
 * @param   string		$table			Table containing field with counter
709
 * @param   string		$field			Field containing already used values of counter
710
 * @param   string		$where			To add a filter on selection (for exemple to filter on invoice types)
711
 * @param   Societe		$objsoc			The company that own the object we need a counter for
0 ignored issues
show
Bug introduced by
The type Alixar\Helpers\Societe was not found. Did you mean Societe? If so, make sure to prefix the type with \.
Loading history...
712
 * @param   string		$date			Date to use for the {y},{m},{d} tags.
713
 * @param   string		$mode			'next' for next value or 'last' for last value
714
 * @param   bool		$bentityon		Activate the entity filter. Default is true (for modules not compatible with multicompany)
715
 * @param	User		$objuser		Object user we need data from.
716
 * @param	int			$forceentity	Entity id to force
717
 * @return 	string						New value (numeric) or error message
718
 */
719
function get_next_value($db,$mask,$table,$field,$where='',$objsoc='',$date='',$mode='next', $bentityon=true, $objuser=null, $forceentity=null)
720
{
721
    global $conf,$user;
722
723
    if (! is_object($objsoc)) $valueforccc=$objsoc;
724
    else if ($table == "commande_fournisseur" || $table == "facture_fourn" ) $valueforccc=$objsoc->code_fournisseur;
725
    else $valueforccc=$objsoc->code_client;
726
727
    $sharetable = $table;
728
    if ($table == 'facture' || $table == 'invoice') $sharetable = 'invoicenumber'; // for getEntity function
729
730
    // Clean parameters
731
    if ($date == '') $date=dol_now();	// We use local year and month of PHP server to search numbers
732
    // but we should use local year and month of user
733
734
    // For debugging
735
    //dol_syslog("mask=".$mask, LOG_DEBUG);
736
    //include_once(DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php');
737
    //$mask='FA{yy}{mm}-{0000@99}';
738
    //$date=dol_mktime(12, 0, 0, 1, 1, 1900);
739
    //$date=dol_stringtotime('20130101');
740
741
    $hasglobalcounter=false;
742
    // Extract value for mask counter, mask raz and mask offset
743
    if (preg_match('/\{(0+)([@\+][0-9\-\+\=]+)?([@\+][0-9\-\+\=]+)?\}/i',$mask,$reg))
744
    {
745
        $masktri=$reg[1].(! empty($reg[2])?$reg[2]:'').(! empty($reg[3])?$reg[3]:'');
746
        $maskcounter=$reg[1];
747
        $hasglobalcounter=true;
748
    }
749
    else
750
    {
751
        // setting some defaults so the rest of the code won't fail if there is a third party counter
752
        $masktri='00000';
753
        $maskcounter='00000';
754
    }
755
756
    $maskraz=-1;
757
    $maskoffset=0;
758
    $resetEveryMonth=false;
759
    if (dol_strlen($maskcounter) < 3 && empty($conf->global->MAIN_COUNTER_WITH_LESS_3_DIGITS)) return 'ErrorCounterMustHaveMoreThan3Digits';
760
761
    // Extract value for third party mask counter
762
    if (preg_match('/\{(c+)(0*)\}/i',$mask,$regClientRef))
763
    {
764
        $maskrefclient=$regClientRef[1].$regClientRef[2];
765
        $maskrefclient_maskclientcode=$regClientRef[1];
766
        $maskrefclient_maskcounter=$regClientRef[2];
767
        $maskrefclient_maskoffset=0; //default value of maskrefclient_counter offset
768
        $maskrefclient_clientcode=substr($valueforccc,0,dol_strlen($maskrefclient_maskclientcode));//get n first characters of client code where n is length in mask
769
        $maskrefclient_clientcode=str_pad($maskrefclient_clientcode,dol_strlen($maskrefclient_maskclientcode),"#",STR_PAD_RIGHT);//padding maskrefclient_clientcode for having exactly n characters in maskrefclient_clientcode
770
        $maskrefclient_clientcode=dol_string_nospecial($maskrefclient_clientcode);//sanitize maskrefclient_clientcode for sql insert and sql select like
771
        if (dol_strlen($maskrefclient_maskcounter) > 0 && dol_strlen($maskrefclient_maskcounter) < 3) return 'ErrorCounterMustHaveMoreThan3Digits';
772
    }
773
    else $maskrefclient='';
774
775
    // fail if there is neither a global nor a third party counter
776
    if (! $hasglobalcounter && ($maskrefclient_maskcounter == ''))
777
    {
778
        return 'ErrorBadMask';
779
    }
780
781
    // Extract value for third party type
782
    if (preg_match('/\{(t+)\}/i',$mask,$regType))
783
    {
784
        $masktype=$regType[1];
785
        $masktype_value=substr(preg_replace('/^TE_/','',$objsoc->typent_code),0,dol_strlen($regType[1]));// get n first characters of thirdpaty typent_code (where n is length in mask)
0 ignored issues
show
Bug introduced by
The property typent_code does not exist on string.
Loading history...
786
        $masktype_value=str_pad($masktype_value,dol_strlen($regType[1]),"#",STR_PAD_RIGHT);				 // we fill on right with # to have same number of char than into mask
787
    }
788
    else
789
    {
790
    	$masktype='';
791
    	$masktype_value='';
792
    }
793
794
    // Extract value for user
795
    if (preg_match('/\{(u+)\}/i',$mask,$regType))
796
    {
797
    	$lastname = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
798
    	if (is_object($objuser)) $lastname = $objuser->lastname;
799
800
    	$maskuser=$regType[1];
801
    	$maskuser_value=substr($lastname,0,dol_strlen($regType[1]));// get n first characters of user firstname (where n is length in mask)
802
    	$maskuser_value=str_pad($maskuser_value,dol_strlen($regType[1]),"#",STR_PAD_RIGHT);				 // we fill on right with # to have same number of char than into mask
803
    }
804
    else
805
    {
806
    	$maskuser='';
807
    	$maskuser_value='';
808
    }
809
810
    // Personalized field {XXX-1} à {XXX-9}
811
    $maskperso=array();
812
    $maskpersonew=array();
813
    $tmpmask=$mask;
814
    while (preg_match('/\{([A-Z]+)\-([1-9])\}/',$tmpmask,$regKey))
815
    {
816
        $maskperso[$regKey[1]]='{'.$regKey[1].'-'.$regKey[2].'}';
817
        $maskpersonew[$regKey[1]]=str_pad('', $regKey[2], '_', STR_PAD_RIGHT);
818
        $tmpmask=preg_replace('/\{'.$regKey[1].'\-'.$regKey[2].'\}/i', $maskpersonew[$regKey[1]], $tmpmask);
819
    }
820
821
    if (strstr($mask,'user_extra_'))
822
    {
823
			$start = "{user_extra_";
824
			$end = "\}";
825
			$extra= get_string_between($mask, "user_extra_", "}");
826
			if(!empty($user->array_options['options_'.$extra])){
827
				$mask =  preg_replace('#('.$start.')(.*?)('.$end.')#si', $user->array_options['options_'.$extra], $mask);
828
			}
829
    }
830
    $maskwithonlyymcode=$mask;
831
    $maskwithonlyymcode=preg_replace('/\{(0+)([@\+][0-9\-\+\=]+)?([@\+][0-9\-\+\=]+)?\}/i',$maskcounter,$maskwithonlyymcode);
832
    $maskwithonlyymcode=preg_replace('/\{dd\}/i','dd',$maskwithonlyymcode);
833
    $maskwithonlyymcode=preg_replace('/\{(c+)(0*)\}/i',$maskrefclient,$maskwithonlyymcode);
834
    $maskwithonlyymcode=preg_replace('/\{(t+)\}/i',$masktype_value,$maskwithonlyymcode);
835
    $maskwithonlyymcode=preg_replace('/\{(u+)\}/i',$maskuser_value,$maskwithonlyymcode);
836
    foreach($maskperso as $key => $val)
837
    {
838
        $maskwithonlyymcode=preg_replace('/'.preg_quote($val,'/').'/i', $maskpersonew[$key], $maskwithonlyymcode);
839
    }
840
    $maskwithnocode=$maskwithonlyymcode;
841
    $maskwithnocode=preg_replace('/\{yyyy\}/i','yyyy',$maskwithnocode);
842
    $maskwithnocode=preg_replace('/\{yy\}/i','yy',$maskwithnocode);
843
    $maskwithnocode=preg_replace('/\{y\}/i','y',$maskwithnocode);
844
    $maskwithnocode=preg_replace('/\{mm\}/i','mm',$maskwithnocode);
845
    // Now maskwithnocode = 0000ddmmyyyyccc for example
846
    // and maskcounter    = 0000 for example
847
    //print "maskwithonlyymcode=".$maskwithonlyymcode." maskwithnocode=".$maskwithnocode."\n<br>";
848
    //var_dump($reg);
849
850
    // If an offset is asked
851
    if (! empty($reg[2]) && preg_match('/^\+/',$reg[2])) $maskoffset=preg_replace('/^\+/','',$reg[2]);
852
    if (! empty($reg[3]) && preg_match('/^\+/',$reg[3])) $maskoffset=preg_replace('/^\+/','',$reg[3]);
853
854
    // Define $sqlwhere
855
    $sqlwhere='';
856
    $yearoffset=0;	// Use year of current $date by default
857
    $yearoffsettype=false;		// false: no reset, 0,-,=,+: reset at offset SOCIETE_FISCAL_MONTH_START, x=reset at offset x
858
859
    // If a restore to zero after a month is asked we check if there is already a value for this year.
860
    if (! empty($reg[2]) && preg_match('/^@/',$reg[2]))	$yearoffsettype = preg_replace('/^@/','',$reg[2]);
861
    if (! empty($reg[3]) && preg_match('/^@/',$reg[3]))	$yearoffsettype = preg_replace('/^@/','',$reg[3]);
862
863
    //print "yearoffset=".$yearoffset." yearoffsettype=".$yearoffsettype;
864
    if (is_numeric($yearoffsettype) && $yearoffsettype >= 1)
865
        $maskraz=$yearoffsettype; // For backward compatibility
866
    else if ($yearoffsettype === '0' || (! empty($yearoffsettype) && ! is_numeric($yearoffsettype) && $conf->global->SOCIETE_FISCAL_MONTH_START > 1))
867
        $maskraz = $conf->global->SOCIETE_FISCAL_MONTH_START;
868
    //print "maskraz=".$maskraz;	// -1=no reset
869
870
    if ($maskraz > 0) {   // A reset is required
871
        if ($maskraz == 99) {
872
            $maskraz = date('m', $date);
873
            $resetEveryMonth = true;
874
        }
875
        if ($maskraz > 12) return 'ErrorBadMaskBadRazMonth';
876
877
        // Define posy, posm and reg
878
        if ($maskraz > 1)	// if reset is not first month, we need month and year into mask
879
        {
880
            if (preg_match('/^(.*)\{(y+)\}\{(m+)\}/i',$maskwithonlyymcode,$reg)) { $posy=2; $posm=3; }
881
            elseif (preg_match('/^(.*)\{(m+)\}\{(y+)\}/i',$maskwithonlyymcode,$reg)) { $posy=3; $posm=2; }
882
            else return 'ErrorCantUseRazInStartedYearIfNoYearMonthInMask';
883
884
            if (dol_strlen($reg[$posy]) < 2) return 'ErrorCantUseRazWithYearOnOneDigit';
885
        }
886
        else // if reset is for a specific month in year, we need year
887
        {
888
            if (preg_match('/^(.*)\{(m+)\}\{(y+)\}/i',$maskwithonlyymcode,$reg)) { $posy=3; $posm=2; }
889
        	else if (preg_match('/^(.*)\{(y+)\}\{(m+)\}/i',$maskwithonlyymcode,$reg)) { $posy=2; $posm=3; }
890
            else if (preg_match('/^(.*)\{(y+)\}/i',$maskwithonlyymcode,$reg)) { $posy=2; $posm=0; }
891
            else return 'ErrorCantUseRazIfNoYearInMask';
892
        }
893
        // Define length
894
        $yearlen = $posy?dol_strlen($reg[$posy]):0;
895
        $monthlen = $posm?dol_strlen($reg[$posm]):0;
896
        // Define pos
897
       	$yearpos = (dol_strlen($reg[1])+1);
898
        $monthpos = ($yearpos+$yearlen);
899
        if ($posy == 3 && $posm == 2) {		// if month is before year
900
          	$monthpos = (dol_strlen($reg[1])+1);
901
           	$yearpos = ($monthpos+$monthlen);
902
        }
903
        //print "xxx ".$maskwithonlyymcode." maskraz=".$maskraz." posy=".$posy." yearlen=".$yearlen." yearpos=".$yearpos." posm=".$posm." monthlen=".$monthlen." monthpos=".$monthpos." yearoffsettype=".$yearoffsettype." resetEveryMonth=".$resetEveryMonth."\n";
904
905
        // Define $yearcomp and $monthcomp (that will be use in the select where to search max number)
906
        $monthcomp=$maskraz;
907
        $yearcomp=0;
908
909
        if (! empty($yearoffsettype) && ! is_numeric($yearoffsettype) && $yearoffsettype != '=')	// $yearoffsettype is - or +
910
        {
911
        	$currentyear=date("Y", $date);
912
        	$fiscaldate=dol_mktime('0','0','0',$maskraz,'1',$currentyear);
913
        	$newyeardate=dol_mktime('0','0','0','1','1',$currentyear);
914
        	$nextnewyeardate=dol_mktime('0','0','0','1','1',$currentyear+1);
915
        	//echo 'currentyear='.$currentyear.' date='.dol_print_date($date, 'day').' fiscaldate='.dol_print_date($fiscaldate, 'day').'<br>';
916
917
        	// If after or equal of current fiscal date
918
        	if ($date >= $fiscaldate)
919
        	{
920
        		// If before of next new year date
921
        		if ($date < $nextnewyeardate && $yearoffsettype == '+') $yearoffset=1;
922
        	}
923
        	// If after or equal of current new year date
924
        	else if ($date >= $newyeardate && $yearoffsettype == '-') $yearoffset=-1;
925
        }
926
        // For backward compatibility
927
        else if (date("m",$date) < $maskraz && empty($resetEveryMonth)) { $yearoffset=-1; }	// If current month lower that month of return to zero, year is previous year
928
929
        if ($yearlen == 4) $yearcomp=sprintf("%04d",date("Y",$date)+$yearoffset);
930
        elseif ($yearlen == 2) $yearcomp=sprintf("%02d",date("y",$date)+$yearoffset);
931
        elseif ($yearlen == 1) $yearcomp=substr(date("y",$date),2,1)+$yearoffset;
932
        if ($monthcomp > 1 && empty($resetEveryMonth))	// Test with month is useless if monthcomp = 0 or 1 (0 is same as 1) (regis: $monthcomp can't equal 0)
933
        {
934
            if ($yearlen == 4) $yearcomp1=sprintf("%04d",date("Y",$date)+$yearoffset+1);
935
            elseif ($yearlen == 2) $yearcomp1=sprintf("%02d",date("y",$date)+$yearoffset+1);
936
937
            $sqlwhere.="(";
938
            $sqlwhere.=" (SUBSTRING(".$field.", ".$yearpos.", ".$yearlen.") = '".$yearcomp."'";
939
            $sqlwhere.=" AND SUBSTRING(".$field.", ".$monthpos.", ".$monthlen.") >= '".str_pad($monthcomp, $monthlen, '0', STR_PAD_LEFT)."')";
940
            $sqlwhere.=" OR";
941
            $sqlwhere.=" (SUBSTRING(".$field.", ".$yearpos.", ".$yearlen.") = '".$yearcomp1."'";
942
            $sqlwhere.=" AND SUBSTRING(".$field.", ".$monthpos.", ".$monthlen.") < '".str_pad($monthcomp, $monthlen, '0', STR_PAD_LEFT)."') ";
943
            $sqlwhere.=')';
944
        }
945
		else if ($resetEveryMonth)
946
		{
947
			$sqlwhere.="(SUBSTRING(".$field.", ".$yearpos.", ".$yearlen.") = '".$yearcomp."'";
948
            $sqlwhere.=" AND SUBSTRING(".$field.", ".$monthpos.", ".$monthlen.") = '".str_pad($monthcomp, $monthlen, '0', STR_PAD_LEFT)."')";
949
		}
950
        else   // reset is done on january
951
        {
952
            $sqlwhere.='(SUBSTRING('.$field.', '.$yearpos.', '.$yearlen.") = '".$yearcomp."')";
953
        }
954
    }
955
    //print "sqlwhere=".$sqlwhere." yearcomp=".$yearcomp."<br>\n";	// sqlwhere and yearcomp defined only if we ask a reset
956
    //print "masktri=".$masktri." maskcounter=".$maskcounter." maskraz=".$maskraz." maskoffset=".$maskoffset."<br>\n";
957
958
    // Define $sqlstring
959
    if (function_exists('mb_strrpos'))
960
    	{
961
    	$posnumstart=mb_strrpos($maskwithnocode,$maskcounter, 'UTF-8');
962
	}
963
	else
964
	{
965
    	$posnumstart=strrpos($maskwithnocode,$maskcounter);
966
	}	// Pos of counter in final string (from 0 to ...)
967
    if ($posnumstart < 0) return 'ErrorBadMaskFailedToLocatePosOfSequence';
968
    $sqlstring='SUBSTRING('.$field.', '.($posnumstart+1).', '.dol_strlen($maskcounter).')';
969
970
    // Define $maskLike
971
    $maskLike = dol_string_nospecial($mask);
972
    $maskLike = str_replace("%","_",$maskLike);
973
    // Replace protected special codes with matching number of _ as wild card caracter
974
    $maskLike = preg_replace('/\{yyyy\}/i','____',$maskLike);
975
    $maskLike = preg_replace('/\{yy\}/i','__',$maskLike);
976
    $maskLike = preg_replace('/\{y\}/i','_',$maskLike);
977
    $maskLike = preg_replace('/\{mm\}/i','__',$maskLike);
978
    $maskLike = preg_replace('/\{dd\}/i','__',$maskLike);
979
    $maskLike = str_replace(dol_string_nospecial('{'.$masktri.'}'),str_pad("",dol_strlen($maskcounter),"_"),$maskLike);
980
    if ($maskrefclient) $maskLike = str_replace(dol_string_nospecial('{'.$maskrefclient.'}'),str_pad("",dol_strlen($maskrefclient),"_"),$maskLike);
981
    if ($masktype) $maskLike = str_replace(dol_string_nospecial('{'.$masktype.'}'),$masktype_value,$maskLike);
982
    if ($maskuser) $maskLike = str_replace(dol_string_nospecial('{'.$maskuser.'}'),$maskuser_value,$maskLike);
983
    foreach($maskperso as $key => $val)
984
    {
985
    	$maskLike = str_replace(dol_string_nospecial($maskperso[$key]),$maskpersonew[$key],$maskLike);
986
    }
987
988
    // Get counter in database
989
    $counter=0;
990
    $sql = "SELECT MAX(".$sqlstring.") as val";
991
    $sql.= " FROM ".MAIN_DB_PREFIX.$table;
992
    $sql.= " WHERE ".$field." LIKE '".$maskLike."'";
993
	$sql.= " AND ".$field." NOT LIKE '(PROV%)'";
994
    if ($bentityon) // only if entity enable
995
    	$sql.= " AND entity IN (".getEntity($sharetable).")";
996
    else if (! empty($forceentity))
997
    	$sql.= " AND entity IN (".$forceentity.")";
998
    if ($where) $sql.=$where;
999
    if ($sqlwhere) $sql.=' AND '.$sqlwhere;
1000
1001
    //print $sql.'<br>';
1002
    dol_syslog("functions2::get_next_value mode=".$mode."", LOG_DEBUG);
1003
    $resql=$db->query($sql);
1004
    if ($resql)
1005
    {
1006
        $obj = $db->fetch_object($resql);
1007
        $counter = $obj->val;
1008
    }
1009
    else dol_print_error($db);
1010
1011
    // Check if we must force counter to maskoffset
1012
    if (empty($counter)) $counter=$maskoffset;
1013
    else if (preg_match('/[^0-9]/i',$counter))
1014
    {
1015
    	$counter=0;
1016
    	dol_syslog("Error, the last counter found is '".$counter."' so is not a numeric value. We will restart to 1.", LOG_ERR);
1017
    }
1018
    else if ($counter < $maskoffset && empty($conf->global->MAIN_NUMBERING_OFFSET_ONLY_FOR_FIRST)) $counter=$maskoffset;
1019
1020
    if ($mode == 'last')	// We found value for counter = last counter value. Now need to get corresponding ref of invoice.
1021
    {
1022
        $counterpadded=str_pad($counter,dol_strlen($maskcounter),"0",STR_PAD_LEFT);
1023
1024
        // Define $maskLike
1025
        $maskLike = dol_string_nospecial($mask);
1026
        $maskLike = str_replace("%","_",$maskLike);
1027
        // Replace protected special codes with matching number of _ as wild card caracter
1028
        $maskLike = preg_replace('/\{yyyy\}/i','____',$maskLike);
1029
        $maskLike = preg_replace('/\{yy\}/i','__',$maskLike);
1030
        $maskLike = preg_replace('/\{y\}/i','_',$maskLike);
1031
        $maskLike = preg_replace('/\{mm\}/i','__',$maskLike);
1032
        $maskLike = preg_replace('/\{dd\}/i','__',$maskLike);
1033
        $maskLike = str_replace(dol_string_nospecial('{'.$masktri.'}'),$counterpadded,$maskLike);
1034
        if ($maskrefclient) $maskLike = str_replace(dol_string_nospecial('{'.$maskrefclient.'}'),str_pad("",dol_strlen($maskrefclient),"_"),$maskLike);
1035
        if ($masktype) $maskLike = str_replace(dol_string_nospecial('{'.$masktype.'}'),$masktype_value,$maskLike);
1036
        if ($maskuser) $maskLike = str_replace(dol_string_nospecial('{'.$maskuser.'}'),$maskuser_value,$maskLike);
1037
1038
        $ref='';
1039
        $sql = "SELECT ".$field." as ref";
1040
        $sql.= " FROM ".MAIN_DB_PREFIX.$table;
1041
        $sql.= " WHERE ".$field." LIKE '".$maskLike."'";
1042
    	$sql.= " AND ".$field." NOT LIKE '%PROV%'";
1043
    	if ($bentityon) // only if entity enable
1044
        	$sql.= " AND entity IN (".getEntity($sharetable).")";
1045
        else if (! empty($forceentity))
1046
        	$sql.= " AND entity IN (".$forceentity.")";
1047
        if ($where) $sql.=$where;
1048
        if ($sqlwhere) $sql.=' AND '.$sqlwhere;
1049
1050
        dol_syslog("functions2::get_next_value mode=".$mode."", LOG_DEBUG);
1051
        $resql=$db->query($sql);
1052
        if ($resql)
1053
        {
1054
            $obj = $db->fetch_object($resql);
1055
            if ($obj) $ref = $obj->ref;
1056
        }
1057
        else dol_print_error($db);
1058
1059
        $numFinal=$ref;
1060
    }
1061
    else if ($mode == 'next')
1062
    {
1063
        $counter++;
1064
1065
        // If value for $counter has a length higher than $maskcounter chars
1066
        if ($counter >= pow(10, dol_strlen($maskcounter)))
1067
        {
1068
        	$counter='ErrorMaxNumberReachForThisMask';
1069
        }
1070
1071
        if (! empty($maskrefclient_maskcounter))
1072
        {
1073
            //print "maskrefclient_maskcounter=".$maskrefclient_maskcounter." maskwithnocode=".$maskwithnocode." maskrefclient=".$maskrefclient."\n<br>";
1074
1075
            // Define $sqlstring
1076
            $maskrefclient_posnumstart=strpos($maskwithnocode,$maskrefclient_maskcounter,strpos($maskwithnocode,$maskrefclient));	// Pos of counter in final string (from 0 to ...)
1077
            if ($maskrefclient_posnumstart <= 0) return 'ErrorBadMask';
1078
            $maskrefclient_sqlstring='SUBSTRING('.$field.', '.($maskrefclient_posnumstart+1).', '.dol_strlen($maskrefclient_maskcounter).')';
1079
            //print "x".$sqlstring;
1080
1081
            // Define $maskrefclient_maskLike
1082
            $maskrefclient_maskLike = dol_string_nospecial($mask);
1083
            $maskrefclient_maskLike = str_replace("%","_",$maskrefclient_maskLike);
1084
            // Replace protected special codes with matching number of _ as wild card caracter
1085
            $maskrefclient_maskLike = str_replace(dol_string_nospecial('{yyyy}'),'____',$maskrefclient_maskLike);
1086
            $maskrefclient_maskLike = str_replace(dol_string_nospecial('{yy}'),'__',$maskrefclient_maskLike);
1087
            $maskrefclient_maskLike = str_replace(dol_string_nospecial('{y}'),'_',$maskrefclient_maskLike);
1088
            $maskrefclient_maskLike = str_replace(dol_string_nospecial('{mm}'),'__',$maskrefclient_maskLike);
1089
            $maskrefclient_maskLike = str_replace(dol_string_nospecial('{dd}'),'__',$maskrefclient_maskLike);
1090
            $maskrefclient_maskLike = str_replace(dol_string_nospecial('{'.$masktri.'}'),str_pad("",dol_strlen($maskcounter),"_"),$maskrefclient_maskLike);
1091
            $maskrefclient_maskLike = str_replace(dol_string_nospecial('{'.$maskrefclient.'}'),$maskrefclient_clientcode.str_pad("",dol_strlen($maskrefclient_maskcounter),"_"),$maskrefclient_maskLike);
1092
1093
            // Get counter in database
1094
            $maskrefclient_counter=0;
1095
            $maskrefclient_sql = "SELECT MAX(".$maskrefclient_sqlstring.") as val";
1096
            $maskrefclient_sql.= " FROM ".MAIN_DB_PREFIX.$table;
1097
            //$sql.= " WHERE ".$field." not like '(%'";
1098
            $maskrefclient_sql.= " WHERE ".$field." LIKE '".$maskrefclient_maskLike."'";
1099
            if ($bentityon) // only if entity enable
1100
            	$maskrefclient_sql.= " AND entity IN (".getEntity($sharetable).")";
1101
            else if (! empty($forceentity))
1102
            	$sql.= " AND entity IN (".$forceentity.")";
1103
            if ($where) $maskrefclient_sql.=$where; //use the same optional where as general mask
1104
            if ($sqlwhere) $maskrefclient_sql.=' AND '.$sqlwhere; //use the same sqlwhere as general mask
1105
            $maskrefclient_sql.=' AND (SUBSTRING('.$field.', '.(strpos($maskwithnocode,$maskrefclient)+1).', '.dol_strlen($maskrefclient_maskclientcode).")='".$maskrefclient_clientcode."')";
1106
1107
            dol_syslog("functions2::get_next_value maskrefclient", LOG_DEBUG);
1108
            $maskrefclient_resql=$db->query($maskrefclient_sql);
1109
            if ($maskrefclient_resql)
1110
            {
1111
                $maskrefclient_obj = $db->fetch_object($maskrefclient_resql);
1112
                $maskrefclient_counter = $maskrefclient_obj->val;
1113
            }
1114
            else dol_print_error($db);
1115
1116
            if (empty($maskrefclient_counter) || preg_match('/[^0-9]/i',$maskrefclient_counter)) $maskrefclient_counter=$maskrefclient_maskoffset;
1117
			$maskrefclient_counter++;
1118
        }
1119
1120
        // Build numFinal
1121
        $numFinal = $mask;
1122
1123
        // We replace special codes except refclient
1124
		if (! empty($yearoffsettype) && ! is_numeric($yearoffsettype) && $yearoffsettype != '=')	// yearoffsettype is - or +, so we don't want current year
1125
		{
1126
	        $numFinal = preg_replace('/\{yyyy\}/i',date("Y",$date)+$yearoffset, $numFinal);
1127
        	$numFinal = preg_replace('/\{yy\}/i',  date("y",$date)+$yearoffset, $numFinal);
1128
        	$numFinal = preg_replace('/\{y\}/i',   substr(date("y",$date),1,1)+$yearoffset, $numFinal);
1129
		}
1130
		else	// we want yyyy to be current year
1131
		{
1132
        	$numFinal = preg_replace('/\{yyyy\}/i',date("Y",$date), $numFinal);
1133
        	$numFinal = preg_replace('/\{yy\}/i',  date("y",$date), $numFinal);
1134
        	$numFinal = preg_replace('/\{y\}/i',   substr(date("y",$date),1,1), $numFinal);
1135
		}
1136
        $numFinal = preg_replace('/\{mm\}/i',  date("m",$date), $numFinal);
1137
        $numFinal = preg_replace('/\{dd\}/i',  date("d",$date), $numFinal);
1138
1139
        // Now we replace the counter
1140
        $maskbefore='{'.$masktri.'}';
1141
        $maskafter=str_pad($counter,dol_strlen($maskcounter),"0",STR_PAD_LEFT);
1142
        //print 'x'.$maskbefore.'-'.$maskafter.'y';
1143
        $numFinal = str_replace($maskbefore,$maskafter,$numFinal);
1144
1145
        // Now we replace the refclient
1146
        if ($maskrefclient)
1147
        {
1148
            //print "maskrefclient=".$maskrefclient." maskwithonlyymcode=".$maskwithonlyymcode." maskwithnocode=".$maskwithnocode."\n<br>";
1149
            $maskrefclient_maskbefore='{'.$maskrefclient.'}';
1150
            $maskrefclient_maskafter=$maskrefclient_clientcode.str_pad($maskrefclient_counter,dol_strlen($maskrefclient_maskcounter),"0",STR_PAD_LEFT);
1151
            $numFinal = str_replace($maskrefclient_maskbefore,$maskrefclient_maskafter,$numFinal);
1152
        }
1153
1154
        // Now we replace the type
1155
        if ($masktype)
1156
        {
1157
            $masktype_maskbefore='{'.$masktype.'}';
1158
            $masktype_maskafter=$masktype_value;
1159
            $numFinal = str_replace($masktype_maskbefore,$masktype_maskafter,$numFinal);
1160
        }
1161
1162
        // Now we replace the user
1163
        if ($maskuser)
1164
        {
1165
        	$maskuser_maskbefore='{'.$maskuser.'}';
1166
        	$maskuser_maskafter=$maskuser_value;
1167
        	$numFinal = str_replace($maskuser_maskbefore,$maskuser_maskafter,$numFinal);
1168
        }
1169
    }
1170
1171
    dol_syslog("functions2::get_next_value return ".$numFinal,LOG_DEBUG);
1172
    return $numFinal;
1173
}
1174
1175
/**
1176
 * Get string between
1177
 *
1178
 * @param   string  $string     String to test
1179
 * @param   int     $start      Value for start
1180
 * @param   int     $end        Value for end
1181
 * @return  string              Return part of string
1182
 */
1183
function get_string_between($string, $start, $end)
1184
{
1185
    $string = " ".$string;
1186
     $ini = strpos($string,$start);
1187
     if ($ini == 0) return "";
1188
     $ini += strlen($start);
1189
     $len = strpos($string,$end,$ini) - $ini;
1190
     return substr($string,$ini,$len);
1191
}
1192
1193
/**
1194
 * Check value
1195
 *
1196
 * @param 	string	$mask		Mask to use
1197
 * @param 	string	$value		Value
1198
 * @return	int|string		    <0 or error string if KO, 0 if OK
1199
 */
1200
function check_value($mask,$value)
1201
{
1202
    $result=0;
1203
1204
    $hasglobalcounter=false;
1205
    // Extract value for mask counter, mask raz and mask offset
1206
    if (preg_match('/\{(0+)([@\+][0-9]+)?([@\+][0-9]+)?\}/i',$mask,$reg))
1207
    {
1208
        $masktri=$reg[1].(isset($reg[2])?$reg[2]:'').(isset($reg[3])?$reg[3]:'');
1209
        $maskcounter=$reg[1];
1210
        $hasglobalcounter=true;
1211
    }
1212
    else
1213
    {
1214
        // setting some defaults so the rest of the code won't fail if there is a third party counter
1215
        $masktri='00000';
1216
        $maskcounter='00000';
1217
    }
1218
1219
    $maskraz=-1;
1220
    $maskoffset=0;
1221
    if (dol_strlen($maskcounter) < 3) return 'ErrorCounterMustHaveMoreThan3Digits';
1222
1223
    // Extract value for third party mask counter
1224
    if (preg_match('/\{(c+)(0*)\}/i',$mask,$regClientRef))
1225
    {
1226
        $maskrefclient=$regClientRef[1].$regClientRef[2];
1227
        $maskrefclient_maskclientcode=$regClientRef[1];
1228
        $maskrefclient_maskcounter=$regClientRef[2];
1229
        $maskrefclient_maskoffset=0; //default value of maskrefclient_counter offset
1230
        $maskrefclient_clientcode=substr('',0,dol_strlen($maskrefclient_maskclientcode));//get n first characters of client code to form maskrefclient_clientcode
1231
        $maskrefclient_clientcode=str_pad($maskrefclient_clientcode,dol_strlen($maskrefclient_maskclientcode),"#",STR_PAD_RIGHT);//padding maskrefclient_clientcode for having exactly n characters in maskrefclient_clientcode
1232
        $maskrefclient_clientcode=dol_string_nospecial($maskrefclient_clientcode);//sanitize maskrefclient_clientcode for sql insert and sql select like
1233
        if (dol_strlen($maskrefclient_maskcounter) > 0 && dol_strlen($maskrefclient_maskcounter) < 3) return 'ErrorCounterMustHaveMoreThan3Digits';
1234
    }
1235
    else $maskrefclient='';
1236
1237
    // fail if there is neither a global nor a third party counter
1238
    if (! $hasglobalcounter && ($maskrefclient_maskcounter == ''))
1239
    {
1240
        return 'ErrorBadMask';
1241
    }
1242
1243
    $maskwithonlyymcode=$mask;
1244
    $maskwithonlyymcode=preg_replace('/\{(0+)([@\+][0-9]+)?([@\+][0-9]+)?\}/i',$maskcounter,$maskwithonlyymcode);
1245
    $maskwithonlyymcode=preg_replace('/\{dd\}/i','dd',$maskwithonlyymcode);
1246
    $maskwithonlyymcode=preg_replace('/\{(c+)(0*)\}/i',$maskrefclient,$maskwithonlyymcode);
1247
    $maskwithnocode=$maskwithonlyymcode;
1248
    $maskwithnocode=preg_replace('/\{yyyy\}/i','yyyy',$maskwithnocode);
1249
    $maskwithnocode=preg_replace('/\{yy\}/i','yy',$maskwithnocode);
1250
    $maskwithnocode=preg_replace('/\{y\}/i','y',$maskwithnocode);
1251
    $maskwithnocode=preg_replace('/\{mm\}/i','mm',$maskwithnocode);
1252
    // Now maskwithnocode = 0000ddmmyyyyccc for example
1253
    // and maskcounter    = 0000 for example
1254
    //print "maskwithonlyymcode=".$maskwithonlyymcode." maskwithnocode=".$maskwithnocode."\n<br>";
1255
1256
    // If an offset is asked
1257
    if (! empty($reg[2]) && preg_match('/^\+/',$reg[2])) $maskoffset=preg_replace('/^\+/','',$reg[2]);
1258
    if (! empty($reg[3]) && preg_match('/^\+/',$reg[3])) $maskoffset=preg_replace('/^\+/','',$reg[3]);
1259
1260
    // Define $sqlwhere
1261
1262
    // If a restore to zero after a month is asked we check if there is already a value for this year.
1263
    if (! empty($reg[2]) && preg_match('/^@/',$reg[2]))  $maskraz=preg_replace('/^@/','',$reg[2]);
1264
    if (! empty($reg[3]) && preg_match('/^@/',$reg[3]))  $maskraz=preg_replace('/^@/','',$reg[3]);
1265
    if ($maskraz >= 0)
1266
    {
1267
        if ($maskraz > 12) return 'ErrorBadMaskBadRazMonth';
1268
1269
        // Define reg
1270
        if ($maskraz > 1 && ! preg_match('/^(.*)\{(y+)\}\{(m+)\}/i',$maskwithonlyymcode,$reg)) return 'ErrorCantUseRazInStartedYearIfNoYearMonthInMask';
1271
        if ($maskraz <= 1 && ! preg_match('/^(.*)\{(y+)\}/i',$maskwithonlyymcode,$reg)) return 'ErrorCantUseRazIfNoYearInMask';
1272
        //print "x".$maskwithonlyymcode." ".$maskraz;
1273
    }
1274
    //print "masktri=".$masktri." maskcounter=".$maskcounter." maskraz=".$maskraz." maskoffset=".$maskoffset."<br>\n";
1275
1276
    // Check we have a number in ($posnumstart+1).', '.dol_strlen($maskcounter)
1277
    //
1278
1279
    // Check length
1280
    $len=dol_strlen($maskwithnocode);
1281
    if (dol_strlen($value) != $len) $result=-1;
1282
1283
    // Define $maskLike
1284
    /* seems not used
1285
    $maskLike = dol_string_nospecial($mask);
1286
    $maskLike = str_replace("%","_",$maskLike);
1287
    // Replace protected special codes with matching number of _ as wild card caracter
1288
    $maskLike = str_replace(dol_string_nospecial('{yyyy}'),'____',$maskLike);
1289
    $maskLike = str_replace(dol_string_nospecial('{yy}'),'__',$maskLike);
1290
    $maskLike = str_replace(dol_string_nospecial('{y}'),'_',$maskLike);
1291
    $maskLike = str_replace(dol_string_nospecial('{mm}'),'__',$maskLike);
1292
    $maskLike = str_replace(dol_string_nospecial('{dd}'),'__',$maskLike);
1293
    $maskLike = str_replace(dol_string_nospecial('{'.$masktri.'}'),str_pad("",dol_strlen($maskcounter),"_"),$maskLike);
1294
    if ($maskrefclient) $maskLike = str_replace(dol_string_nospecial('{'.$maskrefclient.'}'),str_pad("",strlen($maskrefclient),"_"),$maskLike);
1295
	*/
1296
1297
    dol_syslog("functions2::check_value result=".$result,LOG_DEBUG);
1298
    return $result;
1299
}
1300
1301
/**
1302
 *	Convert a binary data to string that represent hexadecimal value
1303
 *
1304
 *	@param   string		$bin		Value to convert
1305
 *	@param   boolean	$pad      	Add 0
1306
 *	@param   boolean	$upper		Convert to tupper
1307
 *	@return  string					x
1308
 */
1309
function binhex($bin, $pad=false, $upper=false)
1310
{
1311
    $last = dol_strlen($bin)-1;
1312
    for($i=0; $i<=$last; $i++){ $x += $bin[$last-$i] * pow(2,$i); }
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $x seems to be never defined.
Loading history...
1313
    $x = dechex($x);
1314
    if($pad){ while(dol_strlen($x) < intval(dol_strlen($bin))/4){ $x = "0$x"; } }
1315
    if($upper){ $x = strtoupper($x); }
1316
    return $x;
1317
}
1318
1319
/**
1320
 *	Convert an hexadecimal string into a binary string
1321
 *
1322
 *	@param	string	$hexa		Hexadecimal string to convert (example: 'FF')
1323
 *	@return string	    		bin
1324
 */
1325
function hexbin($hexa)
1326
{
1327
    $bin='';
1328
    $strLength = dol_strlen($hexa);
1329
    for($i=0;$i<$strLength;$i++)
1330
    {
1331
        $bin.=str_pad(decbin(hexdec($hexa{$i})),4,'0',STR_PAD_LEFT);
1332
    }
1333
    return $bin;
1334
}
1335
1336
/**
1337
 *	Retourne le numero de la semaine par rapport a une date
1338
 *
1339
 *	@param	string	$time   	Date au format 'timestamp'
1340
 *	@return string					Number of week
1341
 */
1342
function numero_semaine($time)
1343
{
1344
    $stime = strftime('%Y-%m-%d',$time);
1345
1346
    if (preg_match('/^([0-9]+)\-([0-9]+)\-([0-9]+)\s?([0-9]+)?:?([0-9]+)?/i',$stime,$reg))
1347
    {
1348
        // Date est au format 'YYYY-MM-DD' ou 'YYYY-MM-DD HH:MM:SS'
1349
        $annee = $reg[1];
1350
        $mois = $reg[2];
1351
        $jour = $reg[3];
1352
    }
1353
1354
    /*
1355
     * Norme ISO-8601:
1356
     * - La semaine 1 de toute annee est celle qui contient le 4 janvier ou que la semaine 1 de toute annee est celle qui contient le 1er jeudi de janvier.
1357
     * - La majorite des annees ont 52 semaines mais les annees qui commence un jeudi et les annees bissextiles commencant un mercredi en possede 53.
1358
     * - Le 1er jour de la semaine est le Lundi
1359
     */
1360
1361
    // Definition du Jeudi de la semaine
1362
    if (date("w",mktime(12,0,0,$mois,$jour,$annee))==0) // Dimanche
1363
    $jeudiSemaine = mktime(12,0,0,$mois,$jour,$annee)-3*24*60*60;
1364
    else if (date("w",mktime(12,0,0,$mois,$jour,$annee))<4) // du Lundi au Mercredi
1365
    $jeudiSemaine = mktime(12,0,0,$mois,$jour,$annee)+(4-date("w",mktime(12,0,0,$mois,$jour,$annee)))*24*60*60;
1366
    else if (date("w",mktime(12,0,0,$mois,$jour,$annee))>4) // du Vendredi au Samedi
1367
    $jeudiSemaine = mktime(12,0,0,$mois,$jour,$annee)-(date("w",mktime(12,0,0,$mois,$jour,$annee))-4)*24*60*60;
1368
    else // Jeudi
1369
    $jeudiSemaine = mktime(12,0,0,$mois,$jour,$annee);
1370
1371
    // Definition du premier Jeudi de l'annee
1372
    if (date("w",mktime(12,0,0,1,1,date("Y",$jeudiSemaine)))==0) // Dimanche
1373
    {
1374
        $premierJeudiAnnee = mktime(12,0,0,1,1,date("Y",$jeudiSemaine))+4*24*60*60;
1375
    }
1376
    else if (date("w",mktime(12,0,0,1,1,date("Y",$jeudiSemaine)))<4) // du Lundi au Mercredi
1377
    {
1378
        $premierJeudiAnnee = mktime(12,0,0,1,1,date("Y",$jeudiSemaine))+(4-date("w",mktime(12,0,0,1,1,date("Y",$jeudiSemaine))))*24*60*60;
1379
    }
1380
    else if (date("w",mktime(12,0,0,1,1,date("Y",$jeudiSemaine)))>4) // du Vendredi au Samedi
1381
    {
1382
        $premierJeudiAnnee = mktime(12,0,0,1,1,date("Y",$jeudiSemaine))+(7-(date("w",mktime(12,0,0,1,1,date("Y",$jeudiSemaine)))-4))*24*60*60;
1383
    }
1384
    else // Jeudi
1385
    {
1386
        $premierJeudiAnnee = mktime(12,0,0,1,1,date("Y",$jeudiSemaine));
1387
    }
1388
1389
    // Definition du numero de semaine: nb de jours entre "premier Jeudi de l'annee" et "Jeudi de la semaine";
1390
    $numeroSemaine =     (
1391
    (
1392
    date("z",mktime(12,0,0,date("m",$jeudiSemaine),date("d",$jeudiSemaine),date("Y",$jeudiSemaine)))
1393
    -
1394
    date("z",mktime(12,0,0,date("m",$premierJeudiAnnee),date("d",$premierJeudiAnnee),date("Y",$premierJeudiAnnee)))
1395
    ) / 7
1396
    ) + 1;
1397
1398
    // Cas particulier de la semaine 53
1399
    if ($numeroSemaine==53)
1400
    {
1401
        // Les annees qui commence un Jeudi et les annees bissextiles commencant un Mercredi en possede 53
1402
        if (date("w",mktime(12,0,0,1,1,date("Y",$jeudiSemaine)))==4 || (date("w",mktime(12,0,0,1,1,date("Y",$jeudiSemaine)))==3 && date("z",mktime(12,0,0,12,31,date("Y",$jeudiSemaine)))==365))
1403
        {
1404
            $numeroSemaine = 53;
1405
        }
1406
        else
1407
        {
1408
            $numeroSemaine = 1;
1409
        }
1410
    }
1411
1412
    //echo $jour."-".$mois."-".$annee." (".date("d-m-Y",$premierJeudiAnnee)." - ".date("d-m-Y",$jeudiSemaine).") -> ".$numeroSemaine."<BR>";
1413
1414
    return sprintf("%02d",$numeroSemaine);
1415
}
1416
1417
/**
1418
 *	Convertit une masse d'une unite vers une autre unite
1419
 *
1420
 *	@param	float	$weight    		Masse a convertir
1421
 *	@param  int		$from_unit 		Unite originale en puissance de 10
1422
 *	@param  int		$to_unit   		Nouvelle unite  en puissance de 10
1423
 *	@return float	        		Masse convertie
1424
 */
1425
function weight_convert($weight,&$from_unit,$to_unit)
1426
{
1427
    /* Pour convertire 320 gr en Kg appeler
1428
     *  $f = -3
1429
     *  weigh_convert(320, $f, 0) retournera 0.32
1430
     *
1431
     */
1432
    while ($from_unit  <> $to_unit)
1433
    {
1434
        if ($from_unit > $to_unit)
1435
        {
1436
            $weight = $weight * 10;
1437
            $from_unit = $from_unit - 1;
1438
            $weight = weight_convert($weight,$from_unit, $to_unit);
1439
        }
1440
        if ($from_unit < $to_unit)
1441
        {
1442
            $weight = $weight / 10;
1443
            $from_unit = $from_unit + 1;
1444
            $weight = weight_convert($weight,$from_unit, $to_unit);
1445
        }
1446
    }
1447
1448
    return $weight;
1449
}
1450
1451
/**
1452
 *	Save personnal parameter
1453
 *
1454
 *	@param	DoliDB	$db         Handler database
1455
 *	@param	Conf	$conf		Object conf
0 ignored issues
show
Bug introduced by
The type Alixar\Helpers\Conf was not found. Did you mean Conf? If so, make sure to prefix the type with \.
Loading history...
1456
 *	@param	User	$user      	Object user
1457
 *	@param	array	$tab        Array (key=>value) with all parameters to save
1458
 *	@return int         		<0 if KO, >0 if OK
1459
 *
1460
 *	@see		dolibarr_get_const, dolibarr_set_const, dolibarr_del_const
1461
 */
1462
function dol_set_user_param($db, $conf, &$user, $tab)
1463
{
1464
    // Verification parametres
1465
    if (count($tab) < 1) return -1;
1466
1467
    $db->begin();
1468
1469
    // We remove old parameters for all keys in $tab
1470
    $sql = "DELETE FROM ".MAIN_DB_PREFIX."user_param";
1471
    $sql.= " WHERE fk_user = ".$user->id;
1472
    $sql.= " AND entity = ".$conf->entity;
1473
    $sql.= " AND param in (";
1474
    $i=0;
1475
    foreach ($tab as $key => $value)
1476
    {
1477
        if ($i > 0) $sql.=',';
1478
        $sql.="'".$db->escape($key)."'";
1479
        $i++;
1480
    }
1481
    $sql.= ")";
1482
    dol_syslog("functions2.lib::dol_set_user_param", LOG_DEBUG);
1483
1484
    $resql=$db->query($sql);
1485
    if (! $resql)
1486
    {
1487
        dol_print_error($db);
1488
        $db->rollback();
1489
        return -1;
1490
    }
1491
1492
    foreach ($tab as $key => $value)
1493
    {
1494
        // Set new parameters
1495
        if ($value)
1496
        {
1497
            $sql = "INSERT INTO ".MAIN_DB_PREFIX."user_param(fk_user,entity,param,value)";
1498
            $sql.= " VALUES (".$user->id.",".$conf->entity.",";
1499
            $sql.= " '".$db->escape($key)."','".$db->escape($value)."')";
1500
1501
            dol_syslog("functions2.lib::dol_set_user_param", LOG_DEBUG);
1502
            $result=$db->query($sql);
1503
            if (! $result)
1504
            {
1505
                dol_print_error($db);
1506
                $db->rollback();
1507
                return -1;
1508
            }
1509
            $user->conf->$key = $value;
1510
            //print "key=".$key." user->conf->key=".$user->conf->$key;
1511
        }
1512
        else
1513
        {
1514
            unset($user->conf->$key);
1515
        }
1516
    }
1517
1518
    $db->commit();
1519
    return 1;
1520
}
1521
1522
/**
1523
 *	Returns formated reduction
1524
 *
1525
 *	@param	int			$reduction		Reduction percentage
1526
 *	@param	Translate	$langs			Output language
1527
 *	@return	string						Formated reduction
1528
 */
1529
function dol_print_reduction($reduction,$langs)
1530
{
1531
    $string = '';
1532
    if ($reduction == 100)
1533
    {
1534
        $string = $langs->transnoentities("Offered");
1535
    }
1536
    else
1537
    {
1538
    	$string = vatrate($reduction,true);
1539
    }
1540
1541
    return $string;
1542
}
1543
1544
/**
1545
 * 	Return OS version.
1546
 *  Note that PHP_OS returns only OS (not version) and OS PHP was built on, not necessarly OS PHP runs on.
1547
 *
1548
 * 	@return		string			OS version
1549
 */
1550
function version_os()
1551
{
1552
    $osversion=php_uname();
1553
    return $osversion;
1554
}
1555
1556
/**
1557
 * 	Return PHP version
1558
 *
1559
 * 	@return		string			PHP version
1560
 *  @see		versionphparray
1561
 */
1562
function version_php()
1563
{
1564
    return phpversion();
1565
}
1566
1567
/**
1568
 * 	Return Dolibarr version
1569
 *
1570
 * 	@return		string			Dolibarr version
1571
 *  @see		versiondolibarrarray
1572
 */
1573
function version_dolibarr()
1574
{
1575
    return DOL_VERSION;
1576
}
1577
1578
/**
1579
 * 	Return web server version
1580
 *
1581
 * 	@return		string			Web server version
1582
 */
1583
function version_webserver()
1584
{
1585
    return $_SERVER["SERVER_SOFTWARE"];
1586
}
1587
1588
/**
1589
 * 	Return list of activated modules usable for document generation
1590
 *
1591
 * 	@param	DoliDB		$db				    Database handler
1592
 * 	@param	string		$type			    Type of models (company, invoice, ...)
1593
 *  @param  int		    $maxfilenamelength  Max length of value to show
1594
 * 	@return	mixed			    			0 if no module is activated, or array(key=>label). For modules that need directory scan, key is completed with ":filename".
1595
 */
1596
function getListOfModels($db,$type,$maxfilenamelength=0)
1597
{
1598
    global $conf,$langs;
1599
    $liste=array();
1600
    $found=0;
1601
    $dirtoscan='';
1602
1603
    $sql = "SELECT nom as id, nom as lib, libelle as label, description as description";
1604
    $sql.= " FROM ".MAIN_DB_PREFIX."document_model";
1605
    $sql.= " WHERE type = '".$type."'";
1606
    $sql.= " AND entity IN (0,".$conf->entity.")";
1607
    $sql.= " ORDER BY description DESC";
1608
1609
    dol_syslog('/core/lib/function2.lib.php::getListOfModels', LOG_DEBUG);
1610
    $resql = $db->query($sql);
1611
    if ($resql)
1612
    {
1613
        $num = $db->num_rows($resql);
1614
        $i = 0;
1615
        while ($i < $num)
1616
        {
1617
            $found=1;
1618
1619
            $obj = $db->fetch_object($resql);
1620
1621
            // If this generation module needs to scan a directory, then description field is filled
1622
            // with the constant that contains list of directories to scan (COMPANY_ADDON_PDF_ODT_PATH, ...).
1623
            if (! empty($obj->description))	// A list of directories to scan is defined
1624
            {
1625
                include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1626
1627
                $const=$obj->description;
1628
                //irtoscan.=($dirtoscan?',':'').preg_replace('/[\r\n]+/',',',trim($conf->global->$const));
1629
                $dirtoscan= preg_replace('/[\r\n]+/',',',trim($conf->global->$const));
1630
1631
		$listoffiles=array();
1632
1633
                // Now we add models found in directories scanned
1634
                $listofdir=explode(',',$dirtoscan);
1635
                foreach($listofdir as $key=>$tmpdir)
1636
                {
1637
                    $tmpdir=trim($tmpdir);
1638
                    $tmpdir=preg_replace('/DOL_DATA_ROOT/',DOL_DATA_ROOT,$tmpdir);
1639
                    if (! $tmpdir) { unset($listofdir[$key]); continue; }
1640
                    if (is_dir($tmpdir))
1641
                    {
1642
			// all type of template is allowed
1643
			$tmpfiles=dol_dir_list($tmpdir, 'files', 0, '', '', 'name', SORT_ASC, 0);
1644
                        if (count($tmpfiles)) $listoffiles=array_merge($listoffiles,$tmpfiles);
1645
                    }
1646
                }
1647
1648
                if (count($listoffiles))
1649
                {
1650
                    foreach($listoffiles as $record)
1651
                    {
1652
                        $max=($maxfilenamelength?$maxfilenamelength:28);
1653
                        $liste[$obj->id.':'.$record['fullname']]=dol_trunc($record['name'],$max,'middle');
1654
                    }
1655
                }
1656
                else
1657
                {
1658
                    $liste[0]=$obj->label.': '.$langs->trans("None");
1659
                }
1660
            }
1661
            else
1662
            {
1663
                if ($type == 'member' && $obj->lib == 'standard')   // Special case, if member template, we add variant per format
1664
                {
1665
                    global $_Avery_Labels;
1666
                    include_once DOL_DOCUMENT_ROOT.'/core/lib/format_cards.lib.php';
1667
                    foreach($_Avery_Labels as $key => $val)
1668
                    {
1669
                        $liste[$obj->id.':'.$key]=($obj->label?$obj->label:$obj->lib).' '.$val['name'];
1670
                    }
1671
                }
1672
                else    // Common usage
1673
                {
1674
                    $liste[$obj->id]=$obj->label?$obj->label:$obj->lib;
1675
                }
1676
            }
1677
            $i++;
1678
        }
1679
    }
1680
    else
1681
    {
1682
        dol_print_error($db);
1683
        return -1;
1684
    }
1685
1686
    if ($found) return $liste;
1687
    else return 0;
1688
}
1689
1690
/**
1691
 * This function evaluates a string that should be a valid IPv4
1692
 * Note: For ip 169.254.0.0, it returns 0 with some PHP (5.6.24) and 2 with some minor patchs of PHP (5.6.25). See https://github.com/php/php-src/pull/1954.
1693
 *
1694
 * @param	string $ip IP Address
1695
 * @return	int 0 if not valid or reserved range, 1 if valid and public IP, 2 if valid and private range IP
1696
 */
1697
function is_ip($ip)
1698
{
1699
	// First we test if it is a valid IPv4
1700
	if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
1701
1702
		// Then we test if it is a private range
1703
		if (! filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE)) return 2;
1704
1705
		// Then we test if it is a reserved range
1706
		if (! filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_RES_RANGE)) return 0;
1707
1708
		return 1;
1709
	}
1710
1711
	return 0;
1712
}
1713
1714
/**
1715
 *  Build a login from lastname, firstname
1716
 *
1717
 *  @param	string		$lastname		Lastname
1718
 *  @param  string		$firstname		Firstname
1719
 *	@return	string						Login
1720
 */
1721
function dol_buildlogin($lastname,$firstname)
1722
{
1723
    $login=strtolower(dol_string_unaccent($firstname));
1724
    $login.=($login?'.':'');
1725
    $login.=strtolower(dol_string_unaccent($lastname));
1726
    $login=dol_string_nospecial($login,''); // For special names
1727
    return $login;
1728
}
1729
1730
/**
1731
 *  Return array to use for SoapClient constructor
1732
 *
1733
 *  @return     array
1734
 */
1735
function getSoapParams()
1736
{
1737
    global $conf;
1738
1739
    $params=array();
1740
    $proxyuse =(empty($conf->global->MAIN_PROXY_USE)?false:true);
1741
    $proxyhost=(empty($conf->global->MAIN_PROXY_USE)?false:$conf->global->MAIN_PROXY_HOST);
1742
    $proxyport=(empty($conf->global->MAIN_PROXY_USE)?false:$conf->global->MAIN_PROXY_PORT);
1743
    $proxyuser=(empty($conf->global->MAIN_PROXY_USE)?false:$conf->global->MAIN_PROXY_USER);
1744
    $proxypass=(empty($conf->global->MAIN_PROXY_USE)?false:$conf->global->MAIN_PROXY_PASS);
1745
    $timeout  =(empty($conf->global->MAIN_USE_CONNECT_TIMEOUT)?10:$conf->global->MAIN_USE_CONNECT_TIMEOUT);               // Connection timeout
1746
    $response_timeout=(empty($conf->global->MAIN_USE_RESPONSE_TIMEOUT)?30:$conf->global->MAIN_USE_RESPONSE_TIMEOUT);    // Response timeout
1747
    //print extension_loaded('soap');
1748
    if ($proxyuse)
1749
    {
1750
        $params=array('connection_timeout'=>$timeout,
1751
                      'response_timeout'=>$response_timeout,
1752
                      'proxy_use'      => 1,
1753
                      'proxy_host'     => $proxyhost,
1754
                      'proxy_port'     => $proxyport,
1755
                      'proxy_login'    => $proxyuser,
1756
                      'proxy_password' => $proxypass,
1757
                      'trace'		   => 1
1758
        );
1759
    }
1760
    else
1761
    {
1762
        $params=array('connection_timeout'=>$timeout,
1763
                      'response_timeout'=>$response_timeout,
1764
                      'proxy_use'      => 0,
1765
                      'proxy_host'     => false,
1766
                      'proxy_port'     => false,
1767
                      'proxy_login'    => false,
1768
                      'proxy_password' => false,
1769
                      'trace'		   => 1
1770
        );
1771
    }
1772
    return $params;
1773
}
1774
1775
1776
/**
1777
 * Return link url to an object
1778
 *
1779
 * @param 	int		$objectid		Id of record
1780
 * @param 	string	$objecttype		Type of object ('invoice', 'order', 'expedition_bon', ...)
1781
 * @param 	int		$withpicto		Picto to show
1782
 * @param 	string	$option			More options
1783
 * @return	string					URL of link to object id/type
1784
 */
1785
function dolGetElementUrl($objectid,$objecttype,$withpicto=0,$option='')
1786
{
1787
	global $db, $conf, $langs;
1788
1789
	$ret='';
1790
1791
	// Parse element/subelement (ex: project_task)
1792
	$module = $element = $subelement = $objecttype;
1793
	if (preg_match('/^([^_]+)_([^_]+)/i',$objecttype,$regs))
1794
	{
1795
		$module = $element = $regs[1];
1796
		$subelement = $regs[2];
1797
	}
1798
1799
	$classpath = $element.'/class';
1800
1801
	// To work with non standard path
1802
	if ($objecttype == 'facture' || $objecttype == 'invoice') {
1803
		$classpath = 'compta/facture/class';
1804
		$module='facture';
1805
		$subelement='facture';
1806
	}
1807
	if ($objecttype == 'commande' || $objecttype == 'order') {
1808
		$classpath = 'commande/class';
1809
		$module='commande';
1810
		$subelement='commande';
1811
	}
1812
	if ($objecttype == 'propal')  {
1813
		$classpath = 'comm/propal/class';
1814
	}
1815
	if ($objecttype == 'supplier_proposal')  {
1816
		$classpath = 'supplier_proposal/class';
1817
	}
1818
	if ($objecttype == 'shipping') {
1819
		$classpath = 'expedition/class';
1820
		$subelement = 'expedition';
1821
		$module = 'expedition_bon';
1822
	}
1823
	if ($objecttype == 'delivery') {
1824
		$classpath = 'livraison/class';
1825
		$subelement = 'livraison';
1826
		$module = 'livraison_bon';
1827
	}
1828
	if ($objecttype == 'contract') {
1829
		$classpath = 'contrat/class';
1830
		$module='contrat';
1831
		$subelement='contrat';
1832
	}
1833
	if ($objecttype == 'member') {
1834
		$classpath = 'adherents/class';
1835
		$module='adherent';
1836
		$subelement='adherent';
1837
	}
1838
	if ($objecttype == 'cabinetmed_cons') {
1839
		$classpath = 'cabinetmed/class';
1840
		$module='cabinetmed';
1841
		$subelement='cabinetmedcons';
1842
	}
1843
	if ($objecttype == 'fichinter') {
1844
		$classpath = 'fichinter/class';
1845
		$module='ficheinter';
1846
		$subelement='fichinter';
1847
	}
1848
	if ($objecttype == 'task') {
1849
		$classpath = 'projet/class';
1850
		$module='projet';
1851
		$subelement='task';
1852
	}
1853
	if ($objecttype == 'stock') {
1854
		$classpath = 'product/stock/class';
1855
		$module='stock';
1856
		$subelement='stock';
1857
	}
1858
1859
	//print "objecttype=".$objecttype." module=".$module." subelement=".$subelement;
1860
1861
	$classfile = strtolower($subelement); $classname = ucfirst($subelement);
1862
	if ($objecttype == 'invoice_supplier') {
1863
		$classfile = 'fournisseur.facture';
1864
		$classname='FactureFournisseur';
1865
		$classpath = 'fourn/class';
1866
		$module='fournisseur';
1867
	}
1868
	elseif ($objecttype == 'order_supplier')   {
1869
		$classfile = 'fournisseur.commande';
1870
		$classname='CommandeFournisseur';
1871
		$classpath = 'fourn/class';
1872
		$module='fournisseur';
1873
	}
1874
	elseif ($objecttype == 'stock')   {
1875
		$classpath = 'product/stock/class';
1876
		$classfile='entrepot';
1877
		$classname='Entrepot';
1878
	}
1879
	if (! empty($conf->$module->enabled))
1880
	{
1881
		$res=dol_include_once('/'.$classpath.'/'.$classfile.'.class.php');
1882
		if ($res)
1883
		{
1884
			if (class_exists($classname))
1885
			{
1886
				$object = new $classname($db);
1887
				$res=$object->fetch($objectid);
1888
				if ($res > 0) {
1889
					$ret=$object->getNomUrl($withpicto,$option);
1890
				} elseif($res==0) {
1891
					$ret=$langs->trans('Deleted');
1892
				}
1893
				unset($object);
1894
			}
1895
			else dol_syslog("Class with classname ".$classname." is unknown even after the include", LOG_ERR);
1896
		}
1897
	}
1898
	return $ret;
1899
}
1900
1901
1902
/**
1903
 * Clean corrupted tree (orphelins linked to a not existing parent), record linked to themself and child-parent loop
1904
 *
1905
 * @param	DoliDB	$db					Database handler
1906
 * @param	string	$tabletocleantree	Table to clean
1907
 * @param	string	$fieldfkparent		Field name that contains id of parent
1908
 * @return	int							Nb of records fixed/deleted
1909
 */
1910
function cleanCorruptedTree($db, $tabletocleantree, $fieldfkparent)
1911
{
1912
	$totalnb=0;
1913
	$listofid=array();
1914
	$listofparentid=array();
1915
1916
	// Get list of all id in array listofid and all parents in array listofparentid
1917
	$sql='SELECT rowid, '.$fieldfkparent.' as parent_id FROM '.MAIN_DB_PREFIX.$tabletocleantree;
1918
	$resql = $db->query($sql);
1919
	if ($resql)
1920
	{
1921
		$num = $db->num_rows($resql);
1922
		$i = 0;
1923
		while ($i < $num)
1924
		{
1925
			$obj = $db->fetch_object($resql);
1926
			$listofid[]=$obj->rowid;
1927
			if ($obj->parent_id > 0) $listofparentid[$obj->rowid]=$obj->parent_id;
1928
			$i++;
1929
		}
1930
	}
1931
	else
1932
	{
1933
		dol_print_error($db);
1934
	}
1935
1936
	if (count($listofid))
1937
	{
1938
		print 'Code requested to clean tree (may be to solve data corruption), so we check/clean orphelins and loops.'."<br>\n";
1939
1940
		// Check loops on each other
1941
		$sql = "UPDATE ".MAIN_DB_PREFIX.$tabletocleantree." SET ".$fieldfkparent." = 0 WHERE ".$fieldfkparent." = rowid";	// So we update only records linked to themself
1942
		$resql = $db->query($sql);
1943
		if ($resql)
1944
		{
1945
			$nb=$db->affected_rows($sql);
1946
			if ($nb > 0)
1947
			{
1948
				print '<br>Some record that were parent of themself were cleaned.';
1949
			}
1950
1951
			$totalnb+=$nb;
1952
		}
1953
		//else dol_print_error($db);
1954
1955
		// Check other loops
1956
		$listofidtoclean=array();
1957
		foreach($listofparentid as $id => $pid)
1958
		{
1959
			// Check depth
1960
			//print 'Analyse record id='.$id.' with parent '.$pid.'<br>';
1961
1962
			$cursor=$id; $arrayidparsed=array();	// We start from child $id
1963
			while ($cursor > 0)
1964
			{
1965
				$arrayidparsed[$cursor]=1;
1966
				if ($arrayidparsed[$listofparentid[$cursor]])	// We detect a loop. A record with a parent that was already into child
1967
				{
1968
					print 'Found a loop between id '.$id.' - '.$cursor.'<br>';
1969
					unset($arrayidparsed);
1970
					$listofidtoclean[$cursor]=$id;
1971
					break;
1972
				}
1973
				$cursor=$listofparentid[$cursor];
1974
			}
1975
1976
			if (count($listofidtoclean)) break;
1977
		}
1978
1979
		$sql = "UPDATE ".MAIN_DB_PREFIX.$tabletocleantree;
1980
		$sql.= " SET ".$fieldfkparent." = 0";
1981
		$sql.= " WHERE rowid IN (".join(',',$listofidtoclean).")";	// So we update only records detected wrong
1982
		$resql = $db->query($sql);
1983
		if ($resql)
1984
		{
1985
			$nb=$db->affected_rows($sql);
1986
			if ($nb > 0)
1987
			{
1988
				// Removed orphelins records
1989
				print '<br>Some records were detected to have parent that is a child, we set them as root record for id: ';
1990
				print join(',',$listofidtoclean);
1991
			}
1992
1993
			$totalnb+=$nb;
1994
		}
1995
		//else dol_print_error($db);
1996
1997
		// Check and clean orphelins
1998
		$sql = "UPDATE ".MAIN_DB_PREFIX.$tabletocleantree;
1999
		$sql.= " SET ".$fieldfkparent." = 0";
2000
		$sql.= " WHERE ".$fieldfkparent." NOT IN (".join(',',$listofid).")";	// So we update only records linked to a non existing parent
2001
		$resql = $db->query($sql);
2002
		if ($resql)
2003
		{
2004
			$nb=$db->affected_rows($sql);
2005
			if ($nb > 0)
2006
			{
2007
				// Removed orphelins records
2008
				print '<br>Some orphelins were found and modified to be parent so records are visible again for id: ';
2009
				print join(',',$listofid);
2010
			}
2011
2012
			$totalnb+=$nb;
2013
		}
2014
		//else dol_print_error($db);
2015
2016
		print '<br>We fixed '.$totalnb.' record(s). Some records may still be corrupted. New check may be required.';
2017
		return $totalnb;
2018
	}
2019
}
2020
2021
/**
2022
 *	Get an array with properties of an element
2023
 *
2024
 * @param 	string 	$element_type 	Element type: 'action', 'facture', 'project_task' or 'object@modulext'...
2025
 * @return 	array					(module, classpath, element, subelement, classfile, classname)
2026
 */
2027
function getElementProperties($element_type)
2028
{
2029
    // Parse element/subelement (ex: project_task)
2030
    $module = $element = $subelement = $element_type;
2031
2032
    // If we ask an resource form external module (instead of default path)
2033
    if (preg_match('/^([^@]+)@([^@]+)$/i',$element_type,$regs))
2034
    {
2035
        $element = $subelement = $regs[1];
2036
        $module 	= $regs[2];
2037
    }
2038
2039
    //print '<br>1. element : '.$element.' - module : '.$module .'<br>';
2040
    if ( preg_match('/^([^_]+)_([^_]+)/i',$element,$regs))
2041
    {
2042
        $module = $element = $regs[1];
2043
        $subelement = $regs[2];
2044
    }
2045
2046
    // For compat
2047
    if($element_type == "action") {
2048
        $classpath = 'comm/action/class';
2049
        $subelement = 'Actioncomm';
2050
        $module = 'agenda';
2051
    }
2052
2053
    // To work with non standard path
2054
    if ($element_type == 'facture' || $element_type == 'invoice') {
2055
        $classpath = 'compta/facture/class';
2056
        $module='facture';
2057
        $subelement='facture';
2058
    }
2059
    if ($element_type == 'commande' || $element_type == 'order') {
2060
        $classpath = 'commande/class';
2061
        $module='commande';
2062
        $subelement='commande';
2063
    }
2064
    if ($element_type == 'propal')  {
2065
        $classpath = 'comm/propal/class';
2066
    }
2067
    if ($element_type == 'supplier_proposal')  {
2068
        $classpath = 'supplier_proposal/class';
2069
    }
2070
    if ($element_type == 'shipping') {
2071
        $classpath = 'expedition/class';
2072
        $subelement = 'expedition';
2073
        $module = 'expedition_bon';
2074
    }
2075
    if ($element_type == 'delivery') {
2076
        $classpath = 'livraison/class';
2077
        $subelement = 'livraison';
2078
        $module = 'livraison_bon';
2079
    }
2080
    if ($element_type == 'contract') {
2081
        $classpath = 'contrat/class';
2082
        $module='contrat';
2083
        $subelement='contrat';
2084
    }
2085
    if ($element_type == 'member') {
2086
        $classpath = 'adherents/class';
2087
        $module='adherent';
2088
        $subelement='adherent';
2089
    }
2090
    if ($element_type == 'cabinetmed_cons') {
2091
        $classpath = 'cabinetmed/class';
2092
        $module='cabinetmed';
2093
        $subelement='cabinetmedcons';
2094
    }
2095
    if ($element_type == 'fichinter') {
2096
        $classpath = 'fichinter/class';
2097
        $module='ficheinter';
2098
        $subelement='fichinter';
2099
    }
2100
    if ($element_type == 'dolresource' || $element_type == 'resource') {
2101
        $classpath = 'resource/class';
2102
        $module='resource';
2103
        $subelement='dolresource';
2104
    }
2105
    if ($element_type == 'propaldet') {
2106
        $classpath = 'comm/propal/class';
2107
        $module='propal';
2108
        $subelement='propaleligne';
2109
    }
2110
    if ($element_type == 'order_supplier')  {
2111
        $classpath = 'fourn/class';
2112
        $module='fournisseur';
2113
        $subelement='commandefournisseur';
2114
        $classfile='fournisseur.commande';
2115
    }
2116
    if ($element_type == 'invoice_supplier')  {
2117
        $classpath = 'fourn/class';
2118
        $module='fournisseur';
2119
        $subelement='facturefournisseur';
2120
        $classfile='fournisseur.facture';
2121
    }
2122
2123
    if (!isset($classfile)) $classfile = strtolower($subelement);
2124
    if (!isset($classname)) $classname = ucfirst($subelement);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $classname seems to never exist and therefore isset should always be false.
Loading history...
2125
    if (!isset($classpath)) $classpath = $module.'/class';
2126
2127
    $element_properties = array(
2128
        'module' => $module,
2129
        'classpath' => $classpath,
2130
        'element' => $element,
2131
        'subelement' => $subelement,
2132
        'classfile' => $classfile,
2133
        'classname' => $classname
2134
    );
2135
    return $element_properties;
2136
}
2137
2138
/**
2139
 * Fetch an object from its id and element_type
2140
 * Inclusion of classes is automatic
2141
 *
2142
 * @param	int     	$element_id 	Element id
2143
 * @param	string  	$element_type 	Element type
2144
 * @param	ref     	$element_ref 	Element ref (Use this if element_id but not both)
2145
 * @return 	int|object 					object || 0 || -1 if error
2146
 */
2147
function fetchObjectByElement($element_id, $element_type, $element_ref='')
2148
{
2149
    global $conf;
2150
	global $db,$conf;
2151
2152
    $element_prop = getElementProperties($element_type);
2153
    if (is_array($element_prop) && $conf->{$element_prop['module']}->enabled)
2154
    {
2155
        dol_include_once('/'.$element_prop['classpath'].'/'.$element_prop['classfile'].'.class.php');
2156
2157
		$objecttmp = new $element_prop['classname']($db);
2158
		$ret = $objecttmp->fetch($element_id, $element_ref);
2159
		if ($ret >= 0)
2160
		{
2161
			return $objecttmp;
2162
		}
2163
	}
2164
	return 0;
2165
}
2166
2167
2168
/**
2169
 *	Convert an array with RGB value into hex RGB value.
2170
 *  This is the opposite function of colorStringToArray
2171
 *
2172
 *  @param	array	$arraycolor			Array
2173
 *  @param	string	$colorifnotfound	Color code to return if entry not defined or not a RGB format
2174
 *  @return	string						RGB hex value (without # before). For example: 'FF00FF', '01FF02'
2175
 *  @see	colorStringToArray
2176
 */
2177
function colorArrayToHex($arraycolor,$colorifnotfound='888888')
2178
{
2179
	if (! is_array($arraycolor)) return $colorifnotfound;
2180
	if (empty($arraycolor)) return $colorifnotfound;
2181
	return sprintf("%02s",dechex($arraycolor[0])).sprintf("%02s",dechex($arraycolor[1])).sprintf("%02s",dechex($arraycolor[2]));
2182
}
2183
2184
/**
2185
 *	Convert a string RGB value ('FFFFFF', '255,255,255') into an array RGB array(255,255,255).
2186
 *  This is the opposite function of colorArrayToHex.
2187
 *  If entry is already an array, return it.
2188
 *
2189
 *  @param	string	$stringcolor		String with hex (FFFFFF) or comma RGB ('255,255,255')
2190
 *  @param	array	$colorifnotfound	Color code array to return if entry not defined
2191
 *  @return	string						RGB hex value (without # before). For example: FF00FF
2192
 *  @see	colorArrayToHex
2193
 */
2194
static function colorStringToArray($stringcolor, $colorifnotfound = array(88, 88, 88))
2195
    {
2196
	if (is_array($stringcolor)) return $stringcolor;	// If already into correct output format, we return as is
2197
	$tmp=preg_match('/^#?([0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F])$/',$stringcolor,$reg);
2198
	if (! $tmp)
2199
	{
2200
		$tmp=explode(',',$stringcolor);
2201
		if (count($tmp) < 3) return $colorifnotfound;
2202
		return $tmp;
2203
	}
2204
	return array(hexdec($reg[1]),hexdec($reg[2]),hexdec($reg[3]));
2205
}
2206
2207
/**
2208
 * Applies the Cartesian product algorithm to an array
2209
 * Source: http://stackoverflow.com/a/15973172
2210
 *
2211
 * @param   array $input    Array of products
2212
 * @return  array           Array of combinations
2213
 */
2214
function cartesianArray(array $input)
2215
{
2216
    // filter out empty values
2217
    $input = array_filter($input);
2218
2219
    $result = array(array());
2220
2221
    foreach ($input as $key => $values) {
2222
        $append = array();
2223
2224
        foreach($result as $product) {
2225
            foreach($values as $item) {
2226
                $product[$key] = $item;
2227
                $append[] = $product;
2228
            }
2229
        }
2230
2231
        $result = $append;
2232
    }
2233
2234
    return $result;
2235
}
2236
2237
2238
/**
2239
 * Get name of directory where the api_...class.php file is stored
2240
 *
2241
 * @param   string  $module     Module name
2242
 * @return  string              Directory name
2243
 */
2244
function getModuleDirForApiClass($module)
2245
{
2246
    $moduledirforclass=$module;
2247
    if ($moduledirforclass != 'api') $moduledirforclass = preg_replace('/api$/i','',$moduledirforclass);
2248
2249
    if ($module == 'contracts') {
2250
    	$moduledirforclass = 'contrat';
2251
    }
2252
    elseif (in_array($module, array('admin', 'login', 'setup', 'access', 'status', 'tools', 'documents'))) {
2253
        $moduledirforclass = 'api';
2254
    }
2255
    elseif ($module == 'contact' || $module == 'contacts' || $module == 'customer' || $module == 'thirdparty' || $module == 'thirdparties') {
2256
        $moduledirforclass = 'societe';
2257
    }
2258
    elseif ($module == 'propale' || $module == 'proposals') {
2259
        $moduledirforclass = 'comm/propal';
2260
    }
2261
    elseif ($module == 'agenda' || $module == 'agendaevents') {
2262
        $moduledirforclass = 'comm/action';
2263
    }
2264
    elseif ($module == 'adherent' || $module == 'members' || $module == 'memberstypes' || $module == 'subscriptions') {
2265
        $moduledirforclass = 'adherents';
2266
    }
2267
    elseif ($module == 'banque' || $module == 'bankaccounts') {
2268
        $moduledirforclass = 'compta/bank';
2269
    }
2270
    elseif ($module == 'category' || $module == 'categorie') {
2271
        $moduledirforclass = 'categories';
2272
    }
2273
    elseif ($module == 'order' || $module == 'orders') {
2274
        $moduledirforclass = 'commande';
2275
    }
2276
    elseif ($module == 'shipments') {
2277
    	$moduledirforclass = 'expedition';
2278
    }
2279
    elseif ($module == 'facture' || $module == 'invoice' || $module == 'invoices') {
2280
        $moduledirforclass = 'compta/facture';
2281
    }
2282
    elseif ($module == 'products') {
2283
        $moduledirforclass = 'product';
2284
    }
2285
    elseif ($module == 'project' || $module == 'projects' || $module == 'tasks') {
2286
        $moduledirforclass = 'projet';
2287
    }
2288
    elseif ($module == 'task') {
2289
        $moduledirforclass = 'projet';
2290
    }
2291
    elseif ($module == 'stock' || $module == 'stockmovements' || $module == 'warehouses') {
2292
        $moduledirforclass = 'product/stock';
2293
    }
2294
    elseif ($module == 'supplierproposals' || $module == 'supplierproposal' || $module == 'supplier_proposal') {
2295
    	$moduledirforclass = 'supplier_proposal';
2296
    }
2297
    elseif ($module == 'fournisseur' || $module == 'supplierinvoices' || $module == 'supplierorders') {
2298
        $moduledirforclass = 'fourn';
2299
    }
2300
    elseif ($module == 'expensereports') {
2301
        $moduledirforclass = 'expensereport';
2302
    }
2303
    elseif ($module == 'users') {
2304
        $moduledirforclass = 'user';
2305
    }
2306
    elseif ($module == 'ficheinter' || $module == 'interventions') {
2307
    	$moduledirforclass = 'fichinter';
2308
    }
2309
    elseif ($module == 'tickets') {
2310
    	$moduledirforclass = 'ticket';
2311
    }
2312
2313
    return $moduledirforclass;
2314
}
2315
2316
/*
2317
 * Return 2 hexa code randomly
2318
 *
2319
 * @param	$min	int	Between 0 and 255
2320
 * @param	$max	int	Between 0 and 255
2321
 * @return String
2322
 */
2323
function random_color_part($min=0,$max=255)
2324
{
2325
    return str_pad( dechex( mt_rand( $min, $max) ), 2, '0', STR_PAD_LEFT);
2326
}
2327
2328
/*
2329
 * Return hexadecimal color randomly
2330
 *
2331
 * @param	$min	int	Between 0 and 255
2332
 * @param	$max	int	Between 0 and 255
2333
 * @return String
2334
 */
2335
function random_color($min=0, $max=255)
2336
{
2337
    return random_color_part($min, $max) . random_color_part($min, $max) . random_color_part($min, $max);
2338
}
2339
}
2340