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

AlDolUtils2::check_value()   F

Complexity

Conditions 25
Paths 1140

Size

Total Lines 99
Code Lines 45

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 25
eloc 45
nop 2
dl 0
loc 99
rs 0
c 0
b 0
f 0
nc 1140

How to fix   Long Method    Complexity   

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:

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
		{