Issues (992)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  Header Injection
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

class/pcltar.lib.php (2 issues)

1
<?php
2
3
// --------------------------------------------------------------------------------
4
// PhpConcept Library - Tar Module 1.3.1
5
// --------------------------------------------------------------------------------
6
// License GNU/GPL - Vincent Blavet - January 2003
7
// http://www.phpconcept.net
8
// --------------------------------------------------------------------------------
9
//
10
// Presentation :
11
//   PclTar is a library that allow you to create a GNU TAR + GNU ZIP archive,
12
//   to add files or directories, to extract all the archive or a part of it.
13
//   So far tests show that the files generated by PclTar are readable by
14
//   gzip tools and WinZip application.
15
//
16
// Description :
17
//   See readme.txt (English & Français) and http://www.phpconcept.net
18
//
19
// Warning :
20
//   This library and the associated files are non commercial, non professional
21
//   work.
22
//   It should not have unexpected results. However if any damage is caused by
23
//   this software the author can not be responsible.
24
//   The use of this software is at the risk of the user.
25
//
26
// --------------------------------------------------------------------------------
27
28
// ----- Look for double include
29
if (!defined('PCL_TAR')) {
30
    define('PCL_TAR', 1);
31
32
    // ----- Configuration variable
33
    // Theses values may be changed by the user of PclTar library
34
    if (!isset($g_pcltar_lib_dir)) {
35
        $g_pcltar_lib_dir = 'lib';
36
    }
37
38
    // ----- Error codes
39
    //   -1 : Unable to open file in binary write mode
40
    //   -2 : Unable to open file in binary read mode
41
    //   -3 : Invalid parameters
42
    //   -4 : File does not exist
43
    //   -5 : Filename is too long (max. 99)
44
    //   -6 : Not a valid tar file
45
    //   -7 : Invalid extracted file size
46
    //   -8 : Unable to create directory
47
    //   -9 : Invalid archive extension
48
    //  -10 : Invalid archive format
49
    //  -11 : Unable to delete file (unlink)
50
    //  -12 : Unable to rename file (rename)
51
    //  -13 : Invalid header checksum
52
53
    // --------------------------------------------------------------------------------
54
    // ***** UNDER THIS LINE NOTHING NEEDS TO BE MODIFIED *****
55
    // --------------------------------------------------------------------------------
56
57
    // ----- Global variables
58
    $g_pcltar_version = '1.3.1';
59
60
    // ----- Include other libraries
61
    // This library should be called by each script before the include of PhpZip
62
    // Library in order to limit the potential 'lib' directory path problem.
63
    if (!defined('PCLERROR_LIB')) {
64
        //        include $g_pcltar_lib_dir . '/pclerror.lib.php';
65
        require __DIR__ . '/pclerror.lib.php';
66
    }
67
    if (!defined('PCLTRACE_LIB')) {
68
        //        include $g_pcltar_lib_dir . '/pcltrace.lib.php';
69
        require __DIR__ . '/pcltrace.lib.php';
70
    }
71
72
    // --------------------------------------------------------------------------------
73
    // Function : PclTarCreate()
74
    // Description :
75
    //   Creates a new archive with name $p_tarname containing the files and/or
76
    //   directories indicated in $p_list. If the tar filename extension is
77
    //   ".tar", the file will not be compressed. If it is ".tar.gz" or ".tgz"
78
    //   it will be a gzip compressed tar archive.
79
    //   If you want to use an other extension, you must indicate the mode in
80
    //   $p_mode ("tar" or "tgz").
81
    //   $p_add_dir and $p_remove_dir give you the ability to store a path
82
    //   which is not the real path of the files.
83
    // Parameters :
84
    //   $p_tarname : Name of an existing tar file
85
    //   $p_filelist : An array containing file or directory names, or
86
    //                 a string containing one filename or directory name, or
87
    //                 a string containing a list of filenames and/or directory
88
    //                 names separated by spaces.
89
    //   $p_mode : "tar" for normal tar archive, "tgz" for gzipped tar archive,
90
    //             if $p_mode is not specified, it will be determined by the extension.
91
    //   $p_add_dir : Path to add in the filename path archived
92
    //   $p_remove_dir : Path to remove in the filename path archived
93
    // Return Values :
94
    //   1 on success, or an error code (see table at the beginning).
95
    // --------------------------------------------------------------------------------
96
    /**
97
     * @param        $p_tarname
98
     * @param string $p_filelist
99
     * @param string $p_mode
100
     * @param string $p_add_dir
101
     * @param string $p_remove_dir
102
     *
103
     * @return int
104
     */
105
    function PclTarCreate($p_tarname, $p_filelist = '', $p_mode = '', $p_add_dir = '', $p_remove_dir = '')
106
    {
107
        TrFctStart(__FILE__, __LINE__, 'PclTarCreate', "tar=$p_tarname, file='$p_filelist', mode=$p_mode, add_dir='$p_add_dir', remove_dir='$p_remove_dir'");
108
        $v_result = 1;
109
110
        // ----- Look for default mode
111
        if (('' == $p_mode) || (('tar' !== $p_mode) && ('tgz' !== $p_mode))) {
112
            // ----- Extract the tar format from the extension
113
            if ('' == ($p_mode = PclTarHandleExtension($p_tarname))) {
114
                // ----- Return
115
                TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
116
117
                return PclErrorCode();
118
            }
119
120
            // ----- Trace
121
            TrFctMessage(__FILE__, __LINE__, 1, "Auto mode selected : found $p_mode");
122
        }
123
124
        // ----- Look if the $p_filelist is really an array
125
        if (is_array($p_filelist)) {
126
            // ----- Call the create fct
127
            $v_result = PclTarHandleCreate($p_tarname, $p_filelist, $p_mode, $p_add_dir, $p_remove_dir);
128
        } // ----- Look if the $p_filelist is a string
129
        elseif (is_string($p_filelist)) {
130
            // ----- Create a list with the elements from the string
131
            $v_list = explode(' ', $p_filelist);
132
133
            // ----- Call the create fct
134
            $v_result = PclTarHandleCreate($p_tarname, $v_list, $p_mode, $p_add_dir, $p_remove_dir);
135
        } // ----- Invalid variable
136
        else {
137
            // ----- Error log
138
            PclErrorLog(-3, 'Invalid variable type p_filelist');
139
            $v_result = -3;
140
        }
141
142
        // ----- Return
143
        TrFctEnd(__FILE__, __LINE__, $v_result);
144
145
        return $v_result;
146
    }
147
148
    // --------------------------------------------------------------------------------
149
150
    // --------------------------------------------------------------------------------
151
    // Function : PclTarAdd()
152
    // Description :
153
    //   PLEASE DO NOT USE ANY MORE THIS FUNCTION. Use PclTarAddList().
154
    //
155
    //   This function is maintained only for compatibility reason
156
    //
157
    // Parameters :
158
    //   $p_tarname : Name of an existing tar file
159
    //   $p_filelist : An array containing file or directory names, or
160
    //                 a string containing one filename or directory name, or
161
    //                 a string containing a list of filenames and/or directory
162
    //                 names separated by spaces.
163
    // Return Values :
164
    //   1 on success,
165
    //   Or an error code (see list on top).
166
    // --------------------------------------------------------------------------------
167
    /**
168
     * @param $p_tarname
169
     * @param $p_filelist
170
     *
171
     * @return int
172
     */
173
    function PclTarAdd($p_tarname, $p_filelist)
174
    {
175
        TrFctStart(__FILE__, __LINE__, 'PclTarAdd', "tar=$p_tarname, file=$p_filelist");
176
        $v_result      = 1;
177
        $v_list_detail = [];
178
179
        // ----- Extract the tar format from the extension
180
        if ('' == ($p_mode = PclTarHandleExtension($p_tarname))) {
181
            // ----- Return
182
            TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
183
184
            return PclErrorCode();
185
        }
186
187
        // ----- Look if the $p_filelist is really an array
188
        if (is_array($p_filelist)) {
189
            // ----- Call the add fct
190
            $v_result = PclTarHandleAppend($p_tarname, $p_filelist, $p_mode, $v_list_detail, '', '');
191
        } // ----- Look if the $p_filelist is a string
192
        elseif (is_string($p_filelist)) {
193
            // ----- Create a list with the elements from the string
194
            $v_list = explode(' ', $p_filelist);
195
196
            // ----- Call the add fct
197
            $v_result = PclTarHandleAppend($p_tarname, $v_list, $p_mode, $v_list_detail, '', '');
198
        } // ----- Invalid variable
199
        else {
200
            // ----- Error log
201
            PclErrorLog(-3, 'Invalid variable type p_filelist');
202
            $v_result = -3;
203
        }
204
205
        // ----- Cleaning
206
        unset($v_list_detail);
207
208
        // ----- Return
209
        TrFctEnd(__FILE__, __LINE__, $v_result);
210
211
        return $v_result;
212
    }
213
214
    // --------------------------------------------------------------------------------
215
216
    // --------------------------------------------------------------------------------
217
    // Function : PclTarAddList()
218
    // Description :
219
    //   Add a list of files or directories ($p_filelist) in the tar archive $p_tarname.
220
    //   The list can be an array of file/directory names or a string with names
221
    //   separated by one space.
222
    //   $p_add_dir and $p_remove_dir will give the ability to memorize a path which is
223
    //   different from the real path of the file. This is usefull if you want to have PclTar
224
    //   running in any directory, and memorize relative path from an other directory.
225
    //   If $p_mode is not set it will be automatically computed from the $p_tarname
226
    //   extension (.tar, .tar.gz or .tgz).
227
    // Parameters :
228
    //   $p_tarname : Name of an existing tar file
229
    //   $p_filelist : An array containing file or directory names, or
230
    //                 a string containing one filename or directory name, or
231
    //                 a string containing a list of filenames and/or directory
232
    //                 names separated by spaces.
233
    //   $p_add_dir : Path to add in the filename path archived
234
    //   $p_remove_dir : Path to remove in the filename path archived
235
    //   $p_mode : 'tar' or 'tgz', if not set, will be determined by $p_tarname extension
236
    // Return Values :
237
    //   1 on success,
238
    //   Or an error code (see list on top).
239
    // --------------------------------------------------------------------------------
240
    /**
241
     * @param        $p_tarname
242
     * @param        $p_filelist
243
     * @param string $p_add_dir
244
     * @param string $p_remove_dir
245
     * @param string $p_mode
246
     *
247
     * @return array|int
248
     */
249
    function PclTarAddList($p_tarname, $p_filelist, $p_add_dir = '', $p_remove_dir = '', $p_mode = '')
250
    {
251
        TrFctStart(__FILE__, __LINE__, 'PclTarAddList', "tar=$p_tarname, file=$p_filelist, p_add_dir='$p_add_dir', p_remove_dir='$p_remove_dir', mode=$p_mode");
252
        $v_result      = 1;
253
        $p_list_detail = [];
254
255
        // ----- Extract the tar format from the extension
256
        if (('' == $p_mode) || (('tar' !== $p_mode) && ('tgz' !== $p_mode))) {
257
            if ('' === ($p_mode = PclTarHandleExtension($p_tarname))) {
258
                // ----- Return
259
                TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
260
261
                return PclErrorCode();
262
            }
263
        }
264
265
        // ----- Look if the $p_filelist is really an array
266
        if (is_array($p_filelist)) {
267
            // ----- Call the add fct
268
            $v_result = PclTarHandleAppend($p_tarname, $p_filelist, $p_mode, $p_list_detail, $p_add_dir, $p_remove_dir);
269
        } // ----- Look if the $p_filelist is a string
270
        elseif (is_string($p_filelist)) {
271
            // ----- Create a list with the elements from the string
272
            $v_list = explode(' ', $p_filelist);
273
274
            // ----- Call the add fct
275
            $v_result = PclTarHandleAppend($p_tarname, $v_list, $p_mode, $p_list_detail, $p_add_dir, $p_remove_dir);
276
        } // ----- Invalid variable
277
        else {
278
            // ----- Error log
279
            PclErrorLog(-3, 'Invalid variable type p_filelist');
280
            $v_result = -3;
281
        }
282
283
        // ----- Return
284
        if (1 != $v_result) {
285
            TrFctEnd(__FILE__, __LINE__, 0);
286
287
            return 0;
288
        }
289
        TrFctEnd(__FILE__, __LINE__, $p_list_detail);
290
291
        return $p_list_detail;
292
    }
293
294
    // --------------------------------------------------------------------------------
295
296
    // --------------------------------------------------------------------------------
297
    // Function : PclTarList()
298
    // Description :
299
    //   Gives the list of all the files present in the tar archive $p_tarname.
300
    //   The list is the function result, it will be 0 on error.
301
    //   Depending on the $p_tarname extension (.tar, .tar.gz or .tgz) the
302
    //   function will determine the type of the archive.
303
    // Parameters :
304
    //   $p_tarname : Name of an existing tar file
305
    //   $p_mode : 'tar' or 'tgz', if not set, will be determined by $p_tarname extension
306
    // Return Values :
307
    //  0 on error (Use PclErrorCode() and PclErrorString() for more info)
308
    //  or
309
    //  An array containing file properties. Each file properties is an array of
310
    //  properties.
311
    //  The properties (array field names) are :
312
    //    filename, size, mode, uid, gid, mtime, typeflag, status
313
    //  Exemple : $v_list = PclTarList("my.tar");
314
    //            for ($i=0; $i<count($v_list); ++$i)
315
    //              echo "Filename :'".$v_list[$i]['filename']."'<br>";
316
    // --------------------------------------------------------------------------------
317
    /**
318
     * @param        $p_tarname
319
     * @param string $p_mode
320
     *
321
     * @return array|int
322
     */
323
    function PclTarList($p_tarname, $p_mode = '')
324
    {
325
        TrFctStart(__FILE__, __LINE__, 'PclTarList', "tar=$p_tarname, mode='$p_mode'");
326
        $v_result = 1;
327
328
        // ----- Extract the tar format from the extension
329
        if (('' == $p_mode) || (('tar' !== $p_mode) && ('tgz' !== $p_mode))) {
330
            if ('' == ($p_mode = PclTarHandleExtension($p_tarname))) {
331
                // ----- Return
332
                TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
333
334
                return 0;
335
            }
336
        }
337
338
        // ----- Call the extracting fct
339
        $p_list = [];
340
        if (1 != ($v_result = PclTarHandleExtract($p_tarname, 0, $p_list, 'list', '', $p_mode, ''))) {
341
            unset($p_list);
342
            TrFctEnd(__FILE__, __LINE__, 0, PclErrorString());
343
344
            return 0;
345
        }
346
347
        // ----- Return
348
        TrFctEnd(__FILE__, __LINE__, $p_list);
349
350
        return $p_list;
351
    }
352
353
    // --------------------------------------------------------------------------------
354
355
    // --------------------------------------------------------------------------------
356
    // Function : PclTarExtract()
357
    // Description :
358
    //   Extract all the files present in the archive $p_tarname, in the directory
359
    //   $p_path. The relative path of the archived files are keep and become
360
    //   relative to $p_path.
361
    //   If a file with the same name already exists it will be replaced.
362
    //   If the path to the file does not exist, it will be created.
363
    //   Depending on the $p_tarname extension (.tar, .tar.gz or .tgz) the
364
    //   function will determine the type of the archive.
365
    // Parameters :
366
    //   $p_tarname : Name of an existing tar file.
367
    //   $p_path : Path where the files will be extracted. The files will use
368
    //             their memorized path from $p_path.
369
    //             If $p_path is "", files will be extracted in "./".
370
    //   $p_remove_path : Path to remove (from the file memorized path) while writing the
371
    //                    extracted files. If the path does not match the file path,
372
    //                    the file is extracted with its memorized path.
373
    //                    $p_path and $p_remove_path are commulative.
374
    //   $p_mode : 'tar' or 'tgz', if not set, will be determined by $p_tarname extension
375
    // Return Values :
376
    //   Same as PclTarList()
377
    // --------------------------------------------------------------------------------
378
    /**
379
     * @param        $p_tarname
380
     * @param string $p_path
381
     * @param string $p_remove_path
382
     * @param string $p_mode
383
     *
384
     * @return int
385
     */
386
    function PclTarExtract($p_tarname, $p_path = './', $p_remove_path = '', $p_mode = '')
387
    {
388
        TrFctStart(__FILE__, __LINE__, 'PclTarExtract', "tar='$p_tarname', path='$p_path', remove_path='$p_remove_path', mode='$p_mode'");
389
        $v_result = 1;
390
391
        // ----- Extract the tar format from the extension
392
        if (('' == $p_mode) || (('tar' !== $p_mode) && ('tgz' !== $p_mode))) {
393
            if ('' == ($p_mode = PclTarHandleExtension($p_tarname))) {
394
                // ----- Return
395
                TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
396
397
                return 0;
398
            }
399
        }
400
401
        // ----- Call the extracting fct
402
        if (1 != ($v_result = PclTarHandleExtract($p_tarname, 0, $p_list, 'complete', $p_path, $p_mode, $p_remove_path))) {
403
            TrFctEnd(__FILE__, __LINE__, 0, PclErrorString());
404
405
            return 0;
406
        }
407
408
        // ----- Return
409
        TrFctEnd(__FILE__, __LINE__, $p_list);
410
411
        return $p_list;
412
    }
413
414
    // --------------------------------------------------------------------------------
415
416
    // --------------------------------------------------------------------------------
417
    // Function : PclTarExtractList()
418
    // Description :
419
    //   Extract the files present in the archive $p_tarname and specified in
420
    //   $p_filelist, in the directory
421
    //   $p_path. The relative path of the archived files are keep and become
422
    //   relative to $p_path.
423
    //   If a directory is specified in the list, all the files from this directory
424
    //   will be extracted.
425
    //   If a file with the same name already exists it will be replaced.
426
    //   If the path to the file does not exist, it will be created.
427
    //   Depending on the $p_tarname extension (.tar, .tar.gz or .tgz) the
428
    //   function will determine the type of the archive.
429
    // Parameters :
430
    //   $p_tarname : Name of an existing tar file
431
    //   $p_filelist : An array containing file or directory names, or
432
    //                 a string containing one filename or directory name, or
433
    //                 a string containing a list of filenames and/or directory
434
    //                 names separated by spaces.
435
    //   $p_path : Path where the files will be extracted. The files will use
436
    //             their memorized path from $p_path.
437
    //             If $p_path is "", files will be extracted in "./".
438
    //   $p_remove_path : Path to remove (from the file memorized path) while writing the
439
    //                    extracted files. If the path does not match the file path,
440
    //                    the file is extracted with its memorized path.
441
    //                    $p_path and $p_remove_path are commulative.
442
    //   $p_mode : 'tar' or 'tgz', if not set, will be determined by $p_tarname extension
443
    // Return Values :
444
    //   Same as PclTarList()
445
    // --------------------------------------------------------------------------------
446
    /**
447
     * @param        $p_tarname
448
     * @param        $p_filelist
449
     * @param string $p_path
450
     * @param string $p_remove_path
451
     * @param string $p_mode
452
     *
453
     * @return int
454
     */
455
    function PclTarExtractList($p_tarname, $p_filelist, $p_path = './', $p_remove_path = '', $p_mode = '')
456
    {
457
        TrFctStart(__FILE__, __LINE__, 'PclTarExtractList', "tar=$p_tarname, list, path=$p_path, remove_path='$p_remove_path', mode='$p_mode'");
458
        $v_result = 1;
459
460
        // ----- Extract the tar format from the extension
461
        if (('' === $p_mode) || (('tar' !== $p_mode) && ('tgz' !== $p_mode))) {
462
            if ('' === ($p_mode = PclTarHandleExtension($p_tarname))) {
463
                // ----- Return
464
                TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
465
466
                return 0;
467
            }
468
        }
469
470
        // ----- Look if the $p_filelist is really an array
471
        if (is_array($p_filelist)) {
472
            // ----- Call the extracting fct
473
            if (1 != ($v_result = PclTarHandleExtract($p_tarname, $p_filelist, $p_list, 'partial', $p_path, $v_tar_mode, $p_remove_path))) {
474
                TrFctEnd(__FILE__, __LINE__, 0, PclErrorString());
475
476
                return 0;
477
            }
478
        } // ----- Look if the $p_filelist is a string
479
        elseif (is_string($p_filelist)) {
480
            // ----- Create a list with the elements from the string
481
            $v_list = explode(' ', $p_filelist);
482
483
            // ----- Call the extracting fct
484
            if (1 != ($v_result = PclTarHandleExtract($p_tarname, $v_list, $p_list, 'partial', $p_path, $v_tar_mode, $p_remove_path))) {
485
                TrFctEnd(__FILE__, __LINE__, 0, PclErrorString());
486
487
                return 0;
488
            }
489
        } // ----- Invalid variable
490
        else {
491
            // ----- Error log
492
            PclErrorLog(-3, 'Invalid variable type p_filelist');
493
494
            // ----- Return
495
            TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
496
497
            return 0;
498
        }
499
500
        // ----- Return
501
        TrFctEnd(__FILE__, __LINE__, $p_list);
502
503
        return $p_list;
504
    }
505
506
    // --------------------------------------------------------------------------------
507
508
    // --------------------------------------------------------------------------------
509
    // Function : PclTarExtractIndex()
510
    // Description :
511
    //   Extract the files present in the archive $p_tarname and specified at
512
    //   the indexes in $p_index, in the directory
513
    //   $p_path. The relative path of the archived files are keep and become
514
    //   relative to $p_path.
515
    //   If a directory is specified in the list, the directory only is created. All
516
    //   the file stored in this archive for this directory
517
    //   are not extracted.
518
    //   If a file with the same name already exists it will be replaced.
519
    //   If the path to the file does not exist, it will be created.
520
    //   Depending on the $p_tarname extension (.tar, .tar.gz or .tgz) the
521
    //   function will determine the type of the archive.
522
    // Parameters :
523
    //   $p_tarname : Name of an existing tar file
524
    //   $p_index : A single index (integer) or a string of indexes of files to
525
    //              extract. The form of the string is "0,4-6,8-12" with only numbers
526
    //              and '-' for range or ',' to separate ranges. No spaces or ';'
527
    //              are allowed.
528
    //   $p_path : Path where the files will be extracted. The files will use
529
    //             their memorized path from $p_path.
530
    //             If $p_path is "", files will be extracted in "./".
531
    //   $p_remove_path : Path to remove (from the file memorized path) while writing the
532
    //                    extracted files. If the path does not match the file path,
533
    //                    the file is extracted with its memorized path.
534
    //                    $p_path and $p_remove_path are commulative.
535
    //   $p_mode : 'tar' or 'tgz', if not set, will be determined by $p_tarname extension
536
    // Return Values :
537
    //   Same as PclTarList()
538
    // --------------------------------------------------------------------------------
539
    /**
540
     * @param        $p_tarname
541
     * @param        $p_index
542
     * @param string $p_path
543
     * @param string $p_remove_path
544
     * @param string $p_mode
545
     *
546
     * @return int
547
     */
548
    function PclTarExtractIndex($p_tarname, $p_index, $p_path = './', $p_remove_path = '', $p_mode = '')
549
    {
550
        TrFctStart(__FILE__, __LINE__, 'PclTarExtractIndex', "tar=$p_tarname, index='$p_index', path=$p_path, remove_path='$p_remove_path', mode='$p_mode'");
551
        $v_result = 1;
552
553
        // ----- Extract the tar format from the extension
554
        if (('' === $p_mode) || (('tar' !== $p_mode) && ('tgz' !== $p_mode))) {
555
            if ('' == ($p_mode = PclTarHandleExtension($p_tarname))) {
556
                // ----- Return
557
                TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
558
559
                return 0;
560
            }
561
        }
562
563
        // ----- Look if the $p_index is really an integer
564
        if (is_int($p_index)) {
565
            // ----- Call the extracting fct
566
            if (1 != ($v_result = PclTarHandleExtractByIndexList($p_tarname, (string)$p_index, $p_list, $p_path, $p_remove_path, $v_tar_mode))) {
567
                TrFctEnd(__FILE__, __LINE__, 0, PclErrorString());
568
569
                return 0;
570
            }
571
        } // ----- Look if the $p_filelist is a string
572
        elseif (is_string($p_index)) {
573
            // ----- Call the extracting fct
574
            if (1 != ($v_result = PclTarHandleExtractByIndexList($p_tarname, $p_index, $p_list, $p_path, $p_remove_path, $v_tar_mode))) {
575
                TrFctEnd(__FILE__, __LINE__, 0, PclErrorString());
576
577
                return 0;
578
            }
579
        } // ----- Invalid variable
580
        else {
581
            // ----- Error log
582
            PclErrorLog(-3, "Invalid variable type $p_index");
583
584
            // ----- Return
585
            TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
586
587
            return 0;
588
        }
589
590
        // ----- Return
591
        TrFctEnd(__FILE__, __LINE__, $p_list);
592
593
        return $p_list;
594
    }
595
596
    // --------------------------------------------------------------------------------
597
598
    // --------------------------------------------------------------------------------
599
    // Function : PclTarDelete()
600
    // Description :
601
    //   This function deletes from the archive $p_tarname the files which are listed
602
    //   in $p_filelist. $p_filelist can be a string with file names separated by
603
    //   spaces, or an array containing the file names.
604
    // Parameters :
605
    //   $p_tarname : Name of an existing tar file
606
    //   $p_filelist : An array or a string containing file names to remove from the
607
    //                 archive.
608
    //   $p_mode : 'tar' or 'tgz', if not set, will be determined by $p_tarname extension
609
    // Return Values :
610
    //   List of the files which are kept in the archive (same format as PclTarList())
611
    // --------------------------------------------------------------------------------
612
    /**
613
     * @param        $p_tarname
614
     * @param        $p_filelist
615
     * @param string $p_mode
616
     *
617
     * @return int
618
     */
619
    function PclTarDelete($p_tarname, $p_filelist, $p_mode = '')
620
    {
621
        TrFctStart(__FILE__, __LINE__, 'PclTarDelete', "tar='$p_tarname', list='$p_filelist', mode='$p_mode'");
622
        $v_result = 1;
623
624
        // ----- Extract the tar format from the extension
625
        if (('' === $p_mode) || (('tar' !== $p_mode) && ('tgz' !== $p_mode))) {
626
            if ('' == ($p_mode = PclTarHandleExtension($p_tarname))) {
627
                // ----- Return
628
                TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
629
630
                return 0;
631
            }
632
        }
633
634
        // ----- Look if the $p_filelist is really an array
635
        if (is_array($p_filelist)) {
636
            // ----- Call the extracting fct
637
            if (1 != ($v_result = PclTarHandleDelete($p_tarname, $p_filelist, $p_list, $p_mode))) {
638
                TrFctEnd(__FILE__, __LINE__, 0, PclErrorString());
639
640
                return 0;
641
            }
642
        } // ----- Look if the $p_filelist is a string
643
        elseif (is_string($p_filelist)) {
644
            // ----- Create a list with the elements from the string
645
            $v_list = explode(' ', $p_filelist);
646
647
            // ----- Call the extracting fct
648
            if (1 != ($v_result = PclTarHandleDelete($p_tarname, $v_list, $p_list, $p_mode))) {
649
                TrFctEnd(__FILE__, __LINE__, 0, PclErrorString());
650
651
                return 0;
652
            }
653
        } // ----- Invalid variable
654
        else {
655
            // ----- Error log
656
            PclErrorLog(-3, 'Invalid variable type p_filelist');
657
658
            // ----- Return
659
            TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
660
661
            return 0;
662
        }
663
664
        // ----- Return
665
        TrFctEnd(__FILE__, __LINE__, $p_list);
666
667
        return $p_list;
668
    }
669
670
    // --------------------------------------------------------------------------------
671
672
    // --------------------------------------------------------------------------------
673
    // Function : PclTarUpdate()
674
    // Description :
675
    //   This function updates the files in $p_filelist which are already in the
676
    //   $p_tarname archive with an older last modified date. If the file does not
677
    //   exist, it is added at the end of the archive.
678
    // Parameters :
679
    //   $p_tarname : Name of an existing tar file
680
    //   $p_filelist : An array or a string containing file names to update from the
681
    //                 archive.
682
    //   $p_mode : 'tar' or 'tgz', if not set, will be determined by $p_tarname extension
683
    // Return Values :
684
    //   List of the files contained in the archive. The field status contains
685
    //   "updated", "not_updated", "added" or "ok" for the files not concerned.
686
    // --------------------------------------------------------------------------------
687
    /**
688
     * @param        $p_tarname
689
     * @param        $p_filelist
690
     * @param string $p_mode
691
     * @param string $p_add_dir
692
     * @param string $p_remove_dir
693
     *
694
     * @return int
695
     */
696
    function PclTarUpdate($p_tarname, $p_filelist, $p_mode = '', $p_add_dir = '', $p_remove_dir = '')
697
    {
698
        TrFctStart(__FILE__, __LINE__, 'PclTarUpdate', "tar='$p_tarname', list='$p_filelist', mode='$p_mode'");
699
        $v_result = 1;
700
701
        // ----- Extract the tar format from the extension
702
        if (('' === $p_mode) || (('tar' !== $p_mode) && ('tgz' !== $p_mode))) {
703
            if ('' == ($p_mode = PclTarHandleExtension($p_tarname))) {
704
                // ----- Return
705
                TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
706
707
                return 0;
708
            }
709
        }
710
711
        // ----- Look if the $p_filelist is really an array
712
        if (is_array($p_filelist)) {
713
            // ----- Call the extracting fct
714
            if (1 != ($v_result = PclTarHandleUpdate($p_tarname, $p_filelist, $p_list, $p_mode, $p_add_dir, $p_remove_dir))) {
715
                TrFctEnd(__FILE__, __LINE__, 0, PclErrorString());
716
717
                return 0;
718
            }
719
        } // ----- Look if the $p_filelist is a string
720
        elseif (is_string($p_filelist)) {
721
            // ----- Create a list with the elements from the string
722
            $v_list = explode(' ', $p_filelist);
723
724
            // ----- Call the extracting fct
725
            if (1 != ($v_result = PclTarHandleUpdate($p_tarname, $v_list, $p_list, $p_mode, $p_add_dir, $p_remove_dir))) {
726
                TrFctEnd(__FILE__, __LINE__, 0, PclErrorString());
727
728
                return 0;
729
            }
730
        } // ----- Invalid variable
731
        else {
732
            // ----- Error log
733
            PclErrorLog(-3, 'Invalid variable type p_filelist');
734
735
            // ----- Return
736
            TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
737
738
            return 0;
739
        }
740
741
        // ----- Return
742
        TrFctEnd(__FILE__, __LINE__, $p_list);
743
744
        return $p_list;
745
    }
746
747
    // --------------------------------------------------------------------------------
748
749
    // --------------------------------------------------------------------------------
750
    // Function : PclTarMerge()
751
    // Description :
752
    //   This function add the content of $p_tarname_add at the end of $p_tarname.
753
    // Parameters :
754
    //   $p_tarname : Name of an existing tar file
755
    //   $p_tarname_add : Name of an existing tar file taht will be added at the end
756
    //                    of $p_tarname.
757
    //   $p_mode : 'tar' or 'tgz', if not set, will be determined by $p_tarname extension
758
    //   $p_mode_add : 'tar' or 'tgz', if not set, will be determined by $p_tarname_add
759
    //                 extension
760
    // Return Values :
761
    //   List of the files contained in the archive. The field status contains
762
    //   "updated", "not_updated", "added" or "ok" for the files not concerned.
763
    // --------------------------------------------------------------------------------
764
    /**
765
     * @param        $p_tarname
766
     * @param        $p_tarname_add
767
     * @param string $p_mode
768
     * @param string $p_mode_add
769
     *
770
     * @return int
771
     */
772
    function PclTarMerge($p_tarname, $p_tarname_add, $p_mode = '', $p_mode_add = '')
773
    {
774
        TrFctStart(__FILE__, __LINE__, 'PclTarMerge', "tar='$p_tarname', tar_add='$p_tarname_add', mode='$p_mode', mode_add='$p_mode_add'");
775
        $v_result = 1;
776
777
        // ----- Check the parameters
778
        if (('' == $p_tarname) || ('' == $p_tarname_add)) {
779
            // ----- Error log
780
            PclErrorLog(-3, 'Invalid empty archive name');
781
782
            // ----- Return
783
            TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
784
785
            return PclErrorCode();
786
        }
787
788
        // ----- Extract the tar format from the extension
789
        if (('' === $p_mode) || (('tar' !== $p_mode) && ('tgz' !== $p_mode))) {
790
            if ('' == ($p_mode = PclTarHandleExtension($p_tarname))) {
791
                // ----- Return
792
                TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
793
794
                return 0;
795
            }
796
        }
797
        if (('' === $p_mode_add) || (('tar' !== $p_mode_add) && ('tgz' !== $p_mode_add))) {
798
            if ('' == ($p_mode_add = PclTarHandleExtension($p_tarname_add))) {
799
                // ----- Return
800
                TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
801
802
                return 0;
803
            }
804
        }
805
806
        // ----- Clear filecache
807
        clearstatcache();
808
809
        // ----- Check the file size
810
        if ((!is_file($p_tarname)) || ((0 != (($v_size = filesize($p_tarname)) % 512)) && ('tar' === $p_mode))) {
811
            // ----- Error log
812
            if (!is_file($p_tarname)) {
813
                PclErrorLog(-4, "Archive '$p_tarname' does not exist");
814
            } else {
815
                PclErrorLog(-6, "Archive '$p_tarname' has invalid size " . filesize($p_tarname) . '(not a 512 block multiple)');
816
            }
817
818
            // ----- Return
819
            TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
820
821
            return PclErrorCode();
822
        }
823
        if ((!is_file($p_tarname_add))
824
            || ((0 != (($v_size_add = filesize($p_tarname_add)) % 512))
825
                && ('tar' === $p_mode_add))) {
826
            // ----- Error log
827
            if (!is_file($p_tarname_add)) {
828
                PclErrorLog(-4, "Archive '$p_tarname_add' does not exist");
829
            } else {
830
                PclErrorLog(-6, "Archive '$p_tarname_add' has invalid size " . filesize($p_tarname_add) . '(not a 512 block multiple)');
831
            }
832
833
            // ----- Return
834
            TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
835
836
            return PclErrorCode();
837
        }
838
839
        // ----- Look for compressed archive
840
        if ('tgz' === $p_mode) {
841
            // ----- Open the file in read mode
842
            if (0 == ($p_tar = @gzopen($p_tarname, 'rb'))) {
843
                // ----- Error log
844
                PclErrorLog(-2, "Unable to open file '$p_tarname' in binary read mode");
845
846
                // ----- Return
847
                TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
848
849
                return PclErrorCode();
850
            }
851
852
            // ----- Open a temporary file in write mode
853
            $v_temp_tarname = uniqid('pcltar-', true) . '.tmp';
854
            TrFctMessage(__FILE__, __LINE__, 2, "Creating temporary archive file $v_temp_tarname");
855
            if (0 == ($v_temp_tar = @gzopen($v_temp_tarname, 'wb'))) {
856
                // ----- Close tar file
857
                gzclose($p_tar);
858
859
                // ----- Error log
860
                PclErrorLog(-1, "Unable to open file '$v_temp_tarname' in binary write mode");
861
862
                // ----- Return
863
                TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
864
865
                return PclErrorCode();
866
            }
867
868
            // ----- Read the first 512 bytes block
869
            $v_buffer = gzread($p_tar, 512);
870
871
            // ----- Read the following blocks but not the last one
872
            if (!gzeof($p_tar)) {
873
                TrFctMessage(__FILE__, __LINE__, 3, 'More than one 512 block file');
874
                $i = 1;
875
876
                // ----- Read new 512 block and write the already read
877
                do {
878
                    // ----- Write the already read block
879
                    $v_binary_data = pack('a512', $v_buffer);
880
                    gzputs($v_temp_tar, $v_binary_data);
881
882
                    ++$i;
883
                    TrFctMessage(__FILE__, __LINE__, 3, "Reading block $i");
884
885
                    // ----- Read next block
886
                    $v_buffer = gzread($p_tar, 512);
887
                } while (!gzeof($p_tar));
888
889
                TrFctMessage(__FILE__, __LINE__, 3, "$i 512 bytes blocks");
890
            }
891
        } // ----- Look for uncompressed tar file
892
        elseif ('tar' === $p_mode) {
893
            // ----- Open the tar file
894
            if (0 == ($p_tar = fopen($p_tarname, 'r+b'))) {
895
                // ----- Error log
896
                PclErrorLog(-1, "Unable to open file '$p_tarname' in binary write mode");
897
898
                // ----- Return
899
                TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
900
901
                return PclErrorCode();
902
            }
903
904
            // ----- Go to the beginning of last block
905
            TrFctMessage(__FILE__, __LINE__, 4, 'Position before :' . ('tar' === $p_mode ? ftell($p_tar) : gztell($p_tar)));
906
            fseek($p_tar, $v_size - 512);
907
            TrFctMessage(__FILE__, __LINE__, 4, 'Position after :' . ('tar' === $p_mode ? ftell($p_tar) : gztell($p_tar)));
908
        } // ----- Look for unknown type
909
        else {
910
            // ----- Error log
911
            PclErrorLog(-3, "Invalid tar mode $p_mode");
912
913
            // ----- Return
914
            TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
915
916
            return PclErrorCode();
917
        }
918
919
        // ----- Look for type of archive to add
920
        if ('tgz' === $p_mode_add) {
921
            TrFctMessage(__FILE__, __LINE__, 4, "Opening file $p_tarname_add");
922
923
            // ----- Open the file in read mode
924
            if (0 == ($p_tar_add = @gzopen($p_tarname_add, 'rb'))) {
925
                // ----- Error log
926
                PclErrorLog(-2, "Unable to open file '$p_tarname_add' in binary read mode");
927
928
                // ----- Return
929
                TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
930
931
                return PclErrorCode();
932
            }
933
934
            // ----- Read the first 512 bytes block
935
            $v_buffer = gzread($p_tar_add, 512);
936
937
            // ----- Read the following blocks but not the last one
938
            if (!gzeof($p_tar_add)) {
939
                TrFctMessage(__FILE__, __LINE__, 3, 'More than one 512 block file');
940
                $i = 1;
941
942
                // ----- Read new 512 block and write the already read
943
                do {
944
                    // ----- Write the already read block
945
                    $v_binary_data = pack('a512', $v_buffer);
946
                    if ('tar' === $p_mode) {
947
                        fwrite($p_tar, $v_binary_data);
948
                    } else {
949
                        gzputs($v_temp_tar, $v_binary_data);
950
                    }
951
952
                    ++$i;
953
                    TrFctMessage(__FILE__, __LINE__, 3, "Reading block $i");
954
955
                    // ----- Read next block
956
                    $v_buffer = gzread($p_tar_add, 512);
957
                } while (!gzeof($p_tar_add));
958
959
                TrFctMessage(__FILE__, __LINE__, 3, "$i 512 bytes blocks");
960
            }
961
962
            // ----- Close the files
963
            gzclose($p_tar_add);
964
        } // ----- Look for uncompressed tar file
965
        elseif ('tar' === $p_mode) {
966
            // ----- Open the file in read mode
967
            if (0 == ($p_tar_add = @fopen($p_tarname_add, 'rb'))) {
968
                // ----- Error log
969
                PclErrorLog(-2, "Unable to open file '$p_tarname_add' in binary read mode");
970
971
                // ----- Return
972
                TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
973
974
                return PclErrorCode();
975
            }
976
977
            // ----- Read the first 512 bytes block
978
            $v_buffer = fread($p_tar_add, 512);
979
980
            // ----- Read the following blocks but not the last one
981
            if (!feof($p_tar_add)) {
982
                TrFctMessage(__FILE__, __LINE__, 3, 'More than one 512 block file');
983
                $i = 1;
984
985
                // ----- Read new 512 block and write the already read
986
                do {
987
                    // ----- Write the already read block
988
                    $v_binary_data = pack('a512', (string)$v_buffer);
989
                    if ('tar' === $p_mode) {
990
                        fwrite($p_tar, $v_binary_data);
991
                    } else {
992
                        gzputs($v_temp_tar, $v_binary_data);
993
                    }
994
995
                    ++$i;
996
                    TrFctMessage(__FILE__, __LINE__, 3, "Reading block $i");
997
998
                    // ----- Read next block
999
                    $v_buffer = fread($p_tar_add, 512);
1000
                } while (!feof($p_tar_add));
1001
1002
                TrFctMessage(__FILE__, __LINE__, 3, "$i 512 bytes blocks");
1003
            }
1004
1005
            // ----- Close the files
1006
            fclose($p_tar_add);
1007
        }
1008
1009
        // ----- Call the footer of the tar archive
1010
        $v_result = PclTarHandleFooter($p_tar, $p_mode);
1011
1012
        // ----- Look for closing compressed archive
1013
        if ('tgz' === $p_mode) {
1014
            // ----- Close the files
1015
            gzclose($p_tar);
1016
            gzclose($v_temp_tar);
1017
1018
            // ----- Unlink tar file
1019
            if (!@unlink($p_tarname)) {
1020
                // ----- Error log
1021
                PclErrorLog(-11, "Error while deleting archive name $p_tarname");
1022
            }
1023
1024
            // ----- Rename tar file
1025
            if (!@rename($v_temp_tarname, $p_tarname)) {
1026
                // ----- Error log
1027
                PclErrorLog(-12, "Error while renaming temporary file $v_temp_tarname to archive name $p_tarname");
1028
1029
                // ----- Return
1030
                TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
1031
1032
                return PclErrorCode();
1033
            }
1034
1035
            // ----- Return
1036
            TrFctEnd(__FILE__, __LINE__, $v_result);
1037
1038
            return $v_result;
1039
        } // ----- Look for closing uncompressed tar file
1040
        elseif ('tar' === $p_mode) {
1041
            // ----- Close the tarfile
1042
            fclose($p_tar);
1043
        }
1044
1045
        // ----- Return
1046
        TrFctEnd(__FILE__, __LINE__, $v_result);
1047
1048
        return $v_result;
1049
    }
1050
1051
    // --------------------------------------------------------------------------------
1052
1053
    // --------------------------------------------------------------------------------
1054
    // ***** UNDER THIS LINE ARE DEFINED PRIVATE INTERNAL FUNCTIONS *****
1055
    // *****                                                        *****
1056
    // *****       THESES FUNCTIONS MUST NOT BE USED DIRECTLY       *****
1057
    // --------------------------------------------------------------------------------
1058
1059
    // --------------------------------------------------------------------------------
1060
    // Function : PclTarHandleCreate()
1061
    // Description :
1062
    // Parameters :
1063
    //   $p_tarname : Name of the tar file
1064
    //   $p_list : An array containing the file or directory names to add in the tar
1065
    //   $p_mode : "tar" for normal tar archive, "tgz" for gzipped tar archive
1066
    // Return Values :
1067
    // --------------------------------------------------------------------------------
1068
    /**
1069
     * @param        $p_tarname
1070
     * @param        $p_list
1071
     * @param        $p_mode
1072
     * @param string $p_add_dir
1073
     * @param string $p_remove_dir
1074
     *
1075
     * @return int
1076
     */
1077
    function PclTarHandleCreate($p_tarname, $p_list, $p_mode, $p_add_dir = '', $p_remove_dir = '')
1078
    {
1079
        TrFctStart(__FILE__, __LINE__, 'PclTarHandleCreate', "tar=$p_tarname, list, mode=$p_mode, add_dir='$p_add_dir', remove_dir='$p_remove_dir'");
1080
        $v_result      = 1;
1081
        $v_list_detail = [];
1082
1083
        // ----- Check the parameters
1084
        if (('' === $p_tarname) || (('tar' !== $p_mode) && ('tgz' !== $p_mode))) {
1085
            // ----- Error log
1086
            if ('' == $p_tarname) {
1087
                PclErrorLog(-3, 'Invalid empty archive name');
1088
            } else {
1089
                PclErrorLog(-3, "Unknown mode '$p_mode'");
1090
            }
1091
1092
            // ----- Return
1093
            TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
1094
1095
            return PclErrorCode();
1096
        }
1097
1098
        // ----- Look for tar file
1099
        if ('tar' === $p_mode) {
1100
            // ----- Open the tar file
1101
            if (0 == ($p_tar = fopen($p_tarname, 'wb'))) {
1102
                // ----- Error log
1103
                PclErrorLog(-1, "Unable to open file [$p_tarname] in binary write mode");
1104
1105
                // ----- Return
1106
                TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
1107
1108
                return PclErrorCode();
1109
            }
1110
1111
            // ----- Call the adding fct inside the tar
1112
            if (1 == ($v_result = PclTarHandleAddList($p_tar, $p_list, $p_mode, $v_list_detail, $p_add_dir, $p_remove_dir))) {
1113
                // ----- Call the footer of the tar archive
1114
                $v_result = PclTarHandleFooter($p_tar, $p_mode);
1115
            }
1116
1117
            // ----- Close the tarfile
1118
            fclose($p_tar);
1119
        } // ----- Look for tgz file
1120
        else {
1121
            // ----- Open the tar file
1122
            if (0 == ($p_tar = @gzopen($p_tarname, 'wb'))) {
1123
                // ----- Error log
1124
                PclErrorLog(-1, "Unable to open file [$p_tarname] in binary write mode");
1125
1126
                // ----- Return
1127
                TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
1128
1129
                return PclErrorCode();
1130
            }
1131
1132
            // ----- Call the adding fct inside the tar
1133
            if (1 == ($v_result = PclTarHandleAddList($p_tar, $p_list, $p_mode, $v_list_detail, $p_add_dir, $p_remove_dir))) {
1134
                // ----- Call the footer of the tar archive
1135
                $v_result = PclTarHandleFooter($p_tar, $p_mode);
1136
            }
1137
1138
            // ----- Close the tarfile
1139
            gzclose($p_tar);
1140
        }
1141
1142
        // ----- Return
1143
        TrFctEnd(__FILE__, __LINE__, $v_result);
1144
1145
        return $v_result;
1146
    }
1147
1148
    // --------------------------------------------------------------------------------
1149
1150
    // --------------------------------------------------------------------------------
1151
    // Function : PclTarHandleAppend()
1152
    // Description :
1153
    // Parameters :
1154
    //   $p_tarname : Name of the tar file
1155
    //   $p_list : An array containing the file or directory names to add in the tar
1156
    //   $p_mode : "tar" for normal tar archive, "tgz" for gzipped tar archive
1157
    // Return Values :
1158
    // --------------------------------------------------------------------------------
1159
    /**
1160
     * @param $p_tarname
1161
     * @param $p_list
1162
     * @param $p_mode
1163
     * @param $p_list_detail
1164
     * @param $p_add_dir
1165
     * @param $p_remove_dir
1166
     *
1167
     * @return int
1168
     */
1169
    function PclTarHandleAppend($p_tarname, $p_list, $p_mode, &$p_list_detail, $p_add_dir, $p_remove_dir)
1170
    {
1171
        TrFctStart(__FILE__, __LINE__, 'PclTarHandleAppend', "tar=$p_tarname, list, mode=$p_mode");
1172
        $v_result = 1;
1173
1174
        // ----- Check the parameters
1175
        if ('' == $p_tarname) {
1176
            // ----- Error log
1177
            PclErrorLog(-3, 'Invalid empty archive name');
1178
1179
            // ----- Return
1180
            TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
1181
1182
            return PclErrorCode();
1183
        }
1184
1185
        clearstatcache();
1186
1187
        // ----- Check the file size
1188
        if ((!is_file($p_tarname)) || ((0 != (($v_size = filesize($p_tarname)) % 512)) && ('tar' === $p_mode))) {
1189
            // ----- Error log
1190
            if (!is_file($p_tarname)) {
1191
                PclErrorLog(-4, "Archive '$p_tarname' does not exist");
1192
            } else {
1193
                PclErrorLog(-6, "Archive '$p_tarname' has invalid size " . filesize($p_tarname) . '(not a 512 block multiple)');
1194
            }
1195
1196
            // ----- Return
1197
            TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
1198
1199
            return PclErrorCode();
1200
        }
1201
1202
        // ----- Look for compressed archive
1203
        if ('tgz' === $p_mode) {
1204
            // ----- Open the file in read mode
1205
            if (0 == ($p_tar = @gzopen($p_tarname, 'rb'))) {
1206
                // ----- Error log
1207
                PclErrorLog(-2, "Unable to open file '$p_tarname' in binary read mode");
1208
1209
                // ----- Return
1210
                TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
1211
1212
                return PclErrorCode();
1213
            }
1214
1215
            // ----- Open a temporary file in write mode
1216
            $v_temp_tarname = uniqid('pcltar-', true) . '.tmp';
1217
            TrFctMessage(__FILE__, __LINE__, 2, "Creating temporary archive file $v_temp_tarname");
1218
            if (0 == ($v_temp_tar = @gzopen($v_temp_tarname, 'wb'))) {
1219
                // ----- Close tar file
1220
                gzclose($p_tar);
1221
1222
                // ----- Error log
1223
                PclErrorLog(-1, "Unable to open file '$v_temp_tarname' in binary write mode");
1224
1225
                // ----- Return
1226
                TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
1227
1228
                return PclErrorCode();
1229
            }
1230
1231
            // ----- Read the first 512 bytes block
1232
            $v_buffer = gzread($p_tar, 512);
1233
1234
            // ----- Read the following blocks but not the last one
1235
            if (!gzeof($p_tar)) {
1236
                TrFctMessage(__FILE__, __LINE__, 3, 'More than one 512 block file');
1237
                $i = 1;
1238
1239
                // ----- Read new 512 block and write the already read
1240
                do {
1241
                    // ----- Write the already read block
1242
                    $v_binary_data = pack('a512', $v_buffer);
1243
                    gzputs($v_temp_tar, $v_binary_data);
1244
1245
                    ++$i;
1246
                    TrFctMessage(__FILE__, __LINE__, 3, "Reading block $i");
1247
1248
                    // ----- Read next block
1249
                    $v_buffer = gzread($p_tar, 512);
1250
                } while (!gzeof($p_tar));
1251
1252
                TrFctMessage(__FILE__, __LINE__, 3, "$i 512 bytes blocks");
1253
            }
1254
1255
            // ----- Call the adding fct inside the tar
1256
            if (1 == ($v_result = PclTarHandleAddList($v_temp_tar, $p_list, $p_mode, $p_list_detail, $p_add_dir, $p_remove_dir))) {
1257
                // ----- Call the footer of the tar archive
1258
                $v_result = PclTarHandleFooter($v_temp_tar, $p_mode);
1259
            }
1260
1261
            // ----- Close the files
1262
            gzclose($p_tar);
1263
            gzclose($v_temp_tar);
1264
1265
            // ----- Unlink tar file
1266
            if (!@unlink($p_tarname)) {
1267
                // ----- Error log
1268
                PclErrorLog(-11, "Error while deleting archive name $p_tarname");
1269
            }
1270
1271
            // ----- Rename tar file
1272
            if (!@rename($v_temp_tarname, $p_tarname)) {
1273
                // ----- Error log
1274
                PclErrorLog(-12, "Error while renaming temporary file $v_temp_tarname to archive name $p_tarname");
1275
1276
                // ----- Return
1277
                TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
1278
1279
                return PclErrorCode();
1280
            }
1281
1282
            // ----- Return
1283
            TrFctEnd(__FILE__, __LINE__, $v_result);
1284
1285
            return $v_result;
1286
        } // ----- Look for uncompressed tar file
1287
        elseif ('tar' === $p_mode) {
1288
            // ----- Open the tar file
1289
            if (0 == ($p_tar = fopen($p_tarname, 'r+b'))) {
1290
                // ----- Error log
1291
                PclErrorLog(-1, "Unable to open file '$p_tarname' in binary write mode");
1292
1293
                // ----- Return
1294
                TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
1295
1296
                return PclErrorCode();
1297
            }
1298
1299
            // ----- Go to the beginning of last block
1300
            TrFctMessage(__FILE__, __LINE__, 4, 'Position before :' . ('tar' === $p_mode ? ftell($p_tar) : gztell($p_tar)));
1301
            fseek($p_tar, $v_size - 512);
1302
            TrFctMessage(__FILE__, __LINE__, 4, 'Position after :' . ('tar' === $p_mode ? ftell($p_tar) : gztell($p_tar)));
1303
1304
            // ----- Call the adding fct inside the tar
1305
            if (1 == ($v_result = PclTarHandleAddList($p_tar, $p_list, $p_mode, $p_list_detail, $p_add_dir, $p_remove_dir))) {
1306
                // ----- Call the footer of the tar archive
1307
                $v_result = PclTarHandleFooter($p_tar, $p_mode);
1308
            }
1309
1310
            // ----- Close the tarfile
1311
            fclose($p_tar);
1312
        } // ----- Look for unknown type
1313
        else {
1314
            // ----- Error log
1315
            PclErrorLog(-3, "Invalid tar mode $p_mode");
1316
1317
            // ----- Return
1318
            TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
1319
1320
            return PclErrorCode();
1321
        }
1322
1323
        // ----- Return
1324
        TrFctEnd(__FILE__, __LINE__, $v_result);
1325
1326
        return $v_result;
1327
    }
1328
1329
    // --------------------------------------------------------------------------------
1330
1331
    // --------------------------------------------------------------------------------
1332
    // Function : PclTarHandleAddList()
1333
    // Description :
1334
    //   $p_add_dir and $p_remove_dir will give the ability to memorize a path which is
1335
    //   different from the real path of the file. This is usefull if you want to have PclTar
1336
    //   running in any directory, and memorize relative path from an other directory.
1337
    // Parameters :
1338
    //   $p_tar : File descriptor of the tar archive
1339
    //   $p_list : An array containing the file or directory names to add in the tar
1340
    //   $p_mode : "tar" for normal tar archive, "tgz" for gzipped tar archive
1341
    //   $p_list_detail : list of added files with their properties (specially the status field)
1342
    //   $p_add_dir : Path to add in the filename path archived
1343
    //   $p_remove_dir : Path to remove in the filename path archived
1344
    // Return Values :
1345
    // --------------------------------------------------------------------------------
1346
    /**
1347
     * @param $p_tar
1348
     * @param $p_list
1349
     * @param $p_mode
1350
     * @param $p_list_detail
1351
     * @param $p_add_dir
1352
     * @param $p_remove_dir
1353
     *
1354
     * @return int
1355
     */
1356
    function PclTarHandleAddList($p_tar, $p_list, $p_mode, &$p_list_detail, $p_add_dir, $p_remove_dir)
1357
    {
1358
        TrFctStart(__FILE__, __LINE__, 'PclTarHandleAddList', "tar='$p_tar', list, mode='$p_mode', add_dir='$p_add_dir', remove_dir='$p_remove_dir'");
1359
        $v_result = 1;
1360
        $v_header = [];
1361
1362
        // ----- Recuperate the current number of elt in list
1363
        $v_nb = count($p_list_detail);
1364
1365
        // ----- Check the parameters
1366
        if (0 == $p_tar) {
1367
            // ----- Error log
1368
            PclErrorLog(-3, 'Invalid file descriptor in file ' . __FILE__ . ', line ' . __LINE__);
1369
1370
            // ----- Return
1371
            TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
1372
1373
            return PclErrorCode();
1374
        }
1375
1376
        // ----- Check the arguments
1377
        if (0 == count($p_list)) {
1378
            // ----- Error log
1379
            PclErrorLog(-3, 'Invalid file list parameter (invalid or empty list)');
1380
1381
            // ----- Return
1382
            TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
1383
1384
            return PclErrorCode();
1385
        }
1386
1387
        // ----- Loop on the files
1388
        for ($j = 0; ($j < count($p_list)) && (1 == $v_result); ++$j) {
1389
            // ----- Recuperate the filename
1390
            $p_filename = $p_list[$j];
1391
1392
            TrFctMessage(__FILE__, __LINE__, 2, "Looking for file [$p_filename]");
1393
1394
            // ----- Skip empty file names
1395
            if ('' == $p_filename) {
1396
                TrFctMessage(__FILE__, __LINE__, 2, 'Skip empty filename');
1397
                continue;
1398
            }
1399
1400
            // ----- Check the filename
1401
            if (!is_dir($p_filename)) {
1402
                // ----- Error log
1403
                TrFctMessage(__FILE__, __LINE__, 2, "File '$p_filename' does not exists");
1404
                PclErrorLog(-4, "File '$p_filename' does not exists");
1405
1406
                // ----- Return
1407
                TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
1408
1409
                return PclErrorCode();
1410
            }
1411
1412
            // ----- Check the path length
1413
            if (mb_strlen($p_filename) > 99) {
1414
                // ----- Error log
1415
                PclErrorLog(-5, "File name is too long (max. 99) : '$p_filename'");
1416
1417
                // ----- Return
1418
                TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
1419
1420
                return PclErrorCode();
1421
            }
1422
1423
            TrFctMessage(__FILE__, __LINE__, 4, 'File position before header =' . ('tar' === $p_mode ? ftell($p_tar) : gztell($p_tar)));
1424
1425
            // ----- Add the file
1426
            if (1 != ($v_result = PclTarHandleAddFile($p_tar, $p_filename, $p_mode, $v_header, $p_add_dir, $p_remove_dir))) {
1427
                // ----- Return status
1428
                TrFctEnd(__FILE__, __LINE__, $v_result);
1429
1430
                return $v_result;
1431
            }
1432
1433
            // ----- Store the file infos
1434
            $p_list_detail[$v_nb++] = $v_header;
1435
1436
            // ----- Look for directory
1437
            if (is_dir($p_filename)) {
1438
                TrFctMessage(__FILE__, __LINE__, 2, "$p_filename is a directory");
1439
1440
                // ----- Look for path
1441
                if ('.' !== $p_filename) {
1442
                    $v_path = $p_filename . '/';
1443
                } else {
1444
                    $v_path = '';
1445
                }
1446
1447
                // ----- Read the directory for files and sub-directories
1448
                $p_hdir  = opendir($p_filename);
1449
                $p_hitem = readdir($p_hdir); // '.' directory
1450
                $p_hitem = readdir($p_hdir); // '..' directory
1451
                while (false !== ($p_hitem = readdir($p_hdir))) {
1452
                    // ----- Look for a file
1453
                    if (is_file($v_path . $p_hitem)) {
1454
                        TrFctMessage(__FILE__, __LINE__, 4, "Add the file '" . $v_path . $p_hitem . "'");
1455
1456
                        // ----- Add the file
1457
                        if (1 != ($v_result = PclTarHandleAddFile($p_tar, $v_path . $p_hitem, $p_mode, $v_header, $p_add_dir, $p_remove_dir))) {
1458
                            // ----- Return status
1459
                            TrFctEnd(__FILE__, __LINE__, $v_result);
1460
1461
                            return $v_result;
1462
                        }
1463
1464
                        // ----- Store the file infos
1465
                        $p_list_detail[$v_nb++] = $v_header;
1466
                    } // ----- Recursive call to PclTarHandleAddFile()
1467
                    else {
1468
                        TrFctMessage(__FILE__, __LINE__, 4, "'" . $v_path . $p_hitem . "' is a directory");
1469
1470
                        // ----- Need an array as parameter
1471
                        $p_temp_list[0] = $v_path . $p_hitem;
1472
                        $v_result       = PclTarHandleAddList($p_tar, $p_temp_list, $p_mode, $p_list_detail, $p_add_dir, $p_remove_dir);
1473
                    }
1474
                }
1475
1476
                // ----- Free memory for the recursive loop
1477
                unset($p_temp_list, $p_hdir, $p_hitem);
1478
            } else {
1479
                TrFctMessage(__FILE__, __LINE__, 4, 'File position after blocks =' . ('tar' === $p_mode ? ftell($p_tar) : gztell($p_tar)));
1480
            }
1481
        }
1482
1483
        // ----- Return
1484
        TrFctEnd(__FILE__, __LINE__, $v_result);
1485
1486
        return $v_result;
1487
    }
1488
1489
    // --------------------------------------------------------------------------------
1490
1491
    // --------------------------------------------------------------------------------
1492
    // Function : PclTarHandleAddFile()
1493
    // Description :
1494
    // Parameters :
1495
    // Return Values :
1496
    // --------------------------------------------------------------------------------
1497
    /**
1498
     * @param $p_tar
1499
     * @param $p_filename
1500
     * @param $p_mode
1501
     * @param $p_header
1502
     * @param $p_add_dir
1503
     * @param $p_remove_dir
1504
     *
1505
     * @return int
1506
     */
1507
    function PclTarHandleAddFile($p_tar, $p_filename, $p_mode, &$p_header, $p_add_dir, $p_remove_dir)
1508
    {
1509
        TrFctStart(__FILE__, __LINE__, 'PclTarHandleAddFile', "tar='$p_tar', filename='$p_filename', p_mode='$p_mode', add_dir='$p_add_dir', remove_dir='$p_remove_dir'");
1510
        $v_result = 1;
1511
1512
        // ----- Check the parameters
1513
        if (0 == $p_tar) {
1514
            // ----- Error log
1515
            PclErrorLog(-3, 'Invalid file descriptor in file ' . __FILE__ . ', line ' . __LINE__);
1516
1517
            // ----- Return
1518
            TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
1519
1520
            return PclErrorCode();
1521
        }
1522
1523
        // ----- Skip empty file names
1524
        if ('' == $p_filename) {
1525
            // ----- Error log
1526
            PclErrorLog(-3, 'Invalid file list parameter (invalid or empty list)');
1527
1528
            // ----- Return
1529
            TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
1530
1531
            return PclErrorCode();
1532
        }
1533
1534
        // ----- Calculate the stored filename
1535
        $v_stored_filename = $p_filename;
1536
        if ('' != $p_remove_dir) {
1537
            if ('/' !== mb_substr($p_remove_dir, -1)) {
1538
                $p_remove_dir .= '/';
1539
            }
1540
1541
            if (('./' === mb_substr($p_filename, 0, 2)) || ('./' === mb_substr($p_remove_dir, 0, 2))) {
1542
                if (('./' === mb_substr($p_filename, 0, 2)) && ('./' !== mb_substr($p_remove_dir, 0, 2))) {
1543
                    $p_remove_dir = './' . $p_remove_dir;
1544
                }
1545
                if (('./' !== mb_substr($p_filename, 0, 2)) && ('./' === mb_substr($p_remove_dir, 0, 2))) {
1546
                    $p_remove_dir = mb_substr($p_remove_dir, 2);
1547
                }
1548
            }
1549
1550
            if (mb_substr($p_filename, 0, mb_strlen($p_remove_dir)) == $p_remove_dir) {
1551
                $v_stored_filename = mb_substr($p_filename, mb_strlen($p_remove_dir));
1552
                TrFctMessage(__FILE__, __LINE__, 3, "Remove path '$p_remove_dir' in file '$p_filename' = '$v_stored_filename'");
1553
            }
1554
        }
1555
        if ('' != $p_add_dir) {
1556
            if ('/' === mb_substr($p_add_dir, -1)) {
1557
                $v_stored_filename = $p_add_dir . $v_stored_filename;
1558
            } else {
1559
                $v_stored_filename = $p_add_dir . '/' . $v_stored_filename;
1560
            }
1561
            TrFctMessage(__FILE__, __LINE__, 3, "Add path '$p_add_dir' in file '$p_filename' = '$v_stored_filename'");
1562
        }
1563
1564
        // ----- Check the path length
1565
        if (mb_strlen($v_stored_filename) > 99) {
1566
            // ----- Error log
1567
            PclErrorLog(-5, "Stored file name is too long (max. 99) : '$v_stored_filename'");
1568
1569
            // ----- Return
1570
            TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
1571
1572
            return PclErrorCode();
1573
        }
1574
1575
        // ----- Look for a file
1576
        if (is_file($p_filename)) {
1577
            // ----- Open the source file
1578
            if (0 == ($v_file = fopen($p_filename, 'rb'))) {
1579
                // ----- Error log
1580
                PclErrorLog(-2, "Unable to open file '$p_filename' in binary read mode");
1581
1582
                // ----- Return
1583
                TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
1584
1585
                return PclErrorCode();
1586
            }
1587
1588
            // ----- Call the header generation
1589
            if (1 != ($v_result = PclTarHandleHeader($p_tar, $p_filename, $p_mode, $p_header, $v_stored_filename))) {
1590
                // ----- Return status
1591
                TrFctEnd(__FILE__, __LINE__, $v_result);
1592
1593
                return $v_result;
1594
            }
1595
1596
            TrFctMessage(__FILE__, __LINE__, 4, 'File position after header =' . ('tar' === $p_mode ? ftell($p_tar) : gztell($p_tar)));
1597
1598
            // ----- Read the file by 512 octets blocks
1599
            $i = 0;
1600
            while ('' != ($v_buffer = fread($v_file, 512))) {
1601
                $v_binary_data = pack('a512', (string)$v_buffer);
1602
                if ('tar' === $p_mode) {
1603
                    fwrite($p_tar, $v_binary_data);
1604
                } else {
1605
                    gzputs($p_tar, $v_binary_data);
1606
                }
1607
                ++$i;
1608
            }
1609
            TrFctMessage(__FILE__, __LINE__, 2, "$i 512 bytes blocks");
1610
1611
            // ----- Close the file
1612
            fclose($v_file);
1613
1614
            TrFctMessage(__FILE__, __LINE__, 4, 'File position after blocks =' . ('tar' === $p_mode ? ftell($p_tar) : gztell($p_tar)));
1615
        } // ----- Look for a directory
1616
        else {
1617
            // ----- Call the header generation
1618
            if (1 != ($v_result = PclTarHandleHeader($p_tar, $p_filename, $p_mode, $p_header, $v_stored_filename))) {
1619
                // ----- Return status
1620
                TrFctEnd(__FILE__, __LINE__, $v_result);
1621
1622
                return $v_result;
1623
            }
1624
1625
            TrFctMessage(__FILE__, __LINE__, 4, 'File position after header =' . ('tar' === $p_mode ? ftell($p_tar) : gztell($p_tar)));
1626
        }
1627
1628
        // ----- Return
1629
        TrFctEnd(__FILE__, __LINE__, $v_result);
1630
1631
        return $v_result;
1632
    }
1633
1634
    // --------------------------------------------------------------------------------
1635
1636
    // --------------------------------------------------------------------------------
1637
    // Function : PclTarHandleHeader()
1638
    // Description :
1639
    //   This function creates in the TAR $p_tar, the TAR header for the file
1640
    //   $p_filename.
1641
    //
1642
    //   1. The informations needed to compose the header are recuperated and formatted
1643
    //   2. Two binary strings are composed for the first part of the header, before
1644
    //      and after checksum field.
1645
    //   3. The checksum is calculated from the two binary strings
1646
    //   4. The header is write in the tar file (first binary string, binary string
1647
    //      for checksum and last binary string).
1648
    // Parameters :
1649
    //   $p_tar : a valid file descriptor, opened in write mode,
1650
    //   $p_filename : The name of the file the header is for,
1651
    //   $p_mode : The mode of the archive ("tar" or "tgz").
1652
    //   $p_header : A pointer to a array where will be set the file properties
1653
    // Return Values :
1654
    // --------------------------------------------------------------------------------
1655
    /**
1656
     * @param $p_tar
1657
     * @param $p_filename
1658
     * @param $p_mode
1659
     * @param $p_header
1660
     * @param $p_stored_filename
1661
     *
1662
     * @return int
1663
     */
1664
    function PclTarHandleHeader($p_tar, $p_filename, $p_mode, &$p_header, $p_stored_filename)
1665
    {
1666
        TrFctStart(__FILE__, __LINE__, 'PclTarHandleHeader', "tar=$p_tar, file='$p_filename', mode='$p_mode', stored_filename='$p_stored_filename'");
1667
        $v_result = 1;
1668
1669
        // ----- Check the parameters
1670
        if ((0 == $p_tar) || ('' == $p_filename)) {
1671
            // ----- Error log
1672
            PclErrorLog(-3, 'Invalid file descriptor in file ' . __FILE__ . ', line ' . __LINE__);
1673
1674
            // ----- Return
1675
            TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
1676
1677
            return PclErrorCode();
1678
        }
1679
1680
        // ----- Filename (reduce the path of stored name)
1681
        if ('' == $p_stored_filename) {
1682
            $p_stored_filename = $p_filename;
1683
        }
1684
        $v_reduce_filename = PclTarHandlePathReduction($p_stored_filename);
1685
        TrFctMessage(__FILE__, __LINE__, 2, "Filename (reduced) '$v_reduce_filename', strlen " . mb_strlen($v_reduce_filename));
1686
1687
        // ----- Get file info
1688
        $v_info = stat($p_filename);
1689
        $v_uid  = sprintf('%6s ', decoct($v_info[4]));
1690
        $v_gid  = sprintf('%6s ', decoct($v_info[5]));
1691
        TrFctMessage(__FILE__, __LINE__, 3, "uid=$v_uid, gid=$v_gid");
1692
        $v_perms = sprintf('%6s ', decoct(fileperms($p_filename)));
1693
        TrFctMessage(__FILE__, __LINE__, 3, "file permissions $v_perms");
1694
1695
        // ----- File mtime
1696
        $v_mtime_data = filemtime($p_filename);
1697
        TrFctMessage(__FILE__, __LINE__, 2, "File mtime : $v_mtime_data");
1698
        $v_mtime = sprintf('%11s', decoct($v_mtime_data));
1699
1700
        // ----- File typeflag
1701
        // '0' or '\0' is the code for regular file
1702
        // '5' is directory
1703
        if (is_dir($p_filename)) {
1704
            $v_typeflag = '5';
1705
            $v_size     = 0;
1706
        } else {
1707
            $v_typeflag = '';
1708
1709
            // ----- Get the file size
1710
            clearstatcache();
1711
            $v_size = filesize($p_filename);
1712
        }
1713
1714
        TrFctMessage(__FILE__, __LINE__, 2, "File size : $v_size");
1715
        $v_size = sprintf('%11s ', decoct($v_size));
1716
1717
        TrFctMessage(__FILE__, __LINE__, 2, "File typeflag : $v_typeflag");
1718
1719
        // ----- Linkname
1720
        $v_linkname = '';
1721
1722
        // ----- Magic
1723
        $v_magic = '';
1724
1725
        // ----- Version
1726
        $v_version = '';
1727
1728
        // ----- uname
1729
        $v_uname = '';
1730
1731
        // ----- gname
1732
        $v_gname = '';
1733
1734
        // ----- devmajor
1735
        $v_devmajor = '';
1736
1737
        // ----- devminor
1738
        $v_devminor = '';
1739
1740
        // ----- prefix
1741
        $v_prefix = '';
1742
1743
        // ----- Compose the binary string of the header in two parts arround the checksum position
1744
        $v_binary_data_first = pack('a100a8a8a8a12A12', $v_reduce_filename, $v_perms, $v_uid, $v_gid, $v_size, $v_mtime);
1745
        $v_binary_data_last  = pack('a1a100a6a2a32a32a8a8a155a12', $v_typeflag, $v_linkname, $v_magic, $v_version, $v_uname, $v_gname, $v_devmajor, $v_devminor, $v_prefix, '');
1746
1747
        // ----- Calculate the checksum
1748
        $v_checksum = 0;
1749
        // ..... First part of the header
1750
        for ($i = 0; $i < 148; ++$i) {
1751
            $v_checksum += ord(mb_substr($v_binary_data_first, $i, 1));
1752
        }
1753
        // ..... Ignore the checksum value and replace it by ' ' (space)
1754
        for ($i = 148; $i < 156; ++$i) {
1755
            $v_checksum += ord(' ');
1756
        }
1757
        // ..... Last part of the header
1758
        for ($i = 156, $j = 0; $i < 512; ++$i, ++$j) {
1759
            $v_checksum += ord(mb_substr($v_binary_data_last, $j, 1));
1760
        }
1761
        TrFctMessage(__FILE__, __LINE__, 3, "Calculated checksum : $v_checksum");
1762
1763
        // ----- Write the first 148 bytes of the header in the archive
1764
        if ('tar' === $p_mode) {
1765
            fwrite($p_tar, $v_binary_data_first, 148);
1766
        } else {
1767
            gzputs($p_tar, $v_binary_data_first, 148);
1768
        }
1769
1770
        // ----- Write the calculated checksum
1771
        $v_checksum    = sprintf('%6s ', decoct($v_checksum));
1772
        $v_binary_data = pack('a8', $v_checksum);
1773
        if ('tar' === $p_mode) {
1774
            fwrite($p_tar, $v_binary_data, 8);
1775
        } else {
1776
            gzputs($p_tar, $v_binary_data, 8);
1777
        }
1778
1779
        // ----- Write the last 356 bytes of the header in the archive
1780
        if ('tar' === $p_mode) {
1781
            fwrite($p_tar, $v_binary_data_last, 356);
1782
        } else {
1783
            gzputs($p_tar, $v_binary_data_last, 356);
1784
        }
1785
1786
        // ----- Set the properties in the header "structure"
1787
        $p_header['filename'] = $v_reduce_filename;
1788
        $p_header['mode']     = $v_perms;
1789
        $p_header['uid']      = $v_uid;
1790
        $p_header['gid']      = $v_gid;
1791
        $p_header['size']     = $v_size;
1792
        $p_header['mtime']    = $v_mtime;
1793
        $p_header['typeflag'] = $v_typeflag;
1794
        $p_header['status']   = 'added';
1795
1796
        // ----- Return
1797
        TrFctEnd(__FILE__, __LINE__, $v_result);
1798
1799
        return $v_result;
1800
    }
1801
1802
    // --------------------------------------------------------------------------------
1803
1804
    // --------------------------------------------------------------------------------
1805
    // Function : PclTarHandleFooter()
1806
    // Description :
1807
    // Parameters :
1808
    // Return Values :
1809
    // --------------------------------------------------------------------------------
1810
    /**
1811
     * @param $p_tar
1812
     * @param $p_mode
1813
     *
1814
     * @return int
1815
     */
1816
    function PclTarHandleFooter($p_tar, $p_mode)
1817
    {
1818
        TrFctStart(__FILE__, __LINE__, 'PclTarHandleFooter', "tar='$p_tar', p_mode=$p_mode");
1819
        $v_result = 1;
1820
1821
        // ----- Write the last 0 filled block for end of archive
1822
        $v_binary_data = pack('a512', '');
1823
        if ('tar' === $p_mode) {
1824
            fwrite($p_tar, $v_binary_data);
1825
        } else {
1826
            gzputs($p_tar, $v_binary_data);
1827
        }
1828
1829
        // ----- Return
1830
        TrFctEnd(__FILE__, __LINE__, $v_result);
1831
1832
        return $v_result;
1833
    }
1834
1835
    // --------------------------------------------------------------------------------
1836
1837
    // --------------------------------------------------------------------------------
1838
    // Function : PclTarHandleExtract()
1839
    // Description :
1840
    // Parameters :
1841
    //   $p_tarname : Filename of the tar (or tgz) archive
1842
    //   $p_file_list : An array which contains the list of files to extract, this
1843
    //                  array may be empty when $p_mode is 'complete'
1844
    //   $p_list_detail : An array where will be placed the properties of  each extracted/listed file
1845
    //   $p_mode : 'complete' will extract all files from the archive,
1846
    //             'partial' will look for files in $p_file_list
1847
    //             'list' will only list the files from the archive without any extract
1848
    //   $p_path : Path to add while writing the extracted files
1849
    //   $p_tar_mode : 'tar' for GNU TAR archive, 'tgz' for compressed archive
1850
    //   $p_remove_path : Path to remove (from the file memorized path) while writing the
1851
    //                    extracted files. If the path does not match the file path,
1852
    //                    the file is extracted with its memorized path.
1853
    //                    $p_remove_path does not apply to 'list' mode.
1854
    //                    $p_path and $p_remove_path are commulative.
1855
    // Return Values :
1856
    // --------------------------------------------------------------------------------
1857
    /**
1858
     * @param $p_tarname
1859
     * @param $p_file_list
1860
     * @param $p_list_detail
1861
     * @param $p_mode
1862
     * @param $p_path
1863
     * @param $p_tar_mode
1864
     * @param $p_remove_path
1865
     *
1866
     * @return int
1867
     */
1868
    function PclTarHandleExtract(
1869
        $p_tarname,
1870
        $p_file_list,
1871
        &$p_list_detail,
1872
        $p_mode,
1873
        $p_path,
1874
        $p_tar_mode,
1875
        $p_remove_path
1876
    ) {
1877
        TrFctStart(__FILE__, __LINE__, 'PclTarHandleExtract', "archive='$p_tarname', list, mode=$p_mode, path=$p_path, tar_mode=$p_tar_mode, remove_path='$p_remove_path'");
1878
        $v_result      = 1;
1879
        $v_nb          = 0;
1880
        $v_extract_all = true;
1881
        $v_listing     = false;
1882
1883
        // ----- Check the path
1884
        //if (($p_path == "") || ((substr($p_path, 0, 1) != "/") && (substr($p_path, 0, 3) != "../")))
1885
        if ('' == $p_path) {
1886
            $p_path = './' . $p_path;
1887
        }
1888
1889
        // ----- Look for path to remove format (should end by /)
1890
        if (('' != $p_remove_path) && ('/' !== mb_substr($p_remove_path, -1))) {
1891
            $p_remove_path .= '/';
1892
        }
1893
        $p_remove_path_size = mb_strlen($p_remove_path);
1894
1895
        // ----- Study the mode
1896
        switch ($p_mode) {
1897
            case 'complete':
1898
                // ----- Flag extract of all files
1899
1900
                $v_extract_all = true;
1901
                $v_listing     = false;
1902
1903
                break;
1904
            case 'partial':
1905
                // ----- Flag extract of specific files
1906
1907
                $v_extract_all = false;
1908
                $v_listing     = false;
1909
1910
                break;
1911
            case 'list':
1912
                // ----- Flag list of all files
1913
1914
                $v_extract_all = false;
1915
                $v_listing     = true;
1916
1917
                break;
1918
            default:
1919
                // ----- Error log
1920
1921
                PclErrorLog(-3, "Invalid extract mode ($p_mode)");
1922
1923
                // ----- Return
1924
                TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
1925
1926
                return PclErrorCode();
1927
        }
1928
1929
        // ----- Open the tar file
1930
        if ('tar' === $p_tar_mode) {
1931
            TrFctMessage(__FILE__, __LINE__, 3, 'Open file in binary read mode');
1932
            $v_tar = fopen($p_tarname, 'rb');
1933
        } else {
1934
            TrFctMessage(__FILE__, __LINE__, 3, 'Open file in gzip binary read mode');
1935
            $v_tar = @gzopen($p_tarname, 'rb');
1936
        }
1937
1938
        // ----- Check that the archive is open
1939
        if (0 == $v_tar) {
1940
            // ----- Error log
1941
            PclErrorLog(-2, "Unable to open archive '$p_tarname' in binary read mode");
1942
1943
            // ----- Return
1944
            TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
1945
1946
            return PclErrorCode();
1947
        }
1948
1949
        // ----- Read the blocks
1950
        while (!($v_end_of_file = ('tar' === $p_tar_mode ? feof($v_tar) : gzeof($v_tar)))) {
1951
            TrFctMessage(__FILE__, __LINE__, 3, 'Looking for next header ...');
1952
1953
            // ----- Clear cache of file infos
1954
            clearstatcache();
1955
1956
            // ----- Reset extract tag
1957
            $v_extract_file       = false;
1958
            $v_extraction_stopped = 0;
1959
1960
            // ----- Read the 512 bytes header
1961
            if ('tar' === $p_tar_mode) {
1962
                $v_binary_data = fread($v_tar, 512);
1963
            } else {
1964
                $v_binary_data = gzread($v_tar, 512);
1965
            }
1966
1967
            // ----- Read the header properties
1968
            if (1 != ($v_result = PclTarHandleReadHeader($v_binary_data, $v_header))) {
1969
                // ----- Close the archive file
1970
                if ('tar' === $p_tar_mode) {
1971
                    fclose($v_tar);
1972
                } else {
1973
                    gzclose($v_tar);
1974
                }
1975
1976
                // ----- Return
1977
                TrFctEnd(__FILE__, __LINE__, $v_result);
1978
1979
                return $v_result;
1980
            }
1981
1982
            // ----- Look for empty blocks to skip
1983
            if ('' == $v_header['filename']) {
1984
                TrFctMessage(__FILE__, __LINE__, 2, 'Empty block found. End of archive?');
1985
                continue;
1986
            }
1987
1988
            TrFctMessage(__FILE__, __LINE__, 2, "Found file '" . $v_header['filename'] . "', size '" . $v_header['size'] . "'");
1989
1990
            // ----- Look for partial extract
1991
            if ((!$v_extract_all) && is_array($p_file_list)) {
1992
                TrFctMessage(__FILE__, __LINE__, 2, 'Look if the file ' . $v_header['filename'] . ' need to be extracted');
1993
1994
                // ----- By default no unzip if the file is not found
1995
                $v_extract_file = false;
1996
1997
                // ----- Look into the file list
1998
                foreach ($p_file_list as $i => $iValue) {
1999
                    TrFctMessage(__FILE__, __LINE__, 2, 'Compare archived file ' . $v_header['filename'] . " from asked list file '" . $iValue . "'");
2000
2001
                    // ----- Look if it is a directory
2002
                    if ('/' === mb_substr($p_file_list[$i], -1)) {
2003
                        TrFctMessage(__FILE__, __LINE__, 3, 'Compare file ' . $v_header['filename'] . " with directory '$p_file_list[$i]'");
2004
2005
                        // ----- Look if the directory is in the filename path
2006
                        if ((mb_strlen($v_header['filename']) > mb_strlen($p_file_list[$i]))
2007
                            && (mb_substr($v_header['filename'], 0, mb_strlen($p_file_list[$i])) == $iValue)) {
2008
                            // ----- The file is in the directory, so extract it
2009
                            TrFctMessage(__FILE__, __LINE__, 2, 'File ' . $v_header['filename'] . " is in directory '$p_file_list[$i]' : extract it");
2010
                            $v_extract_file = true;
2011
2012
                            // ----- End of loop
2013
                            break;
2014
                        }
2015
                    } // ----- It is a file, so compare the file names
2016
                    elseif ($iValue == $v_header['filename']) {
2017
                        // ----- File found
2018
                        TrFctMessage(__FILE__, __LINE__, 2, 'File ' . $v_header['filename'] . ' should be extracted');
2019
                        $v_extract_file = true;
2020
2021
                        // ----- End of loop
2022
                        break;
2023
                    }
2024
                }
2025
2026
                // ----- Trace
2027
                if (!$v_extract_file) {
2028
                    TrFctMessage(__FILE__, __LINE__, 2, 'File ' . $v_header['filename'] . ' should not be extracted');
2029
                }
2030
            } else {
2031
                // ----- All files need to be extracted
2032
                $v_extract_file = true;
2033
            }
2034
2035
            // ----- Look if this file need to be extracted
2036
            if ($v_extract_file && (!$v_listing)) {
2037
                // ----- Look for path to remove
2038
                if (('' != $p_remove_path)
2039
                    && (mb_substr($v_header['filename'], 0, $p_remove_path_size) == $p_remove_path)) {
2040
                    TrFctMessage(__FILE__, __LINE__, 3, "Found path '$p_remove_path' to remove in file " . $v_header['filename'] . '');
2041
                    // ----- Remove the path
2042
                    $v_header['filename'] = mb_substr($v_header['filename'], $p_remove_path_size);
2043
                    TrFctMessage(__FILE__, __LINE__, 3, 'Reslting file is ' . $v_header['filename'] . '');
2044
                }
2045
2046
                // ----- Add the path to the file
2047
                if (('./' !== $p_path) && ('/' !== $p_path)) {
2048
                    // ----- Look for the path end '/'
2049
                    while ('/' === mb_substr($p_path, -1)) {
2050
                        TrFctMessage(__FILE__, __LINE__, 3, "Destination path [$p_path] ends by '/'");
2051
                        $p_path = mb_substr($p_path, 0, -1);
2052
                        TrFctMessage(__FILE__, __LINE__, 3, "Modified to [$p_path]");
2053
                    }
2054
2055
                    // ----- Add the path
2056
                    if ('/' === mb_substr($v_header['filename'], 0, 1)) {
2057
                        $v_header['filename'] = $p_path . $v_header['filename'];
2058
                    } else {
2059
                        $v_header['filename'] = $p_path . '/' . $v_header['filename'];
2060
                    }
2061
                }
2062
2063
                // ----- Trace
2064
                TrFctMessage(__FILE__, __LINE__, 2, 'Extracting file (with path) ' . $v_header['filename'] . ", size '" . $v_header['size'] . "'");
2065
2066
                // ----- Check that the file does not exists
2067
                if (file_exists($v_header['filename'])) {
2068
                    TrFctMessage(__FILE__, __LINE__, 2, 'File ' . $v_header['filename'] . ' already exists');
2069
2070
                    // ----- Look if file is a directory
2071
                    if (is_dir($v_header['filename'])) {
2072
                        TrFctMessage(__FILE__, __LINE__, 2, 'Existing file ' . $v_header['filename'] . ' is a directory');
2073
2074
                        // ----- Change the file status
2075
                        $v_header['status'] = 'already_a_directory';
2076
2077
                        // ----- Skip the extract
2078
                        $v_extraction_stopped = 1;
2079
                        $v_extract_file       = 0;
2080
                    } // ----- Look if file is write protected
2081
                    elseif (!is_writable($v_header['filename'])) {
2082
                        TrFctMessage(__FILE__, __LINE__, 2, 'Existing file ' . $v_header['filename'] . ' is write protected');
2083
2084
                        // ----- Change the file status
2085
                        $v_header['status'] = 'write_protected';
2086
2087
                        // ----- Skip the extract
2088
                        $v_extraction_stopped = 1;
2089
                        $v_extract_file       = 0;
2090
                    }
2091
                    // ----- Look if the extracted file is older
2092
                    /*else if (filemtime($v_header['filename']) > $v_header['mtime']) {
2093
            TrFctMessage(__FILE__, __LINE__, 2, "Existing file ".$v_header['filename']." is newer (".date("l dS of F Y h:i:s A", filemtime($v_header['filename'])).") than the extracted file (".date("l dS of F Y h:i:s A", $v_header['mtime']).")");
2094
2095
            // ----- Change the file status
2096
            $v_header['status'] = "newer_exist";
2097
2098
            // ----- Skip the extract
2099
            $v_extraction_stopped = 1;
2100
            $v_extract_file = 0;
2101
          }*/
2102
                } // ----- Check the directory availability and create it if necessary
2103
                else {
2104
                    if ('5' == $v_header['typeflag']) {
2105
                        $v_dir_to_check = $v_header['filename'];
2106
                    } elseif (false === mb_strpos($v_header['filename'], '/')) {
2107
                        $v_dir_to_check = '';
2108
                    } else {
2109
                        $v_dir_to_check = \dirname($v_header['filename']);
2110
                    }
2111
2112
                    if (1 != ($v_result = PclTarHandlerDirCheck($v_dir_to_check))) {
2113
                        TrFctMessage(__FILE__, __LINE__, 2, 'Unable to create path for ' . $v_header['filename'] . '');
2114
2115
                        // ----- Change the file status
2116
                        $v_header['status'] = 'path_creation_fail';
2117
2118
                        // ----- Skip the extract
2119
                        $v_extraction_stopped = 1;
2120
                        $v_extract_file       = 0;
2121
                    }
2122
                }
2123
2124
                // ----- Do the extraction
2125
                if ($v_extract_file && ('5' != $v_header['typeflag'])) {
2126
                    // ----- Open the destination file in write mode
2127
                    if (0 == ($v_dest_file = @fopen($v_header['filename'], 'wb'))) {
2128
                        TrFctMessage(__FILE__, __LINE__, 2, 'Error while opening ' . $v_header['filename'] . ' in write binary mode');
2129
2130
                        // ----- Change the file status
2131
                        $v_header['status'] = 'write_error';
2132
2133
                        // ----- Jump to next file
2134
                        TrFctMessage(__FILE__, __LINE__, 2, 'Jump to next file');
2135
                        if ('tar' === $p_tar_mode) {
2136
                            fseek($v_tar, ftell($v_tar) + (ceil($v_header['size'] / 512) * 512));
2137
                        } else {
2138
                            gzseek($v_tar, gztell($v_tar) + (ceil($v_header['size'] / 512) * 512));
2139
                        }
2140
                    } else {
2141
                        TrFctMessage(__FILE__, __LINE__, 2, 'Start extraction of ' . $v_header['filename'] . '');
2142
2143
                        // ----- Read data
2144
                        $n = floor($v_header['size'] / 512);
2145
                        for ($i = 0; $i < $n; ++$i) {
2146
                            TrFctMessage(__FILE__, __LINE__, 3, 'Read complete 512 bytes block number ' . ($i + 1));
2147
                            if ('tar' === $p_tar_mode) {
2148
                                $v_content = fread($v_tar, 512);
2149
                            } else {
2150
                                $v_content = gzread($v_tar, 512);
2151
                            }
2152
                            fwrite($v_dest_file, $v_content, 512);
2153
                        }
2154
                        if (0 != ($v_header['size'] % 512)) {
2155
                            TrFctMessage(__FILE__, __LINE__, 3, 'Read last ' . ($v_header['size'] % 512) . ' bytes in a 512 block');
2156
                            if ('tar' === $p_tar_mode) {
2157
                                $v_content = fread($v_tar, 512);
2158
                            } else {
2159
                                $v_content = gzread($v_tar, 512);
2160
                            }
2161
                            fwrite($v_dest_file, $v_content, $v_header['size'] % 512);
2162
                        }
2163
2164
                        // ----- Close the destination file
2165
                        fclose($v_dest_file);
2166
2167
                        // ----- Change the file mode, mtime
2168
                        touch($v_header['filename'], $v_header['mtime']);
2169
                        //chmod($v_header['filename'], decoct($v_header['mode']));
2170
                    }
2171
2172
                    // ----- Check the file size
2173
                    clearstatcache();
2174
                    if (filesize($v_header['filename']) != $v_header['size']) {
2175
                        // ----- Close the archive file
2176
                        if ('tar' === $p_tar_mode) {
2177
                            fclose($v_tar);
2178
                        } else {
2179
                            gzclose($v_tar);
2180
                        }
2181
2182
                        // ----- Error log
2183
                        PclErrorLog(-7, 'Extracted file ' . $v_header['filename'] . " does not have the correct file size '" . filesize($v_filename) . "' ('" . $v_header['size'] . "' expected). Archive may be corrupted.");
2184
2185
                        // ----- Return
2186
                        TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
2187
2188
                        return PclErrorCode();
2189
                    }
2190
2191
                    // ----- Trace
2192
                    TrFctMessage(__FILE__, __LINE__, 2, 'Extraction done');
2193
                } else {
2194
                    TrFctMessage(__FILE__, __LINE__, 2, 'Extraction of file ' . $v_header['filename'] . ' skipped.');
2195
2196
                    // ----- Jump to next file
2197
                    TrFctMessage(__FILE__, __LINE__, 2, 'Jump to next file');
2198
                    if ('tar' === $p_tar_mode) {
2199
                        fseek($v_tar, ftell($v_tar) + (ceil($v_header['size'] / 512) * 512));
2200
                    } else {
2201
                        gzseek($v_tar, gztell($v_tar) + (ceil($v_header['size'] / 512) * 512));
2202
                    }
2203
                }
2204
            } // ----- Look for file that is not to be unzipped
2205
            else {
2206
                // ----- Trace
2207
                TrFctMessage(__FILE__, __LINE__, 2, 'Jump file ' . $v_header['filename'] . '');
2208
                TrFctMessage(__FILE__, __LINE__, 4, 'Position avant jump [' . ('tar' === $p_tar_mode ? ftell($v_tar) : gztell($v_tar)) . ']');
2209
2210
                // ----- Jump to next file
2211
                if ('tar' === $p_tar_mode) {
2212
                    fseek($v_tar, ('tar' === $p_tar_mode ? ftell($v_tar) : gztell($v_tar)) + (ceil($v_header['size'] / 512) * 512));
2213
                } else {
2214
                    gzseek($v_tar, gztell($v_tar) + (ceil($v_header['size'] / 512) * 512));
2215
                }
2216
2217
                TrFctMessage(__FILE__, __LINE__, 4, 'Position après jump [' . ('tar' === $p_tar_mode ? ftell($v_tar) : gztell($v_tar)) . ']');
2218
            }
2219
2220
            if ('tar' === $p_tar_mode) {
2221
                $v_end_of_file = feof($v_tar);
2222
            } else {
2223
                $v_end_of_file = gzeof($v_tar);
2224
            }
2225
2226
            // ----- File name and properties are logged if listing mode or file is extracted
2227
            if ($v_listing || $v_extract_file || $v_extraction_stopped) {
2228
                TrFctMessage(__FILE__, __LINE__, 2, 'Memorize info about file ' . $v_header['filename'] . '');
2229
2230
                // ----- Log extracted files
2231
                if (($v_file_dir = \dirname($v_header['filename'])) == $v_header['filename']) {
2232
                    $v_file_dir = '';
2233
                }
2234
                if (('/' === mb_substr($v_header['filename'], 0, 1)) && ('' == $v_file_dir)) {
2235
                    $v_file_dir = '/';
2236
                }
2237
2238
                // ----- Add the array describing the file into the list
2239
                $p_list_detail[$v_nb] = $v_header;
2240
2241
                // ----- Increment
2242
                ++$v_nb;
2243
            }
2244
        }
2245
2246
        // ----- Close the tarfile
2247
        if ('tar' === $p_tar_mode) {
2248
            fclose($v_tar);
2249
        } else {
2250
            gzclose($v_tar);
2251
        }
2252
2253
        // ----- Return
2254
        TrFctEnd(__FILE__, __LINE__, $v_result);
2255
2256
        return $v_result;
2257
    }
2258
2259
    // --------------------------------------------------------------------------------
2260
2261
    // --------------------------------------------------------------------------------
2262
    // Function : PclTarHandleExtractByIndexList()
2263
    // Description :
2264
    //   Extract the files which are at the indexes specified. If the 'file' at the
2265
    //   index is a directory, the directory only is created, not all the files stored
2266
    //   for that directory.
2267
    // Parameters :
2268
    //   $p_index_string : String of indexes of files to extract. The form of the
2269
    //                     string is "0,4-6,8-12" with only numbers and '-' for
2270
    //                     for range, and ',' to separate ranges. No spaces or ';'
2271
    //                     are allowed.
2272
    // Return Values :
2273
    // --------------------------------------------------------------------------------
2274
    /**
2275
     * @param $p_tarname
2276
     * @param $p_index_string
2277
     * @param $p_list_detail
2278
     * @param $p_path
2279
     * @param $p_remove_path
2280
     * @param $p_tar_mode
2281
     *
2282
     * @return int
2283
     */
2284
    function PclTarHandleExtractByIndexList(
2285
        $p_tarname,
2286
        $p_index_string,
2287
        &$p_list_detail,
2288
        $p_path,
2289
        $p_remove_path,
2290
        $p_tar_mode
2291
    ) {
2292
        TrFctStart(__FILE__, __LINE__, 'PclTarHandleExtractByIndexList', "archive='$p_tarname', index_string='$p_index_string', list, path=$p_path, remove_path='$p_remove_path', tar_mode=$p_tar_mode");
2293
        $v_result = 1;
2294
        $v_nb     = 0;
2295
2296
        // ----- TBC : I should check the string by a regexp
2297
2298
        // ----- Check the path
2299
        if (('' == $p_path)
2300
            || (('/' !== mb_substr($p_path, 0, 1)) && ('../' !== mb_substr($p_path, 0, 3))
2301
                && ('./' !== mb_substr($p_path, 0, 2)))) {
2302
            $p_path = './' . $p_path;
2303
        }
2304
2305
        // ----- Look for path to remove format (should end by /)
2306
        if (('' != $p_remove_path) && ('/' !== mb_substr($p_remove_path, -1))) {
2307
            $p_remove_path .= '/';
2308
        }
2309
        $p_remove_path_size = mb_strlen($p_remove_path);
2310
2311
        // ----- Open the tar file
2312
        if ('tar' === $p_tar_mode) {
2313
            TrFctMessage(__FILE__, __LINE__, 3, 'Open file in binary read mode');
2314
            $v_tar = @fopen($p_tarname, 'rb');
2315
        } else {
2316
            TrFctMessage(__FILE__, __LINE__, 3, 'Open file in gzip binary read mode');
2317
            $v_tar = @gzopen($p_tarname, 'rb');
2318
        }
2319
2320
        // ----- Check that the archive is open
2321
        if (0 == $v_tar) {
2322
            // ----- Error log
2323
            PclErrorLog(-2, "Unable to open archive '$p_tarname' in binary read mode");
2324
2325
            // ----- Return
2326
            TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
2327
2328
            return PclErrorCode();
2329
        }
2330
2331
        // ----- Manipulate the index list
2332
        $v_list = explode(',', $p_index_string);
2333
        sort($v_list);
2334
2335
        // ----- Loop on the index list
2336
        $v_index = 0;
2337
        for ($i = 0; ($i < count($v_list)) && $v_result; ++$i) {
2338
            TrFctMessage(__FILE__, __LINE__, 3, "Looking for index part '$v_list[$i]'");
2339
2340
            // ----- Extract range
2341
            $v_index_list      = explode('-', $v_list[$i]);
2342
            $v_size_index_list = count($v_index_list);
2343
            if (1 == $v_size_index_list) {
2344
                TrFctMessage(__FILE__, __LINE__, 3, "Only one index '$v_index_list[0]'");
2345
2346
                // ----- Do the extraction
2347
                $v_result = PclTarHandleExtractByIndex($v_tar, $v_index, $v_index_list[0], $v_index_list[0], $p_list_detail, $p_path, $p_remove_path, $p_tar_mode);
2348
            } elseif (2 == $v_size_index_list) {
2349
                TrFctMessage(__FILE__, __LINE__, 3, "Two indexes '$v_index_list[0]' and '$v_index_list[1]'");
2350
2351
                // ----- Do the extraction
2352
                $v_result = PclTarHandleExtractByIndex($v_tar, $v_index, $v_index_list[0], $v_index_list[1], $p_list_detail, $p_path, $p_remove_path, $p_tar_mode);
2353
            }
2354
        }
2355
2356
        // ----- Close the tarfile
2357
        if ('tar' === $p_tar_mode) {
2358
            fclose($v_tar);
2359
        } else {
2360
            gzclose($v_tar);
2361
        }
2362
2363
        // ----- Return
2364
        TrFctEnd(__FILE__, __LINE__, $v_result);
2365
2366
        return $v_result;
2367
    }
2368
2369
    // --------------------------------------------------------------------------------
2370
2371
    // --------------------------------------------------------------------------------
2372
    // Function : PclTarHandleExtractByIndex()
2373
    // Description :
2374
    // Parameters :
2375
    // Return Values :
2376
    // --------------------------------------------------------------------------------
2377
    /**
2378
     * @param $p_tar
2379
     * @param $p_index_current
2380
     * @param $p_index_start
2381
     * @param $p_index_stop
2382
     * @param $p_list_detail
2383
     * @param $p_path
2384
     * @param $p_remove_path
2385
     * @param $p_tar_mode
2386
     *
2387
     * @return int
2388
     */
2389
    function PclTarHandleExtractByIndex(
2390
        $p_tar,
2391
        &$p_index_current,
2392
        $p_index_start,
2393
        $p_index_stop,
2394
        &$p_list_detail,
2395
        $p_path,
2396
        $p_remove_path,
2397
        $p_tar_mode
2398
    ) {
2399
        TrFctStart(__FILE__, __LINE__, 'PclTarHandleExtractByIndex', "archive_descr='$p_tar', index_current=$p_index_current, index_start='$p_index_start', index_stop='$p_index_stop', list, path=$p_path, remove_path='$p_remove_path', tar_mode=$p_tar_mode");
2400
        $v_result = 1;
2401
        $v_nb     = 0;
2402
2403
        // TBC : I should replace all $v_tar by $p_tar in this function ....
2404
        $v_tar = $p_tar;
2405
2406
        // ----- Look the number of elements already in $p_list_detail
2407
        $v_nb = count($p_list_detail);
2408
2409
        // ----- Read the blocks
2410
        while (!($v_end_of_file = ('tar' === $p_tar_mode ? feof($v_tar) : gzeof($v_tar)))) {
2411
            TrFctMessage(__FILE__, __LINE__, 3, 'Looking for next file ...');
2412
            TrFctMessage(__FILE__, __LINE__, 3, "Index current=$p_index_current, range=[$p_index_start, $p_index_stop])");
2413
2414
            if ($p_index_current > $p_index_stop) {
2415
                TrFctMessage(__FILE__, __LINE__, 2, 'Stop extraction, past stop index');
2416
                break;
2417
            }
2418
2419
            // ----- Clear cache of file infos
2420
            clearstatcache();
2421
2422
            // ----- Reset extract tag
2423
            $v_extract_file       = false;
2424
            $v_extraction_stopped = 0;
2425
2426
            // ----- Read the 512 bytes header
2427
            if ('tar' === $p_tar_mode) {
2428
                $v_binary_data = fread($v_tar, 512);
2429
            } else {
2430
                $v_binary_data = gzread($v_tar, 512);
2431
            }
2432
2433
            // ----- Read the header properties
2434
            if (1 != ($v_result = PclTarHandleReadHeader($v_binary_data, $v_header))) {
2435
                // ----- Return
2436
                TrFctEnd(__FILE__, __LINE__, $v_result);
2437
2438
                return $v_result;
2439
            }
2440
2441
            // ----- Look for empty blocks to skip
2442
            if ('' == $v_header['filename']) {
2443
                TrFctMessage(__FILE__, __LINE__, 2, 'Empty block found. End of archive?');
2444
                continue;
2445
            }
2446
2447
            TrFctMessage(__FILE__, __LINE__, 2, 'Found file ' . $v_header['filename'] . ", size '" . $v_header['size'] . "'");
2448
2449
            // ----- Look if file is in the range to be extracted
2450
            if (($p_index_current >= $p_index_start) && ($p_index_current <= $p_index_stop)) {
2451
                TrFctMessage(__FILE__, __LINE__, 2, 'File ' . $v_header['filename'] . ' is in the range to be extracted');
2452
                $v_extract_file = true;
2453
            } else {
2454
                TrFctMessage(__FILE__, __LINE__, 2, 'File ' . $v_header['filename'] . ' is out of the range');
2455
                $v_extract_file = false;
2456
            }
2457
2458
            // ----- Look if this file need to be extracted
2459
            if ($v_extract_file) {
2460
                if (1 != ($v_result = PclTarHandleExtractFile($v_tar, $v_header, $p_path, $p_remove_path, $p_tar_mode))) {
2461
                    // ----- Return
2462
                    TrFctEnd(__FILE__, __LINE__, $v_result);
2463
2464
                    return $v_result;
2465
                }
2466
            } // ----- Look for file that is not to be extracted
2467
            else {
2468
                // ----- Trace
2469
                TrFctMessage(__FILE__, __LINE__, 2, 'Jump file ' . $v_header['filename'] . '');
2470
                TrFctMessage(__FILE__, __LINE__, 4, 'Position avant jump [' . ('tar' === $p_tar_mode ? ftell($v_tar) : gztell($v_tar)) . ']');
2471
2472
                // ----- Jump to next file
2473
                if ('tar' === $p_tar_mode) {
2474
                    fseek($v_tar, ('tar' === $p_tar_mode ? ftell($v_tar) : gztell($v_tar)) + (ceil($v_header['size'] / 512) * 512));
2475
                } else {
2476
                    gzseek($v_tar, gztell($v_tar) + (ceil($v_header['size'] / 512) * 512));
2477
                }
2478
2479
                TrFctMessage(__FILE__, __LINE__, 4, 'Position après jump [' . ('tar' === $p_tar_mode ? ftell($v_tar) : gztell($v_tar)) . ']');
2480
            }
2481
2482
            if ('tar' === $p_tar_mode) {
2483
                $v_end_of_file = feof($v_tar);
2484
            } else {
2485
                $v_end_of_file = gzeof($v_tar);
2486
            }
2487
2488
            // ----- File name and properties are logged if listing mode or file is extracted
2489
            if ($v_extract_file) {
2490
                TrFctMessage(__FILE__, __LINE__, 2, 'Memorize info about file ' . $v_header['filename'] . '');
2491
2492
                // ----- Log extracted files
2493
                if (($v_file_dir = \dirname($v_header['filename'])) == $v_header['filename']) {
2494
                    $v_file_dir = '';
2495
                }
2496
                if (('/' === mb_substr($v_header['filename'], 0, 1)) && ('' === $v_file_dir)) {
2497
                    $v_file_dir = '/';
2498
                }
2499
2500
                // ----- Add the array describing the file into the list
2501
                $p_list_detail[$v_nb] = $v_header;
2502
2503
                // ----- Increment
2504
                ++$v_nb;
2505
            }
2506
2507
            // ----- Increment the current file index
2508
            ++$p_index_current;
2509
        }
2510
2511
        // ----- Return
2512
        TrFctEnd(__FILE__, __LINE__, $v_result);
2513
2514
        return $v_result;
2515
    }
2516
2517
    // --------------------------------------------------------------------------------
2518
2519
    // --------------------------------------------------------------------------------
2520
    // Function : PclTarHandleExtractFile()
2521
    // Description :
2522
    // Parameters :
2523
    // Return Values :
2524
    // --------------------------------------------------------------------------------
2525
    /**
2526
     * @param $p_tar
2527
     * @param $v_header
2528
     * @param $p_path
2529
     * @param $p_remove_path
2530
     * @param $p_tar_mode
2531
     *
2532
     * @return int
2533
     */
2534
    function PclTarHandleExtractFile($p_tar, &$v_header, $p_path, $p_remove_path, $p_tar_mode)
2535
    {
2536
        TrFctStart(__FILE__, __LINE__, 'PclTarHandleExtractFile', "archive_descr='$p_tar', path=$p_path, remove_path='$p_remove_path', tar_mode=$p_tar_mode");
2537
        $v_result = 1;
2538
2539
        // TBC : I should replace all $v_tar by $p_tar in this function ....
2540
        $v_tar          = $p_tar;
2541
        $v_extract_file = 1;
2542
2543
        $p_remove_path_size = mb_strlen($p_remove_path);
2544
2545
        // ----- Look for path to remove
2546
        if (('' != $p_remove_path) && (mb_substr($v_header['filename'], 0, $p_remove_path_size) == $p_remove_path)) {
2547
            TrFctMessage(__FILE__, __LINE__, 3, "Found path '$p_remove_path' to remove in file " . $v_header['filename'] . '');
2548
            // ----- Remove the path
2549
            $v_header['filename'] = mb_substr($v_header['filename'], $p_remove_path_size);
2550
            TrFctMessage(__FILE__, __LINE__, 3, 'Resulting file is ' . $v_header['filename'] . '');
2551
        }
2552
2553
        // ----- Add the path to the file
2554
        if (('./' !== $p_path) && ('/' !== $p_path)) {
2555
            // ----- Look for the path end '/'
2556
            while ('/' === mb_substr($p_path, -1)) {
2557
                TrFctMessage(__FILE__, __LINE__, 3, "Destination path [$p_path] ends by '/'");
2558
                $p_path = mb_substr($p_path, 0, -1);
2559
                TrFctMessage(__FILE__, __LINE__, 3, "Modified to [$p_path]");
2560
            }
2561
2562
            // ----- Add the path
2563
            if ('/' === mb_substr($v_header['filename'], 0, 1)) {
2564
                $v_header['filename'] = $p_path . $v_header['filename'];
2565
            } else {
2566
                $v_header['filename'] = $p_path . '/' . $v_header['filename'];
2567
            }
2568
        }
2569
2570
        // ----- Trace
2571
        TrFctMessage(__FILE__, __LINE__, 2, 'Extracting file (with path) ' . $v_header['filename'] . ", size '" . $v_header['size'] . "'");
2572
2573
        // ----- Check that the file does not exists
2574
        if (file_exists($v_header['filename'])) {
2575
            TrFctMessage(__FILE__, __LINE__, 2, 'File ' . $v_header['filename'] . ' already exists');
2576
2577
            // ----- Look if file is a directory
2578
            if (is_dir($v_header['filename'])) {
2579
                TrFctMessage(__FILE__, __LINE__, 2, 'Existing file ' . $v_header['filename'] . ' is a directory');
2580
2581
                // ----- Change the file status
2582
                $v_header['status'] = 'already_a_directory';
2583
2584
                // ----- Skip the extract
2585
                $v_extraction_stopped = 1;
2586
                $v_extract_file       = 0;
2587
            } // ----- Look if file is write protected
2588
            elseif (!is_writable($v_header['filename'])) {
2589
                TrFctMessage(__FILE__, __LINE__, 2, 'Existing file ' . $v_header['filename'] . ' is write protected');
2590
2591
                // ----- Change the file status
2592
                $v_header['status'] = 'write_protected';
2593
2594
                // ----- Skip the extract
2595
                $v_extraction_stopped = 1;
2596
                $v_extract_file       = 0;
2597
            } // ----- Look if the extracted file is older
2598
            elseif (filemtime($v_header['filename']) > $v_header['mtime']) {
2599
                TrFctMessage(__FILE__, __LINE__, 2, 'Existing file ' . $v_header['filename'] . ' is newer (' . date('l dS of F Y h:i:s A', filemtime($v_header['filename'])) . ') than the extracted file (' . date('l dS of F Y h:i:s A', $v_header['mtime']) . ')');
2600
2601
                // ----- Change the file status
2602
                $v_header['status'] = 'newer_exist';
2603
2604
                // ----- Skip the extract
2605
                $v_extraction_stopped = 1;
2606
                $v_extract_file       = 0;
2607
            }
2608
        } // ----- Check the directory availability and create it if necessary
2609
        else {
2610
            if ('5' == $v_header['typeflag']) {
2611
                $v_dir_to_check = $v_header['filename'];
2612
            } elseif (false === mb_strpos($v_header['filename'], '/')) {
2613
                $v_dir_to_check = '';
2614
            } else {
2615
                $v_dir_to_check = \dirname($v_header['filename']);
2616
            }
2617
2618
            if (1 != ($v_result = PclTarHandlerDirCheck($v_dir_to_check))) {
2619
                TrFctMessage(__FILE__, __LINE__, 2, 'Unable to create path for ' . $v_header['filename'] . '');
2620
2621
                // ----- Change the file status
2622
                $v_header['status'] = 'path_creation_fail';
2623
2624
                // ----- Skip the extract
2625
                $v_extraction_stopped = 1;
2626
                $v_extract_file       = 0;
2627
            }
2628
        }
2629
2630
        // ----- Do the real bytes extraction (if not a directory)
2631
        if ($v_extract_file && ('5' != $v_header['typeflag'])) {
2632
            // ----- Open the destination file in write mode
2633
            if (0 == ($v_dest_file = @fopen($v_header['filename'], 'wb'))) {
2634
                TrFctMessage(__FILE__, __LINE__, 2, 'Error while opening ' . $v_header['filename'] . ' in write binary mode');
2635
2636
                // ----- Change the file status
2637
                $v_header['status'] = 'write_error';
2638
2639
                // ----- Jump to next file
2640
                TrFctMessage(__FILE__, __LINE__, 2, 'Jump to next file');
2641
                if ('tar' === $p_tar_mode) {
2642
                    fseek($v_tar, ftell($v_tar) + (ceil($v_header['size'] / 512) * 512));
2643
                } else {
2644
                    gzseek($v_tar, gztell($v_tar) + (ceil($v_header['size'] / 512) * 512));
2645
                }
2646
            } else {
2647
                TrFctMessage(__FILE__, __LINE__, 2, 'Start extraction of ' . $v_header['filename'] . '');
2648
2649
                // ----- Read data
2650
                $n = floor($v_header['size'] / 512);
2651
                for ($i = 0; $i < $n; ++$i) {
2652
                    TrFctMessage(__FILE__, __LINE__, 3, 'Read complete 512 bytes block number ' . ($i + 1));
2653
                    if ('tar' === $p_tar_mode) {
2654
                        $v_content = fread($v_tar, 512);
2655
                    } else {
2656
                        $v_content = gzread($v_tar, 512);
2657
                    }
2658
                    fwrite($v_dest_file, $v_content, 512);
2659
                }
2660
                if (0 != ($v_header['size'] % 512)) {
2661
                    TrFctMessage(__FILE__, __LINE__, 3, 'Read last ' . ($v_header['size'] % 512) . ' bytes in a 512 block');
2662
                    if ('tar' === $p_tar_mode) {
2663
                        $v_content = fread($v_tar, 512);
2664
                    } else {
2665
                        $v_content = gzread($v_tar, 512);
2666
                    }
2667
                    fwrite($v_dest_file, $v_content, $v_header['size'] % 512);
2668
                }
2669
2670
                // ----- Close the destination file
2671
                fclose($v_dest_file);
2672
2673
                // ----- Change the file mode, mtime
2674
                touch($v_header['filename'], $v_header['mtime']);
2675
                //chmod($v_header['filename'], decoct($v_header['mode']));
2676
            }
2677
2678
            // ----- Check the file size
2679
            clearstatcache();
2680
            if (filesize($v_header['filename']) != $v_header['size']) {
2681
                // ----- Error log
2682
                PclErrorLog(-7, 'Extracted file ' . $v_header['filename'] . " does not have the correct file size '" . filesize($v_filename) . "' ('" . $v_header['size'] . "' expected). Archive may be corrupted.");
2683
2684
                // ----- Return
2685
                TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
2686
2687
                return PclErrorCode();
2688
            }
2689
2690
            // ----- Trace
2691
            TrFctMessage(__FILE__, __LINE__, 2, 'Extraction done');
2692
        } else {
2693
            TrFctMessage(__FILE__, __LINE__, 2, 'Extraction of file ' . $v_header['filename'] . ' skipped.');
2694
2695
            // ----- Jump to next file
2696
            TrFctMessage(__FILE__, __LINE__, 2, 'Jump to next file');
2697
            if ('tar' === $p_tar_mode) {
2698
                fseek($v_tar, ftell($v_tar) + (ceil($v_header['size'] / 512) * 512));
2699
            } else {
2700
                gzseek($v_tar, gztell($v_tar) + (ceil($v_header['size'] / 512) * 512));
2701
            }
2702
        }
2703
2704
        // ----- Return
2705
        TrFctEnd(__FILE__, __LINE__, $v_result);
2706
2707
        return $v_result;
2708
    }
2709
2710
    // --------------------------------------------------------------------------------
2711
2712
    // --------------------------------------------------------------------------------
2713
    // Function : PclTarHandleDelete()
2714
    // Description :
2715
    // Parameters :
2716
    // Return Values :
2717
    // --------------------------------------------------------------------------------
2718
    /**
2719
     * @param $p_tarname
2720
     * @param $p_file_list
2721
     * @param $p_list_detail
2722
     * @param $p_tar_mode
2723
     *
2724
     * @return int
2725
     */
2726
    function PclTarHandleDelete($p_tarname, $p_file_list, &$p_list_detail, $p_tar_mode)
2727
    {
2728
        TrFctStart(__FILE__, __LINE__, 'PclTarHandleDelete', "archive='$p_tarname', list, tar_mode=$p_tar_mode");
2729
        $v_result = 1;
2730
        $v_nb     = 0;
2731
2732
        // ----- Look for regular tar file
2733
        if ('tar' === $p_tar_mode) {
2734
            // ----- Open file
2735
            TrFctMessage(__FILE__, __LINE__, 3, 'Open file in binary read mode');
2736
            if (0 == ($v_tar = @fopen($p_tarname, 'rb'))) {
2737
                // ----- Error log
2738
                PclErrorLog(-2, "Unable to open file '$p_tarname' in binary read mode");
2739
2740
                // ----- Return
2741
                TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
2742
2743
                return PclErrorCode();
2744
            }
2745
2746
            // ----- Open a temporary file in write mode
2747
            $v_temp_tarname = uniqid('pcltar-', true) . '.tmp';
2748
            TrFctMessage(__FILE__, __LINE__, 2, "Creating temporary archive file $v_temp_tarname");
2749
            if (0 == ($v_temp_tar = @fopen($v_temp_tarname, 'wb'))) {
2750
                // ----- Close tar file
2751
                fclose($v_tar);
2752
2753
                // ----- Error log
2754
                PclErrorLog(-1, "Unable to open file '$v_temp_tarname' in binary write mode");
2755
2756
                // ----- Return
2757
                TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
2758
2759
                return PclErrorCode();
2760
            }
2761
        } // ----- Look for compressed tar file
2762
        else {
2763
            // ----- Open the file in read mode
2764
            TrFctMessage(__FILE__, __LINE__, 3, 'Open file in gzip binary read mode');
2765
            if (0 == ($v_tar = @gzopen($p_tarname, 'rb'))) {
2766
                // ----- Error log
2767
                PclErrorLog(-2, "Unable to open file '$p_tarname' in binary read mode");
2768
2769
                // ----- Return
2770
                TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
2771
2772
                return PclErrorCode();
2773
            }
2774
2775
            // ----- Open a temporary file in write mode
2776
            $v_temp_tarname = uniqid('pcltar-', true) . '.tmp';
2777
            TrFctMessage(__FILE__, __LINE__, 2, "Creating temporary archive file $v_temp_tarname");
2778
            if (0 == ($v_temp_tar = @gzopen($v_temp_tarname, 'wb'))) {
2779
                // ----- Close tar file
2780
                gzclose($v_tar);
2781
2782
                // ----- Error log
2783
                PclErrorLog(-1, "Unable to open file '$v_temp_tarname' in binary write mode");
2784
2785
                // ----- Return
2786
                TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
2787
2788
                return PclErrorCode();
2789
            }
2790
        }
2791
2792
        // ----- Read the blocks
2793
        while (!($v_end_of_file = ('tar' === $p_tar_mode ? feof($v_tar) : gzeof($v_tar)))) {
2794
            TrFctMessage(__FILE__, __LINE__, 3, 'Looking for next header ...');
2795
2796
            // ----- Clear cache of file infos
2797
            clearstatcache();
2798
2799
            // ----- Reset delete tag
2800
            $v_delete_file = false;
2801
2802
            // ----- Read the first 512 block header
2803
            if ('tar' === $p_tar_mode) {
2804
                $v_binary_data = fread($v_tar, 512);
2805
            } else {
2806
                $v_binary_data = gzread($v_tar, 512);
2807
            }
2808
2809
            // ----- Read the header properties
2810
            if (1 != ($v_result = PclTarHandleReadHeader($v_binary_data, $v_header))) {
2811
                // ----- Close the archive file
2812
                if ('tar' === $p_tar_mode) {
2813
                    fclose($v_tar);
2814
                    fclose($v_temp_tar);
2815
                } else {
2816
                    gzclose($v_tar);
2817
                    gzclose($v_temp_tar);
2818
                }
2819
                @unlink($v_temp_tarname);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for unlink(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

2819
                /** @scrutinizer ignore-unhandled */ @unlink($v_temp_tarname);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
2820
2821
                // ----- Return
2822
                TrFctEnd(__FILE__, __LINE__, $v_result);
2823
2824
                return $v_result;
2825
            }
2826
2827
            // ----- Look for empty blocks to skip
2828
            if ('' == $v_header['filename']) {
2829
                TrFctMessage(__FILE__, __LINE__, 2, 'Empty block found. End of archive?');
2830
                continue;
2831
            }
2832
2833
            TrFctMessage(__FILE__, __LINE__, 2, 'Found file ' . $v_header['filename'] . ", size '" . $v_header['size'] . "'");
2834
2835
            // ----- Look for filenames to delete
2836
            for ($i = 0, $v_delete_file = false; ($i < count($p_file_list)) && (!$v_delete_file); ++$i) {
2837
                // ----- Compare the file names
2838
                //        if ($p_file_list[$i] == $v_header['filename'])
2839
                if (($v_len = strcmp($p_file_list[$i], $v_header['filename'])) <= 0) {
2840
                    if (0 == $v_len) {
2841
                        TrFctMessage(__FILE__, __LINE__, 3, 'Found that ' . $v_header['filename'] . ' need to be deleted');
2842
                        $v_delete_file = true;
2843
                    } else {
2844
                        TrFctMessage(__FILE__, __LINE__, 3, 'Look if ' . $v_header['filename'] . " is a file in $p_file_list[$i]");
2845
                        if ('/' === mb_substr($v_header['filename'], mb_strlen($p_file_list[$i]), 1)) {
2846
                            TrFctMessage(__FILE__, __LINE__, 3, '' . $v_header['filename'] . " is a file in $p_file_list[$i]");
2847
                            $v_delete_file = true;
2848
                        }
2849
                    }
2850
                }
2851
            }
2852
2853
            // ----- Copy files that do not need to be deleted
2854
            if (!$v_delete_file) {
2855
                TrFctMessage(__FILE__, __LINE__, 2, 'Keep file ' . $v_header['filename'] . '');
2856
2857
                // ----- Write the file header
2858
                if ('tar' === $p_tar_mode) {
2859
                    fwrite($v_temp_tar, $v_binary_data, 512);
2860
                } else {
2861
                    gzputs($v_temp_tar, $v_binary_data, 512);
2862
                }
2863
2864
                // ----- Write the file data
2865
                $n = ceil($v_header['size'] / 512);
2866
                for ($i = 0; $i < $n; ++$i) {
2867
                    TrFctMessage(__FILE__, __LINE__, 3, 'Read complete 512 bytes block number ' . ($i + 1));
2868
                    if ('tar' === $p_tar_mode) {
2869
                        $v_content = fread($v_tar, 512);
2870
                        fwrite($v_temp_tar, $v_content, 512);
2871
                    } else {
2872
                        $v_content = gzread($v_tar, 512);
2873
                        gzwrite($v_temp_tar, $v_content, 512);
2874
                    }
2875
                }
2876
2877
                // ----- File name and properties are logged if listing mode or file is extracted
2878
                TrFctMessage(__FILE__, __LINE__, 2, 'Memorize info about file ' . $v_header['filename'] . '');
2879
2880
                // ----- Add the array describing the file into the list
2881
                $p_list_detail[$v_nb]           = $v_header;
2882
                $p_list_detail[$v_nb]['status'] = 'ok';
2883
2884
                // ----- Increment
2885
                ++$v_nb;
2886
            } // ----- Look for file that is to be deleted
2887
            else {
2888
                // ----- Trace
2889
                TrFctMessage(__FILE__, __LINE__, 2, 'Start deletion of ' . $v_header['filename'] . '');
2890
                TrFctMessage(__FILE__, __LINE__, 4, 'Position avant jump [' . ('tar' === $p_tar_mode ? ftell($v_tar) : gztell($v_tar)) . ']');
2891
2892
                // ----- Jump to next file
2893
                if ('tar' === $p_tar_mode) {
2894
                    fseek($v_tar, ftell($v_tar) + (ceil($v_header['size'] / 512) * 512));
2895
                } else {
2896
                    gzseek($v_tar, gztell($v_tar) + (ceil($v_header['size'] / 512) * 512));
2897
                }
2898
2899
                TrFctMessage(__FILE__, __LINE__, 4, 'Position après jump [' . ('tar' === $p_tar_mode ? ftell($v_tar) : gztell($v_tar)) . ']');
2900
            }
2901
2902
            // ----- Look for end of file
2903
            if ('tar' === $p_tar_mode) {
2904
                $v_end_of_file = feof($v_tar);
2905
            } else {
2906
                $v_end_of_file = gzeof($v_tar);
2907
            }
2908
        }
2909
2910
        // ----- Write the last empty buffer
2911
        PclTarHandleFooter($v_temp_tar, $p_tar_mode);
2912
2913
        // ----- Close the tarfile
2914
        if ('tar' === $p_tar_mode) {
2915
            fclose($v_tar);
2916
            fclose($v_temp_tar);
2917
        } else {
2918
            gzclose($v_tar);
2919
            gzclose($v_temp_tar);
2920
        }
2921
2922
        // ----- Unlink tar file
2923
        if (!@unlink($p_tarname)) {
2924
            // ----- Error log
2925
            PclErrorLog(-11, "Error while deleting archive name $p_tarname");
2926
        }
2927
2928
        // ----- Rename tar file
2929
        if (!@rename($v_temp_tarname, $p_tarname)) {
2930
            // ----- Error log
2931
            PclErrorLog(-12, "Error while renaming temporary file $v_temp_tarname to archive name $p_tarname");
2932
2933
            // ----- Return
2934
            TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
2935
2936
            return PclErrorCode();
2937
        }
2938
2939
        // ----- Return
2940
        TrFctEnd(__FILE__, __LINE__, $v_result);
2941
2942
        return $v_result;
2943
    }
2944
2945
    // --------------------------------------------------------------------------------
2946
2947
    // --------------------------------------------------------------------------------
2948
    // Function : PclTarHandleUpdate()
2949
    // Description :
2950
    // Parameters :
2951
    // Return Values :
2952
    // --------------------------------------------------------------------------------
2953
    /**
2954
     * @param $p_tarname
2955
     * @param $p_file_list
2956
     * @param $p_list_detail
2957
     * @param $p_tar_mode
2958
     * @param $p_add_dir
2959
     * @param $p_remove_dir
2960
     *
2961
     * @return int
2962
     */
2963
    function PclTarHandleUpdate($p_tarname, $p_file_list, &$p_list_detail, $p_tar_mode, $p_add_dir, $p_remove_dir)
2964
    {
2965
        TrFctStart(__FILE__, __LINE__, 'PclTarHandleUpdate', "archive='$p_tarname', list, tar_mode=$p_tar_mode");
2966
        $v_result     = 1;
2967
        $v_nb         = 0;
2968
        $v_found_list = [];
2969
2970
        // ----- Look for regular tar file
2971
        if ('tar' === $p_tar_mode) {
2972
            // ----- Open file
2973
            TrFctMessage(__FILE__, __LINE__, 3, 'Open file in binary read mode');
2974
            if (0 == ($v_tar = @fopen($p_tarname, 'rb'))) {
2975
                // ----- Error log
2976
                PclErrorLog(-2, "Unable to open file '$p_tarname' in binary read mode");
2977
2978
                // ----- Return
2979
                TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
2980
2981
                return PclErrorCode();
2982
            }
2983
2984
            // ----- Open a temporary file in write mode
2985
            $v_temp_tarname = uniqid('pcltar-', true) . '.tmp';
2986
            TrFctMessage(__FILE__, __LINE__, 2, "Creating temporary archive file $v_temp_tarname");
2987
            if (0 == ($v_temp_tar = @fopen($v_temp_tarname, 'wb'))) {
2988
                // ----- Close tar file
2989
                fclose($v_tar);
2990
2991
                // ----- Error log
2992
                PclErrorLog(-1, "Unable to open file '$v_temp_tarname' in binary write mode");
2993
2994
                // ----- Return
2995
                TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
2996
2997
                return PclErrorCode();
2998
            }
2999
        } // ----- Look for compressed tar file
3000
        else {
3001
            // ----- Open the file in read mode
3002
            TrFctMessage(__FILE__, __LINE__, 3, 'Open file in gzip binary read mode');
3003
            if (0 == ($v_tar = @gzopen($p_tarname, 'rb'))) {
3004
                // ----- Error log
3005
                PclErrorLog(-2, "Unable to open file '$p_tarname' in binary read mode");
3006
3007
                // ----- Return
3008
                TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
3009
3010
                return PclErrorCode();
3011
            }
3012
3013
            // ----- Open a temporary file in write mode
3014
            $v_temp_tarname = uniqid('pcltar-', true) . '.tmp';
3015
            TrFctMessage(__FILE__, __LINE__, 2, "Creating temporary archive file $v_temp_tarname");
3016
            if (0 == ($v_temp_tar = @gzopen($v_temp_tarname, 'wb'))) {
3017
                // ----- Close tar file
3018
                gzclose($v_tar);
3019
3020
                // ----- Error log
3021
                PclErrorLog(-1, "Unable to open file '$v_temp_tarname' in binary write mode");
3022
3023
                // ----- Return
3024
                TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
3025
3026
                return PclErrorCode();
3027
            }
3028
        }
3029
3030
        // ----- Prepare the list of files
3031
        for ($i = 0, $iMax = count($p_file_list); $i < $iMax; ++$i) {
3032
            // ----- Reset the found list
3033
            $v_found_list[$i] = 0;
3034
3035
            // ----- Calculate the stored filename
3036
            $v_stored_list[$i] = $p_file_list[$i];
3037
            if ('' != $p_remove_dir) {
3038
                if ('/' !== mb_substr($p_file_list[$i], -1)) {
3039
                    $p_remove_dir .= '/';
3040
                }
3041
3042
                if (mb_substr($p_file_list[$i], 0, mb_strlen($p_remove_dir)) == $p_remove_dir) {
3043
                    $v_stored_list[$i] = mb_substr($p_file_list[$i], mb_strlen($p_remove_dir));
3044
                    TrFctMessage(__FILE__, __LINE__, 3, "Remove path '$p_remove_dir' in file '$p_file_list[$i]' = '$v_stored_list[$i]'");
3045
                }
3046
            }
3047
            if ('' != $p_add_dir) {
3048
                if ('/' === mb_substr($p_add_dir, -1)) {
3049
                    $v_stored_list[$i] = $p_add_dir . $v_stored_list[$i];
3050
                } else {
3051
                    $v_stored_list[$i] = $p_add_dir . '/' . $v_stored_list[$i];
3052
                }
3053
                TrFctMessage(__FILE__, __LINE__, 3, "Add path '$p_add_dir' in file '$p_file_list[$i]' = '$v_stored_list[$i]'");
3054
            }
3055
            $v_stored_list[$i] = PclTarHandlePathReduction($v_stored_list[$i]);
3056
            TrFctMessage(__FILE__, __LINE__, 3, "After reduction '$v_stored_list[$i]'");
3057
        }
3058
3059
        // ----- Update file cache
3060
        clearstatcache();
3061
3062
        // ----- Read the blocks
3063
        while (!($v_end_of_file = ('tar' === $p_tar_mode ? feof($v_tar) : gzeof($v_tar)))) {
3064
            TrFctMessage(__FILE__, __LINE__, 3, 'Looking for next header ...');
3065
3066
            // ----- Clear cache of file infos
3067
            clearstatcache();
3068
3069
            // ----- Reset current found filename
3070
            $v_current_filename = '';
3071
3072
            // ----- Reset delete tag
3073
            $v_delete_file = false;
3074
3075
            // ----- Read the first 512 block header
3076
            if ('tar' === $p_tar_mode) {
3077
                $v_binary_data = fread($v_tar, 512);
3078
            } else {
3079
                $v_binary_data = gzread($v_tar, 512);
3080
            }
3081
3082
            // ----- Read the header properties
3083
            if (1 != ($v_result = PclTarHandleReadHeader($v_binary_data, $v_header))) {
3084
                // ----- Close the archive file
3085
                if ('tar' === $p_tar_mode) {
3086
                    fclose($v_tar);
3087
                    fclose($v_temp_tar);
3088
                } else {
3089
                    gzclose($v_tar);
3090
                    gzclose($v_temp_tar);
3091
                }
3092
                @unlink($v_temp_tarname);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for unlink(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

3092
                /** @scrutinizer ignore-unhandled */ @unlink($v_temp_tarname);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
3093
3094
                // ----- Return
3095
                TrFctEnd(__FILE__, __LINE__, $v_result);
3096
3097
                return $v_result;
3098
            }
3099
3100
            // ----- Look for empty blocks to skip
3101
            if ('' == $v_header['filename']) {
3102
                TrFctMessage(__FILE__, __LINE__, 2, 'Empty block found. End of archive?');
3103
                continue;
3104
            }
3105
3106
            TrFctMessage(__FILE__, __LINE__, 2, 'Found file ' . $v_header['filename'] . ", size '" . $v_header['size'] . "'");
3107
3108
            // ----- Look for filenames to update
3109
            for ($i = 0, $v_update_file = false, $v_found_file = false; ($i < count($v_stored_list)) && (!$v_update_file); ++$i) {
3110
                TrFctMessage(__FILE__, __LINE__, 4, "Compare with file '$v_stored_list[$i]'");
3111
3112
                // ----- Compare the file names
3113
                if ($v_stored_list[$i] == $v_header['filename']) {
3114
                    TrFctMessage(__FILE__, __LINE__, 3, "File '$v_stored_list[$i]' is present in archive");
3115
                    TrFctMessage(__FILE__, __LINE__, 3, "File '$v_stored_list[$i]' mtime=" . filemtime($p_file_list[$i]) . ' ' . date('l dS of F Y h:i:s A', filemtime($p_file_list[$i])));
3116
                    TrFctMessage(__FILE__, __LINE__, 3, 'Archived mtime=' . $v_header['mtime'] . ' ' . date('l dS of F Y h:i:s A', $v_header['mtime']));
3117
3118
                    // ----- Store found informations
3119
                    $v_found_file       = true;
3120
                    $v_current_filename = $p_file_list[$i];
3121
3122
                    // ----- Look if the file need to be updated
3123
                    if (filemtime($p_file_list[$i]) > $v_header['mtime']) {
3124
                        TrFctMessage(__FILE__, __LINE__, 3, "File '$p_file_list[$i]' need to be updated");
3125
                        $v_update_file = true;
3126
                    } else {
3127
                        TrFctMessage(__FILE__, __LINE__, 3, "File '$p_file_list[$i]' does not need to be updated");
3128
                        $v_update_file = false;
3129
                    }
3130
3131
                    // ----- Flag the name in order not to add the file at the end
3132
                    $v_found_list[$i] = 1;
3133
                } else {
3134
                    TrFctMessage(__FILE__, __LINE__, 4, "File '$p_file_list[$i]' is not " . $v_header['filename'] . '');
3135
                }
3136
            }
3137
3138
            // ----- Copy files that do not need to be updated
3139
            if (!$v_update_file) {
3140
                TrFctMessage(__FILE__, __LINE__, 2, 'Keep file ' . $v_header['filename'] . '');
3141
3142
                // ----- Write the file header
3143
                if ('tar' === $p_tar_mode) {
3144
                    fwrite($v_temp_tar, $v_binary_data, 512);
3145
                } else {
3146
                    gzputs($v_temp_tar, $v_binary_data, 512);
3147
                }
3148
3149
                // ----- Write the file data
3150
                $n = ceil($v_header['size'] / 512);
3151
                for ($j = 0; $j < $n; ++$j) {
3152
                    TrFctMessage(__FILE__, __LINE__, 3, 'Read complete 512 bytes block number ' . ($j + 1));
3153
                    if ('tar' === $p_tar_mode) {
3154
                        $v_content = fread($v_tar, 512);
3155
                        fwrite($v_temp_tar, $v_content, 512);
3156
                    } else {
3157
                        $v_content = gzread($v_tar, 512);
3158
                        gzwrite($v_temp_tar, $v_content, 512);
3159
                    }
3160
                }
3161
3162
                // ----- File name and properties are logged if listing mode or file is extracted
3163
                TrFctMessage(__FILE__, __LINE__, 2, 'Memorize info about file ' . $v_header['filename'] . '');
3164
3165
                // ----- Add the array describing the file into the list
3166
                $p_list_detail[$v_nb]           = $v_header;
3167
                $p_list_detail[$v_nb]['status'] = ($v_found_file ? 'not_updated' : 'ok');
3168
3169
                // ----- Increment
3170
                ++$v_nb;
3171
            } // ----- Look for file that need to be updated
3172
            else {
3173
                // ----- Trace
3174
                TrFctMessage(__FILE__, __LINE__, 2, "Start update of file '$v_current_filename'");
3175
3176
                // ----- Store the old file size
3177
                $v_old_size = $v_header['size'];
3178
3179
                // ----- Add the file
3180
                if (1 != ($v_result = PclTarHandleAddFile($v_temp_tar, $v_current_filename, $p_tar_mode, $v_header, $p_add_dir, $p_remove_dir))) {
3181
                    // ----- Close the tarfile
3182
                    if ('tar' === $p_tar_mode) {
3183
                        fclose($v_tar);
3184
                        fclose($v_temp_tar);
3185
                    } else {
3186
                        gzclose($v_tar);
3187
                        gzclose($v_temp_tar);
3188
                    }
3189
                    @unlink($p_temp_tarname);
3190
3191
                    // ----- Return status
3192
                    TrFctEnd(__FILE__, __LINE__, $v_result);
3193
3194
                    return $v_result;
3195
                }
3196
3197
                // ----- Trace
3198
                TrFctMessage(__FILE__, __LINE__, 2, 'Skip old file ' . $v_header['filename'] . '');
3199
3200
                // ----- Jump to next file
3201
                if ('tar' === $p_tar_mode) {
3202
                    fseek($v_tar, ftell($v_tar) + (ceil($v_old_size / 512) * 512));
3203
                } else {
3204
                    gzseek($v_tar, gztell($v_tar) + (ceil($v_old_size / 512) * 512));
3205
                }
3206
3207
                // ----- Add the array describing the file into the list
3208
                $p_list_detail[$v_nb]           = $v_header;
3209
                $p_list_detail[$v_nb]['status'] = 'updated';
3210
3211
                // ----- Increment
3212
                ++$v_nb;
3213
            }
3214
3215
            // ----- Look for end of file
3216
            if ('tar' === $p_tar_mode) {
3217
                $v_end_of_file = feof($v_tar);
3218
            } else {
3219
                $v_end_of_file = gzeof($v_tar);
3220
            }
3221
        }
3222
3223
        // ----- Look for files that does not exists in the archive and need to be added
3224
        for ($i = 0, $iMax = count($p_file_list); $i < $iMax; ++$i) {
3225
            // ----- Look if file not found in the archive
3226
            if (!$v_found_list[$i]) {
3227
                TrFctMessage(__FILE__, __LINE__, 3, "File '$p_file_list[$i]' need to be added");
3228
3229
                // ----- Add the file
3230
                if (1 != ($v_result = PclTarHandleAddFile($v_temp_tar, $p_file_list[$i], $p_tar_mode, $v_header, $p_add_dir, $p_remove_dir))) {
3231
                    // ----- Close the tarfile
3232
                    if ('tar' === $p_tar_mode) {
3233
                        fclose($v_tar);
3234
                        fclose($v_temp_tar);
3235
                    } else {
3236
                        gzclose($v_tar);
3237
                        gzclose($v_temp_tar);
3238
                    }
3239
                    @unlink($p_temp_tarname);
3240
3241
                    // ----- Return status
3242
                    TrFctEnd(__FILE__, __LINE__, $v_result);
3243
3244
                    return $v_result;
3245
                }
3246
3247
                // ----- Add the array describing the file into the list
3248
                $p_list_detail[$v_nb]           = $v_header;
3249
                $p_list_detail[$v_nb]['status'] = 'added';
3250
3251
                // ----- Increment
3252
                ++$v_nb;
3253
            } else {
3254
                TrFctMessage(__FILE__, __LINE__, 3, "File '$p_file_list[$i]' was already updated if needed");
3255
            }
3256
        }
3257
3258
        // ----- Write the last empty buffer
3259
        PclTarHandleFooter($v_temp_tar, $p_tar_mode);
3260
3261
        // ----- Close the tarfile
3262
        if ('tar' === $p_tar_mode) {
3263
            fclose($v_tar);
3264
            fclose($v_temp_tar);
3265
        } else {
3266
            gzclose($v_tar);
3267
            gzclose($v_temp_tar);
3268
        }
3269
3270
        // ----- Unlink tar file
3271
        if (!@unlink($p_tarname)) {
3272
            // ----- Error log
3273
            PclErrorLog(-11, "Error while deleting archive name $p_tarname");
3274
        }
3275
3276
        // ----- Rename tar file
3277
        if (!@rename($v_temp_tarname, $p_tarname)) {
3278
            // ----- Error log
3279
            PclErrorLog(-12, "Error while renaming temporary file $v_temp_tarname to archive name $p_tarname");
3280
3281
            // ----- Return
3282
            TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
3283
3284
            return PclErrorCode();
3285
        }
3286
3287
        // ----- Return
3288
        TrFctEnd(__FILE__, __LINE__, $v_result);
3289
3290
        return $v_result;
3291
    }
3292
3293
    // --------------------------------------------------------------------------------
3294
3295
    // --------------------------------------------------------------------------------
3296
    // Function : PclTarHandleReadHeader()
3297
    // Description :
3298
    // Parameters :
3299
    // Return Values :
3300
    // --------------------------------------------------------------------------------
3301
    /**
3302
     * @param $v_binary_data
3303
     * @param $v_header
3304
     *
3305
     * @return int
3306
     */
3307
    function PclTarHandleReadHeader($v_binary_data, &$v_header)
3308
    {
3309
        TrFctStart(__FILE__, __LINE__, 'PclTarHandleReadHeader', '');
3310
        $v_result = 1;
3311
3312
        // ----- Read the 512 bytes header
3313
        /*
3314
    if ($p_tar_mode == "tar")
3315
      $v_binary_data = fread($p_tar, 512);
3316
    else
3317
      $v_binary_data = gzread($p_tar, 512);
3318
    */
3319
3320
        // ----- Look for no more block
3321
        if (0 == mb_strlen($v_binary_data)) {
3322
            $v_header['filename'] = '';
3323
            $v_header['status']   = 'empty';
3324
3325
            // ----- Return
3326
            TrFctEnd(__FILE__, __LINE__, $v_result, 'End of archive found');
3327
3328
            return $v_result;
3329
        }
3330
3331
        // ----- Look for invalid block size
3332
        if (512 != mb_strlen($v_binary_data)) {
3333
            $v_header['filename'] = '';
3334
            $v_header['status']   = 'invalid_header';
3335
            TrFctMessage(__FILE__, __LINE__, 2, 'Invalid block size : ' . mb_strlen($v_binary_data));
3336
3337
            // ----- Error log
3338
            PclErrorLog(-10, 'Invalid block size : ' . mb_strlen($v_binary_data));
3339
3340
            // ----- Return
3341
            TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
3342
3343
            return PclErrorCode();
3344
        }
3345
3346
        // ----- Calculate the checksum
3347
        $v_checksum = 0;
3348
        // ..... First part of the header
3349
        for ($i = 0; $i < 148; ++$i) {
3350
            $v_checksum += ord(mb_substr($v_binary_data, $i, 1));
3351
        }
3352
        // ..... Ignore the checksum value and replace it by ' ' (space)
3353
        for ($i = 148; $i < 156; ++$i) {
3354
            $v_checksum += ord(' ');
3355
        }
3356
        // ..... Last part of the header
3357
        for ($i = 156; $i < 512; ++$i) {
3358
            $v_checksum += ord(mb_substr($v_binary_data, $i, 1));
3359
        }
3360
        TrFctMessage(__FILE__, __LINE__, 3, "Calculated checksum : $v_checksum");
3361
3362
        // ----- Extract the values
3363
        TrFctMessage(__FILE__, __LINE__, 2, "Header : '$v_binary_data'");
3364
        $v_data = unpack('a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/a8checksum/a1typeflag/a100link/a6magic/a2version/a32uname/a32gname/a8devmajor/a8devminor', $v_binary_data);
3365
3366
        // ----- Extract the checksum for check
3367
        $v_header['checksum'] = octdec(trim($v_data['checksum']));
3368
        TrFctMessage(__FILE__, __LINE__, 3, 'File checksum : ' . $v_header['checksum'] . '');
3369
        if ($v_header['checksum'] != $v_checksum) {
3370
            TrFctMessage(__FILE__, __LINE__, 2, "File checksum is invalid : $v_checksum calculated, " . $v_header['checksum'] . ' expected');
3371
3372
            $v_header['filename'] = '';
3373
            $v_header['status']   = 'invalid_header';
3374
3375
            // ----- Look for last block (empty block)
3376
            if ((256 == $v_checksum) && (0 == $v_header['checksum'])) {
3377
                $v_header['status'] = 'empty';
3378
                // ----- Return
3379
                TrFctEnd(__FILE__, __LINE__, $v_result, 'End of archive found');
3380
3381
                return $v_result;
3382
            }
3383
3384
            // ----- Error log
3385
            PclErrorLog(-13, "Invalid checksum : $v_checksum calculated, " . $v_header['checksum'] . ' expected');
3386
3387
            // ----- Return
3388
            TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
3389
3390
            return PclErrorCode();
3391
        }
3392
        TrFctMessage(__FILE__, __LINE__, 2, "File checksum is valid ($v_checksum)");
3393
3394
        // ----- Extract the properties
3395
        $v_header['filename'] = trim($v_data['filename']);
3396
        TrFctMessage(__FILE__, __LINE__, 2, 'Name : ' . $v_header['filename'] . '');
3397
        $v_header['mode'] = octdec(trim($v_data['mode']));
3398
        TrFctMessage(__FILE__, __LINE__, 2, "Mode : '" . decoct($v_header['mode']) . "'");
3399
        $v_header['uid'] = octdec(trim($v_data['uid']));
3400
        TrFctMessage(__FILE__, __LINE__, 2, "Uid : '" . $v_header['uid'] . "'");
3401
        $v_header['gid'] = octdec(trim($v_data['gid']));
3402
        TrFctMessage(__FILE__, __LINE__, 2, "Gid : '" . $v_header['gid'] . "'");
3403
        $v_header['size'] = octdec(trim($v_data['size']));
3404
        TrFctMessage(__FILE__, __LINE__, 2, "Size : '" . $v_header['size'] . "'");
3405
        $v_header['mtime'] = octdec(trim($v_data['mtime']));
3406
        TrFctMessage(__FILE__, __LINE__, 2, 'Date : ' . date('l dS of F Y h:i:s A', $v_header['mtime']));
3407
        if ('5' == ($v_header['typeflag'] = $v_data['typeflag'])) {
3408
            $v_header['size'] = 0;
3409
            TrFctMessage(__FILE__, __LINE__, 2, "Size (folder) : '" . $v_header['size'] . "'");
3410
        }
3411
        TrFctMessage(__FILE__, __LINE__, 2, 'File typeflag : ' . $v_header['typeflag'] . '');
3412
        /* ----- All these fields are removed form the header because they do not carry interesting info
3413
    $v_header[link] = trim($v_data[link]);
3414
    TrFctMessage(__FILE__, __LINE__, 2, "Linkname : $v_header[linkname]");
3415
    $v_header[magic] = trim($v_data[magic]);
3416
    TrFctMessage(__FILE__, __LINE__, 2, "Magic : $v_header[magic]");
3417
    $v_header[version] = trim($v_data[version]);
3418
    TrFctMessage(__FILE__, __LINE__, 2, "Version : $v_header[version]");
3419
    $v_header[uname] = trim($v_data[uname]);
3420
    TrFctMessage(__FILE__, __LINE__, 2, "Uname : $v_header[uname]");
3421
    $v_header[gname] = trim($v_data[gname]);
3422
    TrFctMessage(__FILE__, __LINE__, 2, "Gname : $v_header[gname]");
3423
    $v_header[devmajor] = trim($v_data[devmajor]);
3424
    TrFctMessage(__FILE__, __LINE__, 2, "Devmajor : $v_header[devmajor]");
3425
    $v_header[devminor] = trim($v_data[devminor]);
3426
    TrFctMessage(__FILE__, __LINE__, 2, "Devminor : $v_header[devminor]");
3427
    */
3428
3429
        // ----- Set the status field
3430
        $v_header['status'] = 'ok';
3431
3432
        // ----- Return
3433
        TrFctEnd(__FILE__, __LINE__, $v_result);
3434
3435
        return $v_result;
3436
    }
3437
3438
    // --------------------------------------------------------------------------------
3439
3440
    // --------------------------------------------------------------------------------
3441
    // Function : PclTarHandlerDirCheck()
3442
    // Description :
3443
    //   Check if a directory exists, if not it creates it and all the parents directory
3444
    //   which may be useful.
3445
    // Parameters :
3446
    //   $p_dir : Directory path to check (without / at the end).
3447
    // Return Values :
3448
    //    1 : OK
3449
    //   -1 : Unable to create directory
3450
    // --------------------------------------------------------------------------------
3451
    /**
3452
     * @param $p_dir
3453
     *
3454
     * @return int
3455
     */
3456
    function PclTarHandlerDirCheck($p_dir)
3457
    {
3458
        $v_result = 1;
3459
3460
        TrFctStart(__FILE__, __LINE__, 'PclTarHandlerDirCheck', (string)$p_dir);
3461
3462
        // ----- Check the directory availability
3463
        if (is_dir($p_dir) || ('' == $p_dir)) {
3464
            TrFctEnd(__FILE__, __LINE__, "'$p_dir' is a directory");
3465
3466
            return 1;
3467
        }
3468
3469
        // ----- Look for file alone
3470
        /*
3471
    if (false === strpos("$p_dir", "/")) {
3472
      TrFctEnd(__FILE__, __LINE__,  "'$p_dir' is a file with no directory");
3473
3474
      return 1;
3475
    }
3476
    */
3477
3478
        // ----- Extract parent directory
3479
        $p_parent_dir = \dirname($p_dir);
3480
        TrFctMessage(__FILE__, __LINE__, 3, "Parent directory is '$p_parent_dir'");
3481
3482
        // ----- Just a check
3483
        if ($p_parent_dir != $p_dir) {
3484
            // ----- Look for parent directory
3485
            if ('' != $p_parent_dir) {
3486
                if (1 != ($v_result = PclTarHandlerDirCheck($p_parent_dir))) {
3487
                    TrFctEnd(__FILE__, __LINE__, $v_result);
3488
3489
                    return $v_result;
3490
                }
3491
            }
3492
        }
3493
3494
        // ----- Create the directory
3495
        TrFctMessage(__FILE__, __LINE__, 3, "Create directory '$p_dir'");
3496
        if (!@mkdir($p_dir, 0777)) {
3497
            // ----- Error log
3498
            PclErrorLog(-8, "Unable to create directory '$p_dir'");
3499
3500
            // ----- Return
3501
            TrFctEnd(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
3502
3503
            return PclErrorCode();
3504
        }
3505
3506
        // ----- Return
3507
        TrFctEnd(__FILE__, __LINE__, $v_result, "Directory '$p_dir' created");
3508
3509
        return $v_result;
3510
    }
3511
3512
    // --------------------------------------------------------------------------------
3513
3514
    // --------------------------------------------------------------------------------
3515
    // Function : PclTarHandleExtension()
3516
    // Description :
3517
    // Parameters :
3518
    // Return Values :
3519
    // --------------------------------------------------------------------------------
3520
    /**
3521
     * @param $p_tarname
3522
     *
3523
     * @return string
3524
     */
3525
    function PclTarHandleExtension($p_tarname)
3526
    {
3527
        TrFctStart(__FILE__, __LINE__, 'PclTarHandleExtension', "tar=$p_tarname");
3528
3529
        // ----- Look for file extension
3530
        if (('.tar.gz' === mb_substr($p_tarname, -7)) || ('.tgz' === mb_substr($p_tarname, -4))) {
3531
            TrFctMessage(__FILE__, __LINE__, 2, 'Archive is a gzip tar');
3532
            $v_tar_mode = 'tgz';
3533
        } elseif ('.tar' === mb_substr($p_tarname, -4)) {
3534
            TrFctMessage(__FILE__, __LINE__, 2, 'Archive is a tar');
3535
            $v_tar_mode = 'tar';
3536
        } else {
3537
            // ----- Error log
3538
            PclErrorLog(-9, 'Invalid archive extension');
3539
3540
            TrFctMessage(__FILE__, __LINE__, PclErrorCode(), PclErrorString());
3541
3542
            $v_tar_mode = '';
3543
        }
3544
3545
        // ----- Return
3546
        TrFctEnd(__FILE__, __LINE__, $v_tar_mode);
3547
3548
        return $v_tar_mode;
3549
    }
3550
3551
    // --------------------------------------------------------------------------------
3552
3553
    // --------------------------------------------------------------------------------
3554
    // Function : PclTarHandlePathReduction()
3555
    // Description :
3556
    // Parameters :
3557
    // Return Values :
3558
    // --------------------------------------------------------------------------------
3559
    /**
3560
     * @param $p_dir
3561
     *
3562
     * @return string
3563
     */
3564
    function PclTarHandlePathReduction($p_dir)
3565
    {
3566
        TrFctStart(__FILE__, __LINE__, 'PclTarHandlePathReduction', "dir='$p_dir'");
3567
        $v_result = '';
3568
3569
        // ----- Look for not empty path
3570
        if ('' != $p_dir) {
3571
            // ----- Explode path by directory names
3572
            $v_list = explode('/', $p_dir);
3573
3574
            // ----- Study directories from last to first
3575
            for ($i = count($v_list) - 1; $i >= 0; $i--) {
3576
                // ----- Look for current path
3577
                if ('.' === $v_list[$i]) {
3578
                    // ----- Ignore this directory
3579
                    // Should be the first $i=0, but no check is done
3580
                } elseif ('..' === $v_list[$i]) {
3581
                    // ----- Ignore it and ignore the $i-1
3582
                    $i--;
3583
                } elseif (('' == $v_list[$i]) && ($i != (count($v_list) - 1)) && (0 != $i)) {
3584
                    // ----- Ignore only the double '//' in path,
3585
                    // but not the first and last '/'
3586
                } else {
3587
                    $v_result = $v_list[$i] . ($i != (count($v_list) - 1) ? '/' . $v_result : '');
3588
                }
3589
            }
3590
        }
3591
3592
        // ----- Return
3593
        TrFctEnd(__FILE__, __LINE__, $v_result);
3594
3595
        return $v_result;
3596
    }
3597
3598
    // --------------------------------------------------------------------------------
3599
3600
    // ----- End of double include look
3601
}
3602