Passed
Push — master ( 3cffbe...0f9140 )
by Alxarafe
23:50
created

AlDolUtils2::get_next_value()   F

Complexity

Conditions 112
Paths > 20000

Size

Total Lines 456
Code Lines 273

Duplication

Lines 0
Ratio 0 %

Importance

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

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