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
        [email protected]($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 alxarafe
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 alxarafe
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+!*(),;?&=\$_.-]+)[email protected])";
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 alxarafe
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 alxarafe
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}-{[email protected]}';
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 alxarafe
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='{�