diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..2f673eb
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,65 @@
+# Drupal git normalization
+# @see https://www.kernel.org/pub/software/scm/git/docs/gitattributes.html
+# @see https://www.drupal.org/node/1542048
+
+# Normally these settings would be done with macro attributes for improved
+# readability and easier maintenance. However macros can only be defined at the
+# repository root directory. Drupal avoids making any assumptions about where it
+# is installed.
+
+# Define text file attributes.
+# - Treat them as text.
+# - Ensure no CRLF line-endings, neither on checkout nor on checkin.
+# - Detect whitespace errors.
+# - Exposed by default in `git diff --color` on the CLI.
+# - Validate with `git diff --check`.
+# - Deny applying with `git apply --whitespace=error-all`.
+# - Fix automatically with `git apply --whitespace=fix`.
+
+*.config text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
+*.css text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
+*.dist text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
+*.engine text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php linguist-language=php
+*.html text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=html
+*.inc text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php linguist-language=php
+*.install text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php linguist-language=php
+*.js text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
+*.json text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
+*.lock text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
+*.map text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
+*.md text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
+*.module text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php linguist-language=php
+*.php text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php linguist-language=php
+*.po text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
+*.profile text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php linguist-language=php
+*.script text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
+*.sh text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php linguist-language=php
+*.sql text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
+*.svg text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
+*.theme text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php linguist-language=php
+*.twig text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
+*.txt text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
+*.xml text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
+*.yml text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
+
+# PHPStan's baseline uses tabs instead of spaces.
+core/.phpstan-baseline.php text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tabwidth=2 diff=php linguist-language=php
+
+# Define binary file attributes.
+# - Do not treat them as text.
+# - Include binary diff in patches instead of "binary files differ."
+*.eot binary -text diff
+*.exe binary -text diff
+*.gif binary -text diff
+*.gz binary -text diff
+*.ico binary -text diff
+*.jpeg binary -text diff
+*.jpg binary -text diff
+*.otf binary -text diff
+*.phar binary -text diff
+*.png binary -text diff
+*.svgz binary -text diff
+*.ttf binary -text diff
+*.woff binary -text diff
+*.woff2 binary -text diff
+*.odt binary -text diff
diff --git a/.gitignore b/.gitignore
index acbc8c8..241f3f0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,8 +1,10 @@
vendor/
build/
bin/
-tests/index.php
-
+.idea/
+.github/
+.phpunit.result.cache
+test-results.xml
# Commit your application's lock file http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file
# You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file
diff --git a/LICENSE b/LICENSE
old mode 100644
new mode 100755
diff --git a/README.fr.md b/README.fr.md
deleted file mode 100644
index 03ca584..0000000
--- a/README.fr.md
+++ /dev/null
@@ -1,15 +0,0 @@
-odtphp
-======
-
-Générateur de document ODT à partir de PHP
-
-Projet initial (version 1.0.1) : http://www.odtphp.com/ (le site ne répond plus).
-
-Le répertoire "tests" contient les exemples publiés sur ce site disparu.
-
-Intégration des modifications de : http://vikasmahajan.wordpress.com/2010/12/09/odtphp-bug-solved/
-Résoud les bugs d'insertion d'image et d'insertion dans l'en-tête et le pied de page.
-
-J'explore ce projet qui semble "Ã l'abandon" mais fait parfaitement ce dont j'ai besoin.
-
-J'intégrerai ici mes modestes contributions et/ou exemples.
diff --git a/README.md b/README.md
index 7cf3140..5dbc2ee 100644
--- a/README.md
+++ b/README.md
@@ -1,16 +1,364 @@
-odtphp
-======
-### Original description
+# ODTPHP
-OdtPHP is a library to quickly generate Open Document Text-files that can be read by a [gigantic set][3] of Office Suites, including LibreOffice, OpenOffice and even Microsoft Office from PHP code. It uses a simple templating mechanism.
-See the tests/ folder for a set of examples.
+A PHP library for creating and manipulating ODT (OpenDocument Text) files.
+
+## Requirements
+
+- PHP 8.1 or higher
+- PHP ZIP Extension or PclZip library. PHP ZIP Extension is recommended as we will probably
+ remove the PclZip library sometime in the future.
+
+## Installation
+
+Install via Composer:
+
+```bash
+composer require sboden/odtphp:^3
+```
+
+## Basic Usage
+
+### Simple Variable Substitution
+
+```php
+setVars('company_name', 'ACME Corporation');
+$odt->setVars('current_date', date('Y-m-d'));
+
+// Save the modified document
+$odt->saveToDisk('output.odt');
+```
+
+### Advanced Usage with Images and Segments
+
+```php
+ '{',
+ 'DELIMITER_RIGHT' => '}',
+];
+$odt = new Odf("invoice_template.odt", $config);
+
+// Insert a company logo
+$odt->setImage('company_logo', 'path/to/logo.png');
+
+// Create a repeatable segment for line items
+$lineItems = $odt->setSegment('invoice_items');
+foreach ($invoiceData['items'] as $item) {
+ $lineItems->setVars('item_name', $item->name);
+ $lineItems->setVars('item_price', number_format($item->price, 2));
+ $lineItems->setVars('item_quantity', $item->quantity);
+ $lineItems->merge();
+}
+
+// Set summary variables
+$odt->setVars('total_amount', number_format($invoiceData['total'], 2));
+$odt->setVars('invoice_number', $invoiceData['number']);
+
+// Save the completed invoice
+$odt->saveToDisk('invoice.odt');
+```
+
+### Error Handling
+
+```php
+setVars('non_existent_variable', 'Some Value');
+} catch (OdfException $e) {
+ // Handle template-related errors
+ error_log("ODT Processing Error: " . $e->getMessage());
+}
+```
+
+### Testing
+
+1. Install dependencies:
+```
+composer install
+```
+
+2. Run the tests:
+
+On Linux:
+```bash
+# Go to the root of odtphp, then:
+./run-tests.sh
+```
+
+On Windows:
+```bash
+# Go to the root of odtphp, then:
+run-tests.bat
+
+# Note that depending on your PHP installation you may have to edit the
+# script to include the path to php.exe
+```
+
+You can also run the PHPUnit tests e.g. in PHPStorm, but you have to exclude
+the vendor directory to avoid warnings about the PHPUnit framework itself.
+
+
+#### Test Structure
+
+The test suite covers various aspects of the ODT templating functionality:
+
+1. **Basic Tests** (`Basic1Test.php` and `Basic2Test.php`):
+ - Verify basic variable substitution in ODT templates
+ - Test both PhpZip and PclZip ZIP handling methods
+ - Demonstrate simple text replacement and encoding
+
+2. **Configuration Tests** (`ConfigTest.php`):
+ - Validate configuration handling
+ - Test custom delimiters
+ - Check error handling for invalid configurations
+
+3. **Edge Case Tests** (`EdgeCaseTest.php`):
+ - Handle complex scenarios like:
+ * Large variable substitution
+ * Nested segment merging
+ * Special character encoding
+ * Advanced image insertion
+ * Invalid template handling
+
+4. **Image Tests** (`ImageTest.php`):
+ - Verify image insertion functionality
+ - Test image resizing
+ - Check error handling for invalid image paths
+
+5. **Variable Tests** (`VariableTest.php`):
+ - Test variable existence checks
+ - Verify special character handling
+ - Check multiline text substitution
+
+Each test is designed to ensure the robustness and reliability of the ODT
+templating library across different use cases and configurations.
+
+Each test is run twice:
+- Once using PclZip library
+- Once using PHP's native Zip extension
+
+The tests generate ODT files and compare them with gold standard files located in:
+- `tests/src/files/gold_phpzip/` - Gold files for PHP Zip tests
+- `tests/src/files/gold_pclzip/` - Gold files for PclZip tests
+
+
+### Linting
+
+On Linux:
+```bash
+# Go to the root of odtphp, then:
+composer install
+vendor/bin/phpcs --standard="Drupal,DrupalPractice" -n --extensions="php,module,inc,install,test,profile,theme" src
+```
+
+
+## Features
+
+- Template variable substitution
+- Image insertion and manipulation
+- Segment management for repeatable content
+- Support for custom delimiters
+- Type-safe implementation
+- Modern PHP 8.1+ features
+
+## Configuration
+
+```php
+$config = [
+ 'ZIP_PROXY' => \Odtphp\Zip\PhpZipProxy::class, // or PclZipProxy
+ 'DELIMITER_LEFT' => '{',
+ 'DELIMITER_RIGHT' => '}',
+ 'PATH_TO_TMP' => '/tmp'
+];
+
+$odt = new Odf("template.odt", $config);
+```
+
+## Type Safety
+
+This library is built with PHP 8.1's type system in mind:
+- Strict typing enabled
+- Property type declarations
+- Return type declarations
+- Parameter type hints
+- Improved error handling
+
+## Contributing
+
+Contributions are welcome! Please feel free to submit a Pull Request.
+
+## License
+
+This project is licensed under the GPL-3.0 License - see the LICENSE file for details.
+
+The GPL-3.0 license is because of what the cybermonde/odtphp author put it
+to, I (sboden) don't want to change it. I don't consider odtphp to be "my" software, I
+only tried to make the cybermonde/odtphp fork work properly in PHP v8.3
+and beyond.
+
+Personally (sboden) I would have used an MIT or BSD license for odtphp, but I
+will happily abide with the original author's intent.
+
+The original version/source code of odtphp is at [https://sourceforge.
+net/projects/odtphp/](https://sourceforge.net/projects/odtphp/). The
+cybermonde/odtphp fork I started from is at [https://github.
+com/cybermonde/odtphp](https://github.com/cybermonde/odtphp).
+
+
+### Usage justification
+How and why we use odtphp in our projects.
+
+Some of our projects send out letters (either PDF or on physical paper) to people:
+the idea is to have a nice template, fill in some data, create a PDF file from the
+filled-in template, and send the resulting PDF to the recipient.
+
+The template is an ODT file, the data is stored in a database. We use odtphp to fill
+in the template. The filled-in ODT file is then transformed into a PDF file using
+(originally) jodconverter, and in newer projects using gotenberg.dev (which is
+essentially jodconverter using golang). The PDF converters run in a different
+container than the main applications.
+
+The reason for using gotenberg over jodconverter is that gotenberg is better
+supported. And jodconverter was initially not able to handle large volumes since
+the most commonly used Docker container did not clean up after itself, so I had to
+build this in myself.
+
+Why not generate PDFs directly from PHP? We tried, but it's difficult to
+have nice-looking PDFs using the existing PHP libraries. One PHP library has
+problems with images, another PHP PDF library faces issues with margins and
+headers/footers, ... We tried a lot of different setups and finally settled
+for odtphp/gotenberg to have the PDF output "pixel perfect". Another
+limitation was that we needed about 50,000 PDFs per day for which we run
+parallel queues to the PDF converters.
+
+
+### Technical tidbits
+
+#### Why do my variables sometimes not get filled in?
+
+Because LibreOffice adds metadata to what you change. E.g. when you have
+something as follows in your ODT file:
+
+```
+{variable_text}
+```
+
+And you make a small change to the previous text it may very well end up as:
+
+```
+{variables _text}]
+```
+where you don't see the "text:span" part visually, but it is there. And since
+odtphp plainly matches variables in an ODT file, the variable name will not match
+anymore and will not be replaced.
+
+How to get around that: When you change variable texts, select the variable
+text (including the begin and end delimiters), copy it, and then use "Paste
+special/Paste unformatted text" to copy the text in the same place without any
+invisible metadata.
+
+
+#### Why does "Catégorie 1" sometimes appear as "Catégorie 1" in the output?
+
+Usually this is a double-encoding problem. When UTF-8 text is encoded again
+as UTF-8, special characters like 'é' can appear as 'é'. This typically
+happens when the text is already in UTF-8 but gets encoded again.
+
+While setting variables you can specify the encoding as needed, e.g. as:
+
+```php
+$categorie->setVars('TitreCategorie', 'Catégorie 1', true, 'UTF-8');
+```
+
+
+#### The default charset has changed?
+
+One of the "major" changes I made is to put UTF-8 as the default charset when
+setting variables. Before the default was ISO-8859-1, but UTF-8 currently
+makes sense to me.
+
+I always recommend using UTF-8 internally within the application and
+handling encoding/decoding at the boundaries.
+
+#### How do I upgrade from v1/v2 to v3?
+
+While it is a breaking change, as long as you only use `odtphp` and don't use
+any of its internals you should be fine by just upgrading the odtphp library
+to v3.
+
+If you inherit from Odf or you use some internal things in the odtphp library,
+then all bets are off.
-This repository already includes the changes suggested by [Vikas Mahajan][1] and a number of other bug fixes.
### History
-This project was initially started by Julien Pauli, Olivier Booklage, Vincent Brouté and published at [http://www.odtphp.com][2] (link leads to archived version of page, as it is not available any longer).
+The odtphp project was initially started by Julien Pauli, Olivier Booklage,
+Vincent Brouté and published at http://www.odtphp.com (the website no longer
+exists).
+
+As DXC Technology working for the Flemish government we started using
+the `cybermonde/odtphp` fork ([source](https://github.com/cybermonde/odtphp))
+in a couple of projects to fill in template ODT files with data.
+We ran into a couple of problems with the `cybermonde/odtphp` library for
+which it was easier to just create my own fork, hence `sboden/odtphp`: we
+sometimes generate 50,000 forms daily, and `cybermonde/odtphp` would
+occasionally overwrite outputs when processing a lot of ODT files
+simultaneously because of non-random random numbers.
+
+Why do I try to keep this "corpse" alive? Simply because I found no
+replacement for it. The projects I work that use odtphp are now (= end 2024) on
+PHP 8.2 moving to PHP 8.3, and some pieces of the original odtphp library
+are starting to spew warnings. During my 2024 Christmas holidays I was
+writing some unit test cases for odtphp, and while testing the AI tool
+"Windsurf", I tried to have Windsurf automatically update odtphp to a newer
+PHP version, and sboden/odtphp v3 is the result of that (after some extra
+manual human changes).
+
+While this fork `sboden/odtphp` is not officially supported, maintenance
+and bug fixes are provided on a best-effort basis. The `sboden/odtphp` library
+is actively used in production applications with planned lifecycles extending
+to 2030.
+
+This software is **not** by DXC Technology, else it would have been called
+`dxc/odtphp`. This software is **not** by the Flemish government, else it
+would probably have been called `vo/odtphp`. I have always worked on odtphp
+during my personal time.
+
+### Version History
+- v3.0.3 - 29Dec2024: odtphp version for PHP 8.x
+- v2.2.1 - 07Dec2022: Parallel processing by odtphp does not overwrite outputs.
+
+### Disclaimer
+
+This software is provided "as is" without warranty of any kind, either
+expressed or implied. The entire risk as to the quality and performance of
+the software is with you.
+
+In no event will the authors, contributors, or licensors be liable for any
+damages, including but not limited to, direct, indirect, special, incidental,
+or consequential damages arising out of the use or inability to use this
+software, even if advised of the possibility of such damage.
+
+By using this software, you acknowledge that you have read this disclaimer,
+understand it, and agree to be bound by its terms.
+
### Links:
@@ -18,4 +366,4 @@ This project was initially started by Julien Pauli, Olivier Booklage, Vincent Br
[1]: http://vikasmahajan.wordpress.com/2010/12/09/odtphp-bug-solved/
[2]: https://web.archive.org/web/20120531095719/http://www.odtphp.com/index.php?i=home
-[3]: https://en.wikipedia.org/wiki/OpenDocument_software#Text_documents_.28.odt.29
\ No newline at end of file
+[3]: https://en.wikipedia.org/wiki/OpenDocument_software#Text_documents_.28.odt.29
diff --git a/composer.json b/composer.json
old mode 100644
new mode 100755
index cd8cac5..66dec65
--- a/composer.json
+++ b/composer.json
@@ -1,20 +1,22 @@
{
- "name": "cybermonde/odtphp",
- "description": "ODT document generator",
+ "name": "sboden/odtphp",
+ "description": "ODT document generator (plugin replacement for cybermonde/odtphp)",
"keywords": [
"odt",
"php"
],
- "license": "GPL-3.0",
+ "license": "GPL-3.0-only",
"type": "library",
- "homepage": "https://github.com/cybermonde/odtphp",
+ "homepage": "https://github.com/sboden/odtphp",
"require": {
- "php": ">=5.2.4"
+ "php": ">=8.1"
},
"require-dev": {
- "phpunit/phpunit" : "4.*",
- "scrutinizer/ocular": "~1.1",
- "symfony/var-dumper": "^2.7"
+ "dealerdirect/phpcodesniffer-composer-installer": "^1.0",
+ "drupal/coder": "^8.3",
+ "phpunit/phpunit": "^10.4",
+ "scrutinizer/ocular": "^1.9",
+ "symfony/var-dumper": "^6.4"
},
"autoload": {
"psr-4": {
@@ -28,6 +30,13 @@
},
"files": ["lib/pclzip.lib.php"]
},
+ "config": {
+ "sort-packages": true,
+ "optimize-autoloader": true,
+ "allow-plugins": {
+ "dealerdirect/phpcodesniffer-composer-installer": true
+ }
+ },
"extra": {
"branch-alias": {
"dev-master": "2.0-dev"
diff --git a/documentation/odtphp_documentation.pdf b/documentation/odtphp_documentation.pdf
old mode 100644
new mode 100755
diff --git a/examples/form.php b/examples/form.php
new file mode 100755
index 0000000..8315cf7
--- /dev/null
+++ b/examples/form.php
@@ -0,0 +1,67 @@
+//////////////////////////////////////////////////////////////
+// ODT Letter Generation Based on a Form //
+// //
+// Laurent Lefèvre - http://www.cybermonde.org //
+// //
+//////////////////////////////////////////////////////////////
+
+// This is a left over example from cybermonde/odtphp, I left it
+// partially in French.
+
+use Odtphp\Odf;
+
+// Make sure you have Zip extension or PclZip library loaded.
+// First : include the library.
+require_once '../vendor/autoload.php';
+
+// base model
+$odf = new Odf("form_template.odt");
+// if nothing has been posted, show the form
+if (!$_POST) {
+?>
+
+
+
+ Form to ODT
+
+
+
+
+
+
+
+setVars('cyb_date', date("d/m/Y"));
+// form data
+$odf->setVars('cyb_invite', $_POST["invite"]);
+// Handle accented characters using this HTML entity decode trick.
+$odf->setVars('cyb_firstname', html_entity_decode(htmlentities($_POST["firstname"],ENT_NOQUOTES, "utf-8")));
+$odf->setVars('cyb_lastname', html_entity_decode(htmlentities($_POST["lastname"],ENT_NOQUOTES, "utf-8")));
+$odf->setVars('cyb_total', $_POST["total"]);
+
+$odf->exportAsAttachedFile();
+}
diff --git a/exemple_form/formulaire_template.odt b/examples/form_template.odt
similarity index 100%
rename from exemple_form/formulaire_template.odt
rename to examples/form_template.odt
diff --git a/tests/images/anaska.gif b/examples/images/anaska.gif
similarity index 100%
rename from tests/images/anaska.gif
rename to examples/images/anaska.gif
diff --git a/tests/images/anaska.jpg b/examples/images/anaska.jpg
similarity index 100%
rename from tests/images/anaska.jpg
rename to examples/images/anaska.jpg
diff --git a/tests/images/apache.gif b/examples/images/apache.gif
similarity index 100%
rename from tests/images/apache.gif
rename to examples/images/apache.gif
diff --git a/tests/images/mysql.gif b/examples/images/mysql.gif
similarity index 100%
rename from tests/images/mysql.gif
rename to examples/images/mysql.gif
diff --git a/tests/images/php.gif b/examples/images/php.gif
similarity index 100%
rename from tests/images/php.gif
rename to examples/images/php.gif
diff --git a/tests/simplecheck.odt b/examples/simplecheck.odt
similarity index 100%
rename from tests/simplecheck.odt
rename to examples/simplecheck.odt
diff --git a/tests/simplecheck.php b/examples/simplecheck.php
similarity index 84%
rename from tests/simplecheck.php
rename to examples/simplecheck.php
index f16f5b9..b5626f9 100755
--- a/tests/simplecheck.php
+++ b/examples/simplecheck.php
@@ -1,112 +1,110 @@
-open($filename) !== true )
- {
- throw new OdfException("Error while Opening the file '$filename' - Check your odt file");
- }
-
- // read content.xml from the oasis document
-
- if (($contentXml = $file->getFromName('content.xml')) === false)
- {
- throw new OdfException("Nothing to parse - check that the content.xml file is correctly formed");
- }
-
- // close the original oasis document
-
- $file->close();
-
- // for futur use, with load content.xml via DOMDocument library :
-
- $odt_content = new DOMDocument('1.0', 'utf-8');
- if ($odt_content->loadXML( $contentXml ) == FALSE)
- {
- throw new OdfException('Unable to load content.xml by DOMDocument library ', __METHOD__);
- }
-
- // here, we dont use the temp function but local temporary file
-
- $tmpfile = md5(uniqid()).'.odt';
- if( !@copy($filename, $tmpfile) );
- {
- // we do not test, because sometime it return false anyway !!
- // $errors = error_get_last();
- // throw new OdfException("Can not copy the tempfile in $tmpfile :[".$errors['message'] ."]/[".$errors['type']."]");
- }
-
- // futur use here : $odt_content modifications ...
-
-
-
-
- // open the temporary zipfile
-
- if( $file->open($tmpfile, ZIPARCHIVE::CREATE) != TRUE )
- {
- @unlink($tmpfile); // erase temporary file
- throw new OdfException("Error while Opening the tempfile '$tmpfile' - Check your odt file");
- }
-
- // for futur use here : with overwrite content.xml in zip file via DOMDocument library :
-
- if (! $file->addFromString('content.xml', $odt_content->saveXML()) )
- {
- @unlink($tmpfile); // erase temporary file
- throw new OdfException('Error during file export');
- }
-
- // close the temporary zipfile
-
- $file->close();
-
- // send the new checkresult.odt file via http :
-
- $name = "checkresult.odt";
- $size = filesize($tmpfile);
- header('Content-type: application/vnd.oasis.opendocument.text');
- header('Content-Disposition: attachment; filename="'.$name.'"');
- header("Content-Length: ".$size);
- readfile($tmpfile); // output
- @unlink($tmpfile); // erase temporary file
- exit; // be sure nothing else is write after
-
-?>
\ No newline at end of file
+open($filename) !== true )
+ {
+ throw new OdfException("Error while Opening the file '$filename' - Check your odt file");
+ }
+
+ // read content.xml from the oasis document
+
+ if (($contentXml = $file->getFromName('content.xml')) === false)
+ {
+ throw new OdfException("Nothing to parse - check that the content.xml file is correctly formed");
+ }
+
+ // close the original oasis document
+
+ $file->close();
+
+ // for futur use, with load content.xml via DOMDocument library :
+
+ $odt_content = new DOMDocument('1.0', 'utf-8');
+ if ($odt_content->loadXML( $contentXml ) == FALSE)
+ {
+ throw new OdfException('Unable to load content.xml by DOMDocument library ', __METHOD__);
+ }
+
+ // here, we dont use the temp function but local temporary file
+
+ $tmpfile = md5(uniqid()).'.odt';
+ if( !@copy($filename, $tmpfile) );
+ {
+ // we do not test, because sometime it return false anyway !!
+ // $errors = error_get_last();
+ // throw new OdfException("Can not copy the tempfile in $tmpfile :[".$errors['message'] ."]/[".$errors['type']."]");
+ }
+
+ // futur use here : $odt_content modifications ...
+
+
+
+
+ // open the temporary zipfile
+
+ if( $file->open($tmpfile, ZIPARCHIVE::CREATE) != TRUE )
+ {
+ @unlink($tmpfile); // erase temporary file
+ throw new OdfException("Error while Opening the tempfile '$tmpfile' - Check your odt file");
+ }
+
+ // for futur use here : with overwrite content.xml in zip file via DOMDocument library :
+
+ if (! $file->addFromString('content.xml', $odt_content->saveXML()) )
+ {
+ @unlink($tmpfile); // Erase temporary file.
+ throw new OdfException('Error during file export');
+ }
+
+ // Close the temporary zipfile.
+
+ $file->close();
+
+ // Send the new checkresult.odt file via http:
+
+ $name = "checkresult.odt";
+ $size = filesize($tmpfile);
+ header('Content-type: application/vnd.oasis.opendocument.text');
+ header('Content-Disposition: attachment; filename="' . $name . '"');
+ header("Content-Length: " . $size);
+ readfile($tmpfile); // Output.
+ @unlink($tmpfile); // Erase temporary file.
+ exit; // Be sure nothing else is write after.
diff --git a/tests/tutoriel1.odt b/examples/tutorial1.odt
similarity index 100%
rename from tests/tutoriel1.odt
rename to examples/tutorial1.odt
diff --git a/tests/tutorial1.php b/examples/tutorial1.php
similarity index 63%
rename from tests/tutorial1.php
rename to examples/tutorial1.php
index 2761985..521cc33 100755
--- a/tests/tutorial1.php
+++ b/examples/tutorial1.php
@@ -4,9 +4,10 @@
ini_set('display_errors', 1);
/**
- * Tutoriel file
+ * Tutorial file
* Description : Simple substitutions of variables
- * You need PHP 5.2 at least
+ *
+ * You need PHP 8.1 at least
* You need Zip Extension or PclZip library
*
* @copyright GPL License 2008 - Julien Pauli - Cyril PIERRE de GEYER - Anaska (http://www.anaska.com)
@@ -16,14 +17,16 @@
use Odtphp\Odf;
-// Make sure you have Zip extension or PclZip library loaded
-// First : include the librairy
+// Make sure you have Zip extension or PclZip library loaded.
+// First : include the library.
require_once '../vendor/autoload.php';
-$odf = new Odf("tutoriel1.odt");
+$odf = new Odf("tutorial1.odt");
-$odf->setVars('titre', 'PHP: Hypertext PreprocessorPHP: Hypertext Preprocessor');
+$odf->setVars('titre', 'PHP: Hypertext Preprocessor');
+// The original version was French, and we keep it in French to see the accents
+// be outputted correctly.
$message = "PHP (sigle de PHP: Hypertext Preprocessor), est un langage de scripts libre
principalement utilisé pour produire des pages Web dynamiques via un serveur HTTP, mais
pouvant également fonctionner comme n'importe quel langage interprété de façon locale,
@@ -31,5 +34,6 @@
$odf->setVars('message', $message);
-// We export the file
+// We export the file. Note that the output will appear on stdout.
+// If you want to capture it, use something as " > output.odt".
$odf->exportAsAttachedFile();
diff --git a/tests/tutoriel2.odt b/examples/tutorial2.odt
similarity index 100%
rename from tests/tutoriel2.odt
rename to examples/tutorial2.odt
diff --git a/examples/tutorial2.php b/examples/tutorial2.php
new file mode 100755
index 0000000..d0f419c
--- /dev/null
+++ b/examples/tutorial2.php
@@ -0,0 +1,35 @@
+setVars('titre','Anaska formation');
+
+$message = "Anaska, leader français de la formation informatique sur les technologies
+Open Source, propose un catalogue de plus de 50 formations, dont certaines préparent
+aux certifications Linux, MySQL, PHP et PostgreSQL.";
+
+$odf->setVars('message', $message);
+
+$odf->setImage('image', './images/anaska.jpg');
+
+// We export the file. Note that the output will appear on stdout.
+// If you want to capture it, use something as " > output.odt".
+$odf->exportAsAttachedFile();
diff --git a/tests/tutoriel3.odt b/examples/tutorial3.odt
similarity index 100%
rename from tests/tutoriel3.odt
rename to examples/tutorial3.odt
diff --git a/examples/tutorial3.php b/examples/tutorial3.php
new file mode 100755
index 0000000..7d02820
--- /dev/null
+++ b/examples/tutorial3.php
@@ -0,0 +1,54 @@
+setVars('titre', 'Quelques articles de l\'encyclopédie Wikipédia');
+
+$message = "PHP (sigle de PHP: Hypertext Preprocessor), est un langage de scripts libre
+principalement utilisé pour produire des pages Web dynamiques via un serveur HTTP, mais
+pouvant également fonctionner comme n'importe quel langage interprété de façon locale,
+en exécutant les programmes en ligne de commande.";
+
+$odf->setVars('message', $message);
+
+$listeArticles = array(
+ array( 'titre' => 'PHP',
+ 'texte' => 'PHP (sigle de PHP: Hypertext Preprocessor), est un langage de scripts (...)',
+ ),
+ array( 'titre' => 'MySQL',
+ 'texte' => 'MySQL est un système de gestion de base de données (SGBD). Selon le (...)',
+ ),
+ array( 'titre' => 'Apache',
+ 'texte' => 'Apache HTTP Server, souvent appelé Apache, est un logiciel de serveur (...)',
+ ),
+);
+
+$article = $odf->setSegment('articles');
+foreach($listeArticles AS $element) {
+ $article->titreArticle($element['titre']);
+ $article->texteArticle($element['texte']);
+ $article->merge();
+}
+$odf->mergeSegment($article);
+
+// We export the file. Note that the output will appear on stdout.
+// If you want to capture it, use something as " > output.odt".
+$odf->exportAsAttachedFile();
diff --git a/tests/tutoriel4.odt b/examples/tutorial4.odt
similarity index 100%
rename from tests/tutoriel4.odt
rename to examples/tutorial4.odt
diff --git a/tests/tutoriel4.php b/examples/tutorial4.php
similarity index 60%
rename from tests/tutoriel4.php
rename to examples/tutorial4.php
index 7d80172..8481786 100755
--- a/tests/tutoriel4.php
+++ b/examples/tutorial4.php
@@ -1,42 +1,43 @@
-setVars('titre','Articles disponibles :');
-
-$categorie = $odf->setSegment('categories');
-for ($j = 1; $j <= 2; $j++) {
- $categorie->setVars('TitreCategorie', 'Catégorie ' . $j);
- for ($i = 1; $i <= 3; $i++) {
- $categorie->articles->titreArticle('Article ' . $i);
- $categorie->articles->date(date('d/m/Y'));
- $categorie->articles->merge();
- }
- for ($i = 1; $i <= 4; $i++) {
- $categorie->commentaires->texteCommentaire('Commentaire ' . $i);
- $categorie->commentaires->merge();
- }
- $categorie->merge();
-}
-$odf->mergeSegment($categorie);
-
-// We export the file
-$odf->exportAsAttachedFile();
-
-?>
+setVars('titre','Articles disponibles:');
+
+$categorie = $odf->setSegment('categories');
+for ($j = 1; $j <= 2; $j++) {
+ $categorie->setVars('TitreCategorie', 'Catégorie ' . $j);
+ for ($i = 1; $i <= 3; $i++) {
+ $categorie->articles->titreArticle('Article ' . $i);
+ $categorie->articles->date(date('d/m/Y'));
+ $categorie->articles->merge();
+ }
+ for ($i = 1; $i <= 4; $i++) {
+ $categorie->commentaires->texteCommentaire('Commentaire ' . $i);
+ $categorie->commentaires->merge();
+ }
+ $categorie->merge();
+}
+$odf->mergeSegment($categorie);
+
+// We export the file. Note that the output will appear on stdout.
+// If you want to capture it, use something as " > output.odt."
+$odf->exportAsAttachedFile();
diff --git a/examples/tutorial5.odt b/examples/tutorial5.odt
new file mode 100755
index 0000000..e8fea2c
Binary files /dev/null and b/examples/tutorial5.odt differ
diff --git a/tests/tutoriel5.php b/examples/tutorial5.php
similarity index 50%
rename from tests/tutoriel5.php
rename to examples/tutorial5.php
index 1c1ed1a..05b07ae 100755
--- a/tests/tutoriel5.php
+++ b/examples/tutorial5.php
@@ -1,57 +1,58 @@
-setVars('titre', 'Quelques articles de l\'encyclopédie Wikipédia');
-
-$message = "La force de cette encyclopédie en ligne réside dans son nombre important de
- contributeurs. Ce sont en effet des millions d'articles qui sont disponibles dans la langue
- de Shakespeare et des centaines de milliers d'autres dans de nombreuses langues dont
- le français, l'espagnol, l'italien, le turc ou encore l'allemand.";
-
-$odf->setVars('message', $message);
-
-$listeArticles = array(
- array( 'titre' => 'PHP',
- 'texte' => 'PHP (sigle de PHP: Hypertext Preprocessor), est un langage de scripts (...)',
- 'image' => './images/php.gif'
- ),
- array( 'titre' => 'MySQL',
- 'texte' => 'MySQL est un système de gestion de base de données (SGDB). Selon le (...)',
- 'image' => './images/mysql.gif'
- ),
- array( 'titre' => 'Apache',
- 'texte' => 'Apache HTTP Server, souvent appelé Apache, est un logiciel de serveur (...)',
- 'image' => './images/apache.gif'
- )
-);
-
-$article = $odf->setSegment('articles');
-foreach($listeArticles AS $element) {
- $article->titreArticle($element['titre']);
- $article->texteArticle($element['texte']);
- $article->setImage('image', $element['image']);
- $article->merge();
-}
-$odf->mergeSegment($article);
-
-// We export the file
-$odf->exportAsAttachedFile();
-
-?>
\ No newline at end of file
+setVars('titre', 'Quelques articles de l\'encyclopédie Wikipédia');
+
+$message = "La force de cette encyclopédie en ligne réside dans son nombre important de
+contributeurs. Ce sont en effet des millions d'articles qui sont disponibles dans la langue
+de Shakespeare et des centaines de milliers d'autres dans de nombreuses langues dont
+le français, l'espagnol, l'italien, le turc ou encore l'allemand.";
+
+$odf->setVars('message', $message);
+
+$listeArticles = array(
+ array( 'titre' => 'PHP',
+ 'texte' => 'PHP (sigle de PHP: Hypertext Preprocessor), est un langage de scripts (...)',
+ 'image' => './images/php.gif'
+ ),
+ array( 'titre' => 'MySQL',
+ 'texte' => 'MySQL est un système de gestion de base de données (SGBD). Selon le (...)',
+ 'image' => './images/mysql.gif'
+ ),
+ array( 'titre' => 'Apache',
+ 'texte' => 'Apache HTTP Server, souvent appelé Apache, est un logiciel de serveur (...)',
+ 'image' => './images/apache.gif'
+ )
+);
+
+$article = $odf->setSegment('articles');
+foreach($listeArticles AS $element) {
+ $article->titreArticle($element['titre']);
+ $article->texteArticle($element['texte']);
+ $article->setImage('image', $element['image']);
+ $article->merge();
+}
+$odf->mergeSegment($article);
+
+// We export the file. Note that the output will appear on stdout.
+// If you want to capture it, use something as " > output.odt."
+$odf->exportAsAttachedFile();
diff --git a/tests/tutoriel6.odt b/examples/tutorial6.odt
similarity index 100%
rename from tests/tutoriel6.odt
rename to examples/tutorial6.odt
diff --git a/examples/tutorial6.php b/examples/tutorial6.php
new file mode 100755
index 0000000..3e3ee11
--- /dev/null
+++ b/examples/tutorial6.php
@@ -0,0 +1,54 @@
+setVars('titre', 'Quelques articles de l\'encyclopédie Wikipédia');
+
+$message = "PHP (sigle de PHP: Hypertext Preprocessor), est un langage de scripts libre
+principalement utilisé pour produire des pages Web dynamiques via un serveur HTTP, mais
+pouvant également fonctionner comme n'importe quel langage interprété de façon locale,
+en exécutant les programmes en ligne de commande.";
+
+$odf->setVars('message', $message);
+
+$listeArticles = array(
+ array( 'titre' => 'PHP',
+ 'texte' => 'PHP (sigle de PHP: Hypertext Preprocessor), est un langage de scripts (...)',
+ ),
+ array( 'titre' => 'MySQL',
+ 'texte' => 'MySQL est un système de gestion de base de données (SGBD). Selon le (...)',
+ ),
+ array( 'titre' => 'Apache',
+ 'texte' => 'Apache HTTP Server, souvent appelé Apache, est un logiciel de serveur (...)',
+ ),
+);
+
+$article = $odf->setSegment('articles');
+foreach($listeArticles AS $element) {
+ $article->titreArticle($element['titre']);
+ $article->texteArticle($element['texte']);
+ $article->merge();
+}
+$odf->mergeSegment($article);
+
+// We export the file. Note that the output will appear on stdout.
+// If you want to capture it, use something as " > output.odt".
+$odf->exportAsAttachedFile();
diff --git a/tests/tutoriel7.odt b/examples/tutorial7.odt
similarity index 100%
rename from tests/tutoriel7.odt
rename to examples/tutorial7.odt
diff --git a/examples/tutorial7.php b/examples/tutorial7.php
new file mode 100755
index 0000000..cbd501b
--- /dev/null
+++ b/examples/tutorial7.php
@@ -0,0 +1,40 @@
+ \Odtphp\Zip\PhpZipProxy::class, // Make sure you have Zip extension loaded.
+ 'DELIMITER_LEFT' => '#', // Yan can also change delimiters.
+ 'DELIMITER_RIGHT' => '#'
+);
+
+$odf = new Odf("tutorial7.odt", $config);
+
+$odf->setVars('titre', 'PHP: Hypertext Preprocessor');
+
+$message = "PHP (sigle de PHP: Hypertext Preprocessor), est un langage de scripts libre
+principalement utilisé pour produire des pages Web dynamiques via un serveur HTTP, mais
+pouvant également fonctionner comme n'importe quel langage interprété de façon locale,
+en exécutant les programmes en ligne de commande.";
+
+$odf->setVars('message', $message);
+
+// We export the file. Note that the output will appear on stdout.
+// If you want to capture it, use something as " > output.odt".
+$odf->exportAsAttachedFile();
diff --git a/exemple_form/README.md b/exemple_form/README.md
deleted file mode 100644
index 4f8479a..0000000
--- a/exemple_form/README.md
+++ /dev/null
@@ -1,6 +0,0 @@
-exemple_form
-============
-
-Génération d'un courrier ODT sur base d'un formulaire.
-
-Version simple, sans mise en forme, pour l'exemple.
diff --git a/exemple_form/formulaire.php b/exemple_form/formulaire.php
deleted file mode 100755
index 1dbfb5d..0000000
--- a/exemple_form/formulaire.php
+++ /dev/null
@@ -1,64 +0,0 @@
-
-
-
-
- Formulaire vers ODT
-
-
-
-
-
-
-
-setVars('cyb_date', date("d/m/Y"));
-// données du formulaire
-$odf->setVars('cyb_invite', $_POST["invite"]);
-// gestion des accents via cet artifice html_entity_decode(htmlentities(...
-$odf->setVars('cyb_prenom', html_entity_decode(htmlentities($_POST["prenom"],ENT_NOQUOTES, "utf-8")));
-$odf->setVars('cyb_nom', html_entity_decode(htmlentities($_POST["nom"],ENT_NOQUOTES, "utf-8")));
-$odf->setVars('cyb_total', $_POST["total"]);
-// création du fichier
-$odf->exportAsAttachedFile();
-}
-?>
diff --git a/lib/pclzip.lib.php b/lib/pclzip.lib.php
old mode 100644
new mode 100755
index c624cc0..6cb5dd3
--- a/lib/pclzip.lib.php
+++ b/lib/pclzip.lib.php
@@ -1,5700 +1,5464 @@
-zipname = $p_zipname;
- $this->zip_fd = 0;
- $this->magic_quotes_status = -1;
-
- // ----- Return
- return;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function :
- // create($p_filelist, $p_add_dir="", $p_remove_dir="")
- // create($p_filelist, $p_option, $p_option_value, ...)
- // Description :
- // This method supports two different synopsis. The first one is historical.
- // This method creates a Zip Archive. The Zip file is created in the
- // filesystem. The files and directories indicated in $p_filelist
- // are added in the archive. See the parameters description for the
- // supported format of $p_filelist.
- // When a directory is in the list, the directory and its content is added
- // in the archive.
- // In this synopsis, the function takes an optional variable list of
- // options. See bellow the supported options.
- // Parameters :
- // $p_filelist : An array containing file or directory names, or
- // a string containing one filename or one directory name, or
- // a string containing a list of filenames and/or directory
- // names separated by spaces.
- // $p_add_dir : A path to add before the real path of the archived file,
- // in order to have it memorized in the archive.
- // $p_remove_dir : A path to remove from the real path of the file to archive,
- // in order to have a shorter path memorized in the archive.
- // When $p_add_dir and $p_remove_dir are set, $p_remove_dir
- // is removed first, before $p_add_dir is added.
- // Options :
- // PCLZIP_OPT_ADD_PATH :
- // PCLZIP_OPT_REMOVE_PATH :
- // PCLZIP_OPT_REMOVE_ALL_PATH :
- // PCLZIP_OPT_COMMENT :
- // PCLZIP_CB_PRE_ADD :
- // PCLZIP_CB_POST_ADD :
- // Return Values :
- // 0 on failure,
- // The list of the added files, with a status of the add action.
- // (see PclZip::listContent() for list entry format)
- // --------------------------------------------------------------------------------
- function create($p_filelist)
- {
- $v_result=1;
-
- // ----- Reset the error handler
- $this->privErrorReset();
-
- // ----- Set default values
- $v_options = array();
- $v_options[PCLZIP_OPT_NO_COMPRESSION] = FALSE;
-
- // ----- Look for variable options arguments
- $v_size = func_num_args();
-
- // ----- Look for arguments
- if ($v_size > 1) {
- // ----- Get the arguments
- $v_arg_list = func_get_args();
-
- // ----- Remove from the options list the first argument
- array_shift($v_arg_list);
- $v_size--;
-
- // ----- Look for first arg
- if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
-
- // ----- Parse the options
- $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
- array (PCLZIP_OPT_REMOVE_PATH => 'optional',
- PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
- PCLZIP_OPT_ADD_PATH => 'optional',
- PCLZIP_CB_PRE_ADD => 'optional',
- PCLZIP_CB_POST_ADD => 'optional',
- PCLZIP_OPT_NO_COMPRESSION => 'optional',
- PCLZIP_OPT_COMMENT => 'optional',
- PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
- PCLZIP_OPT_TEMP_FILE_ON => 'optional',
- PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
- //, PCLZIP_OPT_CRYPT => 'optional'
- ));
- if ($v_result != 1) {
- return 0;
- }
- }
-
- // ----- Look for 2 args
- // Here we need to support the first historic synopsis of the
- // method.
- else {
-
- // ----- Get the first argument
- $v_options[PCLZIP_OPT_ADD_PATH] = $v_arg_list[0];
-
- // ----- Look for the optional second argument
- if ($v_size == 2) {
- $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1];
- }
- else if ($v_size > 2) {
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER,
- "Invalid number / type of arguments");
- return 0;
- }
- }
- }
-
- // ----- Look for default option values
- $this->privOptionDefaultThreshold($v_options);
-
- // ----- Init
- $v_string_list = array();
- $v_att_list = array();
- $v_filedescr_list = array();
- $p_result_list = array();
-
- // ----- Look if the $p_filelist is really an array
- if (is_array($p_filelist)) {
-
- // ----- Look if the first element is also an array
- // This will mean that this is a file description entry
- if (isset($p_filelist[0]) && is_array($p_filelist[0])) {
- $v_att_list = $p_filelist;
- }
-
- // ----- The list is a list of string names
- else {
- $v_string_list = $p_filelist;
- }
- }
-
- // ----- Look if the $p_filelist is a string
- else if (is_string($p_filelist)) {
- // ----- Create a list from the string
- $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist);
- }
-
- // ----- Invalid variable type for $p_filelist
- else {
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_filelist");
- return 0;
- }
-
- // ----- Reformat the string list
- if (sizeof($v_string_list) != 0) {
- foreach ($v_string_list as $v_string) {
- if ($v_string != '') {
- $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string;
- }
- else {
- }
- }
- }
-
- // ----- For each file in the list check the attributes
- $v_supported_attributes
- = array ( PCLZIP_ATT_FILE_NAME => 'mandatory'
- ,PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional'
- ,PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional'
- ,PCLZIP_ATT_FILE_MTIME => 'optional'
- ,PCLZIP_ATT_FILE_CONTENT => 'optional'
- ,PCLZIP_ATT_FILE_COMMENT => 'optional'
- );
- foreach ($v_att_list as $v_entry) {
- $v_result = $this->privFileDescrParseAtt($v_entry,
- $v_filedescr_list[],
- $v_options,
- $v_supported_attributes);
- if ($v_result != 1) {
- return 0;
- }
- }
-
- // ----- Expand the filelist (expand directories)
- $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options);
- if ($v_result != 1) {
- return 0;
- }
-
- // ----- Call the create fct
- $v_result = $this->privCreate($v_filedescr_list, $p_result_list, $v_options);
- if ($v_result != 1) {
- return 0;
- }
-
- // ----- Return
- return $p_result_list;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function :
- // add($p_filelist, $p_add_dir="", $p_remove_dir="")
- // add($p_filelist, $p_option, $p_option_value, ...)
- // Description :
- // This method supports two synopsis. The first one is historical.
- // This methods add the list of files in an existing archive.
- // If a file with the same name already exists, it is added at the end of the
- // archive, the first one is still present.
- // If the archive does not exist, it is created.
- // Parameters :
- // $p_filelist : An array containing file or directory names, or
- // a string containing one filename or one directory name, or
- // a string containing a list of filenames and/or directory
- // names separated by spaces.
- // $p_add_dir : A path to add before the real path of the archived file,
- // in order to have it memorized in the archive.
- // $p_remove_dir : A path to remove from the real path of the file to archive,
- // in order to have a shorter path memorized in the archive.
- // When $p_add_dir and $p_remove_dir are set, $p_remove_dir
- // is removed first, before $p_add_dir is added.
- // Options :
- // PCLZIP_OPT_ADD_PATH :
- // PCLZIP_OPT_REMOVE_PATH :
- // PCLZIP_OPT_REMOVE_ALL_PATH :
- // PCLZIP_OPT_COMMENT :
- // PCLZIP_OPT_ADD_COMMENT :
- // PCLZIP_OPT_PREPEND_COMMENT :
- // PCLZIP_CB_PRE_ADD :
- // PCLZIP_CB_POST_ADD :
- // Return Values :
- // 0 on failure,
- // The list of the added files, with a status of the add action.
- // (see PclZip::listContent() for list entry format)
- // --------------------------------------------------------------------------------
- function add($p_filelist)
- {
- $v_result=1;
-
- // ----- Reset the error handler
- $this->privErrorReset();
-
- // ----- Set default values
- $v_options = array();
- $v_options[PCLZIP_OPT_NO_COMPRESSION] = FALSE;
-
- // ----- Look for variable options arguments
- $v_size = func_num_args();
-
- // ----- Look for arguments
- if ($v_size > 1) {
- // ----- Get the arguments
- $v_arg_list = func_get_args();
-
- // ----- Remove form the options list the first argument
- array_shift($v_arg_list);
- $v_size--;
-
- // ----- Look for first arg
- if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
-
- // ----- Parse the options
- $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
- array (PCLZIP_OPT_REMOVE_PATH => 'optional',
- PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
- PCLZIP_OPT_ADD_PATH => 'optional',
- PCLZIP_CB_PRE_ADD => 'optional',
- PCLZIP_CB_POST_ADD => 'optional',
- PCLZIP_OPT_NO_COMPRESSION => 'optional',
- PCLZIP_OPT_COMMENT => 'optional',
- PCLZIP_OPT_ADD_COMMENT => 'optional',
- PCLZIP_OPT_PREPEND_COMMENT => 'optional',
- PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
- PCLZIP_OPT_TEMP_FILE_ON => 'optional',
- PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
- //, PCLZIP_OPT_CRYPT => 'optional'
- ));
- if ($v_result != 1) {
- return 0;
- }
- }
-
- // ----- Look for 2 args
- // Here we need to support the first historic synopsis of the
- // method.
- else {
-
- // ----- Get the first argument
- $v_options[PCLZIP_OPT_ADD_PATH] = $v_add_path = $v_arg_list[0];
-
- // ----- Look for the optional second argument
- if ($v_size == 2) {
- $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1];
- }
- else if ($v_size > 2) {
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments");
-
- // ----- Return
- return 0;
- }
- }
- }
-
- // ----- Look for default option values
- $this->privOptionDefaultThreshold($v_options);
-
- // ----- Init
- $v_string_list = array();
- $v_att_list = array();
- $v_filedescr_list = array();
- $p_result_list = array();
-
- // ----- Look if the $p_filelist is really an array
- if (is_array($p_filelist)) {
-
- // ----- Look if the first element is also an array
- // This will mean that this is a file description entry
- if (isset($p_filelist[0]) && is_array($p_filelist[0])) {
- $v_att_list = $p_filelist;
- }
-
- // ----- The list is a list of string names
- else {
- $v_string_list = $p_filelist;
- }
- }
-
- // ----- Look if the $p_filelist is a string
- else if (is_string($p_filelist)) {
- // ----- Create a list from the string
- $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist);
- }
-
- // ----- Invalid variable type for $p_filelist
- else {
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type '".gettype($p_filelist)."' for p_filelist");
- return 0;
- }
-
- // ----- Reformat the string list
- if (sizeof($v_string_list) != 0) {
- foreach ($v_string_list as $v_string) {
- $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string;
- }
- }
-
- // ----- For each file in the list check the attributes
- $v_supported_attributes
- = array ( PCLZIP_ATT_FILE_NAME => 'mandatory'
- ,PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional'
- ,PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional'
- ,PCLZIP_ATT_FILE_MTIME => 'optional'
- ,PCLZIP_ATT_FILE_CONTENT => 'optional'
- ,PCLZIP_ATT_FILE_COMMENT => 'optional'
- );
- foreach ($v_att_list as $v_entry) {
- $v_result = $this->privFileDescrParseAtt($v_entry,
- $v_filedescr_list[],
- $v_options,
- $v_supported_attributes);
- if ($v_result != 1) {
- return 0;
- }
- }
-
- // ----- Expand the filelist (expand directories)
- $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options);
- if ($v_result != 1) {
- return 0;
- }
-
- // ----- Call the create fct
- $v_result = $this->privAdd($v_filedescr_list, $p_result_list, $v_options);
- if ($v_result != 1) {
- return 0;
- }
-
- // ----- Return
- return $p_result_list;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : listContent()
- // Description :
- // This public method, gives the list of the files and directories, with their
- // properties.
- // The properties of each entries in the list are (used also in other functions) :
- // filename : Name of the file. For a create or add action it is the filename
- // given by the user. For an extract function it is the filename
- // of the extracted file.
- // stored_filename : Name of the file / directory stored in the archive.
- // size : Size of the stored file.
- // compressed_size : Size of the file's data compressed in the archive
- // (without the headers overhead)
- // mtime : Last known modification date of the file (UNIX timestamp)
- // comment : Comment associated with the file
- // folder : true | false
- // index : index of the file in the archive
- // status : status of the action (depending of the action) :
- // Values are :
- // ok : OK !
- // filtered : the file / dir is not extracted (filtered by user)
- // already_a_directory : the file can not be extracted because a
- // directory with the same name already exists
- // write_protected : the file can not be extracted because a file
- // with the same name already exists and is
- // write protected
- // newer_exist : the file was not extracted because a newer file exists
- // path_creation_fail : the file is not extracted because the folder
- // does not exist and can not be created
- // write_error : the file was not extracted because there was a
- // error while writing the file
- // read_error : the file was not extracted because there was a error
- // while reading the file
- // invalid_header : the file was not extracted because of an archive
- // format error (bad file header)
- // Note that each time a method can continue operating when there
- // is an action error on a file, the error is only logged in the file status.
- // Return Values :
- // 0 on an unrecoverable failure,
- // The list of the files in the archive.
- // --------------------------------------------------------------------------------
- function listContent()
- {
- $v_result=1;
-
- // ----- Reset the error handler
- $this->privErrorReset();
-
- // ----- Check archive
- if (!$this->privCheckFormat()) {
- return(0);
- }
-
- // ----- Call the extracting fct
- $p_list = array();
- if (($v_result = $this->privList($p_list)) != 1)
- {
- unset($p_list);
- return(0);
- }
-
- // ----- Return
- return $p_list;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function :
- // extract($p_path="./", $p_remove_path="")
- // extract([$p_option, $p_option_value, ...])
- // Description :
- // This method supports two synopsis. The first one is historical.
- // This method extract all the files / directories from the archive to the
- // folder indicated in $p_path.
- // If you want to ignore the 'root' part of path of the memorized files
- // you can indicate this in the optional $p_remove_path parameter.
- // By default, if a newer file with the same name already exists, the
- // file is not extracted.
- //
- // If both PCLZIP_OPT_PATH and PCLZIP_OPT_ADD_PATH aoptions
- // are used, the path indicated in PCLZIP_OPT_ADD_PATH is append
- // at the end of the path value of PCLZIP_OPT_PATH.
- // Parameters :
- // $p_path : Path where the files and directories are to be extracted
- // $p_remove_path : First part ('root' part) of the memorized path
- // (if any similar) to remove while extracting.
- // Options :
- // PCLZIP_OPT_PATH :
- // PCLZIP_OPT_ADD_PATH :
- // PCLZIP_OPT_REMOVE_PATH :
- // PCLZIP_OPT_REMOVE_ALL_PATH :
- // PCLZIP_CB_PRE_EXTRACT :
- // PCLZIP_CB_POST_EXTRACT :
- // Return Values :
- // 0 or a negative value on failure,
- // The list of the extracted files, with a status of the action.
- // (see PclZip::listContent() for list entry format)
- // --------------------------------------------------------------------------------
- function extract()
- {
- $v_result=1;
-
- // ----- Reset the error handler
- $this->privErrorReset();
-
- // ----- Check archive
- if (!$this->privCheckFormat()) {
- return(0);
- }
-
- // ----- Set default values
- $v_options = array();
-// $v_path = "./";
- $v_path = '';
- $v_remove_path = "";
- $v_remove_all_path = false;
-
- // ----- Look for variable options arguments
- $v_size = func_num_args();
-
- // ----- Default values for option
- $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE;
-
- // ----- Look for arguments
- if ($v_size > 0) {
- // ----- Get the arguments
- $v_arg_list = func_get_args();
-
- // ----- Look for first arg
- if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
-
- // ----- Parse the options
- $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
- array (PCLZIP_OPT_PATH => 'optional',
- PCLZIP_OPT_REMOVE_PATH => 'optional',
- PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
- PCLZIP_OPT_ADD_PATH => 'optional',
- PCLZIP_CB_PRE_EXTRACT => 'optional',
- PCLZIP_CB_POST_EXTRACT => 'optional',
- PCLZIP_OPT_SET_CHMOD => 'optional',
- PCLZIP_OPT_BY_NAME => 'optional',
- PCLZIP_OPT_BY_EREG => 'optional',
- PCLZIP_OPT_BY_PREG => 'optional',
- PCLZIP_OPT_BY_INDEX => 'optional',
- PCLZIP_OPT_EXTRACT_AS_STRING => 'optional',
- PCLZIP_OPT_EXTRACT_IN_OUTPUT => 'optional',
- PCLZIP_OPT_REPLACE_NEWER => 'optional'
- ,PCLZIP_OPT_STOP_ON_ERROR => 'optional'
- ,PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional',
- PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
- PCLZIP_OPT_TEMP_FILE_ON => 'optional',
- PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
- ));
- if ($v_result != 1) {
- return 0;
- }
-
- // ----- Set the arguments
- if (isset($v_options[PCLZIP_OPT_PATH])) {
- $v_path = $v_options[PCLZIP_OPT_PATH];
- }
- if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) {
- $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH];
- }
- if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) {
- $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH];
- }
- if (isset($v_options[PCLZIP_OPT_ADD_PATH])) {
- // ----- Check for '/' in last path char
- if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) {
- $v_path .= '/';
- }
- $v_path .= $v_options[PCLZIP_OPT_ADD_PATH];
- }
- }
-
- // ----- Look for 2 args
- // Here we need to support the first historic synopsis of the
- // method.
- else {
-
- // ----- Get the first argument
- $v_path = $v_arg_list[0];
-
- // ----- Look for the optional second argument
- if ($v_size == 2) {
- $v_remove_path = $v_arg_list[1];
- }
- else if ($v_size > 2) {
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments");
-
- // ----- Return
- return 0;
- }
- }
- }
-
- // ----- Look for default option values
- $this->privOptionDefaultThreshold($v_options);
-
- // ----- Trace
-
- // ----- Call the extracting fct
- $p_list = array();
- $v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path,
- $v_remove_all_path, $v_options);
- if ($v_result < 1) {
- unset($p_list);
- return(0);
- }
-
- // ----- Return
- return $p_list;
- }
- // --------------------------------------------------------------------------------
-
-
- // --------------------------------------------------------------------------------
- // Function :
- // extractByIndex($p_index, $p_path="./", $p_remove_path="")
- // extractByIndex($p_index, [$p_option, $p_option_value, ...])
- // Description :
- // This method supports two synopsis. The first one is historical.
- // This method is doing a partial extract of the archive.
- // The extracted files or folders are identified by their index in the
- // archive (from 0 to n).
- // Note that if the index identify a folder, only the folder entry is
- // extracted, not all the files included in the archive.
- // Parameters :
- // $p_index : A single index (integer) or a string of indexes of files to
- // extract. The form of the string is "0,4-6,8-12" with only numbers
- // and '-' for range or ',' to separate ranges. No spaces or ';'
- // are allowed.
- // $p_path : Path where the files and directories are to be extracted
- // $p_remove_path : First part ('root' part) of the memorized path
- // (if any similar) to remove while extracting.
- // Options :
- // PCLZIP_OPT_PATH :
- // PCLZIP_OPT_ADD_PATH :
- // PCLZIP_OPT_REMOVE_PATH :
- // PCLZIP_OPT_REMOVE_ALL_PATH :
- // PCLZIP_OPT_EXTRACT_AS_STRING : The files are extracted as strings and
- // not as files.
- // The resulting content is in a new field 'content' in the file
- // structure.
- // This option must be used alone (any other options are ignored).
- // PCLZIP_CB_PRE_EXTRACT :
- // PCLZIP_CB_POST_EXTRACT :
- // Return Values :
- // 0 on failure,
- // The list of the extracted files, with a status of the action.
- // (see PclZip::listContent() for list entry format)
- // --------------------------------------------------------------------------------
- //function extractByIndex($p_index, options...)
- function extractByIndex($p_index)
- {
- $v_result=1;
-
- // ----- Reset the error handler
- $this->privErrorReset();
-
- // ----- Check archive
- if (!$this->privCheckFormat()) {
- return(0);
- }
-
- // ----- Set default values
- $v_options = array();
-// $v_path = "./";
- $v_path = '';
- $v_remove_path = "";
- $v_remove_all_path = false;
-
- // ----- Look for variable options arguments
- $v_size = func_num_args();
-
- // ----- Default values for option
- $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE;
-
- // ----- Look for arguments
- if ($v_size > 1) {
- // ----- Get the arguments
- $v_arg_list = func_get_args();
-
- // ----- Remove form the options list the first argument
- array_shift($v_arg_list);
- $v_size--;
-
- // ----- Look for first arg
- if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
-
- // ----- Parse the options
- $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
- array (PCLZIP_OPT_PATH => 'optional',
- PCLZIP_OPT_REMOVE_PATH => 'optional',
- PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
- PCLZIP_OPT_EXTRACT_AS_STRING => 'optional',
- PCLZIP_OPT_ADD_PATH => 'optional',
- PCLZIP_CB_PRE_EXTRACT => 'optional',
- PCLZIP_CB_POST_EXTRACT => 'optional',
- PCLZIP_OPT_SET_CHMOD => 'optional',
- PCLZIP_OPT_REPLACE_NEWER => 'optional'
- ,PCLZIP_OPT_STOP_ON_ERROR => 'optional'
- ,PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional',
- PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
- PCLZIP_OPT_TEMP_FILE_ON => 'optional',
- PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
- ));
- if ($v_result != 1) {
- return 0;
- }
-
- // ----- Set the arguments
- if (isset($v_options[PCLZIP_OPT_PATH])) {
- $v_path = $v_options[PCLZIP_OPT_PATH];
- }
- if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) {
- $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH];
- }
- if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) {
- $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH];
- }
- if (isset($v_options[PCLZIP_OPT_ADD_PATH])) {
- // ----- Check for '/' in last path char
- if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) {
- $v_path .= '/';
- }
- $v_path .= $v_options[PCLZIP_OPT_ADD_PATH];
- }
- if (!isset($v_options[PCLZIP_OPT_EXTRACT_AS_STRING])) {
- $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE;
- }
- else {
- }
- }
-
- // ----- Look for 2 args
- // Here we need to support the first historic synopsis of the
- // method.
- else {
-
- // ----- Get the first argument
- $v_path = $v_arg_list[0];
-
- // ----- Look for the optional second argument
- if ($v_size == 2) {
- $v_remove_path = $v_arg_list[1];
- }
- else if ($v_size > 2) {
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments");
-
- // ----- Return
- return 0;
- }
- }
- }
-
- // ----- Trace
-
- // ----- Trick
- // Here I want to reuse extractByRule(), so I need to parse the $p_index
- // with privParseOptions()
- $v_arg_trick = array (PCLZIP_OPT_BY_INDEX, $p_index);
- $v_options_trick = array();
- $v_result = $this->privParseOptions($v_arg_trick, sizeof($v_arg_trick), $v_options_trick,
- array (PCLZIP_OPT_BY_INDEX => 'optional' ));
- if ($v_result != 1) {
- return 0;
- }
- $v_options[PCLZIP_OPT_BY_INDEX] = $v_options_trick[PCLZIP_OPT_BY_INDEX];
-
- // ----- Look for default option values
- $this->privOptionDefaultThreshold($v_options);
-
- // ----- Call the extracting fct
- if (($v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, $v_remove_all_path, $v_options)) < 1) {
- return(0);
- }
-
- // ----- Return
- return $p_list;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function :
- // delete([$p_option, $p_option_value, ...])
- // Description :
- // This method removes files from the archive.
- // If no parameters are given, then all the archive is emptied.
- // Parameters :
- // None or optional arguments.
- // Options :
- // PCLZIP_OPT_BY_INDEX :
- // PCLZIP_OPT_BY_NAME :
- // PCLZIP_OPT_BY_EREG :
- // PCLZIP_OPT_BY_PREG :
- // Return Values :
- // 0 on failure,
- // The list of the files which are still present in the archive.
- // (see PclZip::listContent() for list entry format)
- // --------------------------------------------------------------------------------
- function delete()
- {
- $v_result=1;
-
- // ----- Reset the error handler
- $this->privErrorReset();
-
- // ----- Check archive
- if (!$this->privCheckFormat()) {
- return(0);
- }
-
- // ----- Set default values
- $v_options = array();
-
- // ----- Look for variable options arguments
- $v_size = func_num_args();
-
- // ----- Look for arguments
- if ($v_size > 0) {
- // ----- Get the arguments
- $v_arg_list = func_get_args();
-
- // ----- Parse the options
- $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
- array (PCLZIP_OPT_BY_NAME => 'optional',
- PCLZIP_OPT_BY_EREG => 'optional',
- PCLZIP_OPT_BY_PREG => 'optional',
- PCLZIP_OPT_BY_INDEX => 'optional' ));
- if ($v_result != 1) {
- return 0;
- }
- }
-
- // ----- Magic quotes trick
- $this->privDisableMagicQuotes();
-
- // ----- Call the delete fct
- $v_list = array();
- if (($v_result = $this->privDeleteByRule($v_list, $v_options)) != 1) {
- $this->privSwapBackMagicQuotes();
- unset($v_list);
- return(0);
- }
-
- // ----- Magic quotes trick
- $this->privSwapBackMagicQuotes();
-
- // ----- Return
- return $v_list;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : deleteByIndex()
- // Description :
- // ***** Deprecated *****
- // delete(PCLZIP_OPT_BY_INDEX, $p_index) should be prefered.
- // --------------------------------------------------------------------------------
- function deleteByIndex($p_index)
- {
-
- $p_list = $this->delete(PCLZIP_OPT_BY_INDEX, $p_index);
-
- // ----- Return
- return $p_list;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : properties()
- // Description :
- // This method gives the properties of the archive.
- // The properties are :
- // nb : Number of files in the archive
- // comment : Comment associated with the archive file
- // status : not_exist, ok
- // Parameters :
- // None
- // Return Values :
- // 0 on failure,
- // An array with the archive properties.
- // --------------------------------------------------------------------------------
- function properties()
- {
-
- // ----- Reset the error handler
- $this->privErrorReset();
-
- // ----- Magic quotes trick
- $this->privDisableMagicQuotes();
-
- // ----- Check archive
- if (!$this->privCheckFormat()) {
- $this->privSwapBackMagicQuotes();
- return(0);
- }
-
- // ----- Default properties
- $v_prop = array();
- $v_prop['comment'] = '';
- $v_prop['nb'] = 0;
- $v_prop['status'] = 'not_exist';
-
- // ----- Look if file exists
- if (@is_file($this->zipname))
- {
- // ----- Open the zip file
- if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0)
- {
- $this->privSwapBackMagicQuotes();
-
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in binary read mode');
-
- // ----- Return
- return 0;
- }
-
- // ----- Read the central directory informations
- $v_central_dir = array();
- if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1)
- {
- $this->privSwapBackMagicQuotes();
- return 0;
- }
-
- // ----- Close the zip file
- $this->privCloseFd();
-
- // ----- Set the user attributes
- $v_prop['comment'] = $v_central_dir['comment'];
- $v_prop['nb'] = $v_central_dir['entries'];
- $v_prop['status'] = 'ok';
- }
-
- // ----- Magic quotes trick
- $this->privSwapBackMagicQuotes();
-
- // ----- Return
- return $v_prop;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : duplicate()
- // Description :
- // This method creates an archive by copying the content of an other one. If
- // the archive already exist, it is replaced by the new one without any warning.
- // Parameters :
- // $p_archive : The filename of a valid archive, or
- // a valid PclZip object.
- // Return Values :
- // 1 on success.
- // 0 or a negative value on error (error code).
- // --------------------------------------------------------------------------------
- function duplicate($p_archive)
- {
- $v_result = 1;
-
- // ----- Reset the error handler
- $this->privErrorReset();
-
- // ----- Look if the $p_archive is a PclZip object
- if ((is_object($p_archive)) && (get_class($p_archive) == 'pclzip'))
- {
-
- // ----- Duplicate the archive
- $v_result = $this->privDuplicate($p_archive->zipname);
- }
-
- // ----- Look if the $p_archive is a string (so a filename)
- else if (is_string($p_archive))
- {
-
- // ----- Check that $p_archive is a valid zip file
- // TBC : Should also check the archive format
- if (!is_file($p_archive)) {
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "No file with filename '".$p_archive."'");
- $v_result = PCLZIP_ERR_MISSING_FILE;
- }
- else {
- // ----- Duplicate the archive
- $v_result = $this->privDuplicate($p_archive);
- }
- }
-
- // ----- Invalid variable
- else
- {
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add");
- $v_result = PCLZIP_ERR_INVALID_PARAMETER;
- }
-
- // ----- Return
- return $v_result;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : merge()
- // Description :
- // This method merge the $p_archive_to_add archive at the end of the current
- // one ($this).
- // If the archive ($this) does not exist, the merge becomes a duplicate.
- // If the $p_archive_to_add archive does not exist, the merge is a success.
- // Parameters :
- // $p_archive_to_add : It can be directly the filename of a valid zip archive,
- // or a PclZip object archive.
- // Return Values :
- // 1 on success,
- // 0 or negative values on error (see below).
- // --------------------------------------------------------------------------------
- function merge($p_archive_to_add)
- {
- $v_result = 1;
-
- // ----- Reset the error handler
- $this->privErrorReset();
-
- // ----- Check archive
- if (!$this->privCheckFormat()) {
- return(0);
- }
-
- // ----- Look if the $p_archive_to_add is a PclZip object
- if ((is_object($p_archive_to_add)) && (get_class($p_archive_to_add) == 'pclzip'))
- {
-
- // ----- Merge the archive
- $v_result = $this->privMerge($p_archive_to_add);
- }
-
- // ----- Look if the $p_archive_to_add is a string (so a filename)
- else if (is_string($p_archive_to_add))
- {
-
- // ----- Create a temporary archive
- $v_object_archive = new PclZip($p_archive_to_add);
-
- // ----- Merge the archive
- $v_result = $this->privMerge($v_object_archive);
- }
-
- // ----- Invalid variable
- else
- {
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add");
- $v_result = PCLZIP_ERR_INVALID_PARAMETER;
- }
-
- // ----- Return
- return $v_result;
- }
- // --------------------------------------------------------------------------------
-
-
-
- // --------------------------------------------------------------------------------
- // Function : errorCode()
- // Description :
- // Parameters :
- // --------------------------------------------------------------------------------
- function errorCode()
- {
- if (PCLZIP_ERROR_EXTERNAL == 1) {
- return(PclErrorCode());
- }
- else {
- return($this->error_code);
- }
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : errorName()
- // Description :
- // Parameters :
- // --------------------------------------------------------------------------------
- function errorName($p_with_code=false)
- {
- $v_name = array ( PCLZIP_ERR_NO_ERROR => 'PCLZIP_ERR_NO_ERROR',
- PCLZIP_ERR_WRITE_OPEN_FAIL => 'PCLZIP_ERR_WRITE_OPEN_FAIL',
- PCLZIP_ERR_READ_OPEN_FAIL => 'PCLZIP_ERR_READ_OPEN_FAIL',
- PCLZIP_ERR_INVALID_PARAMETER => 'PCLZIP_ERR_INVALID_PARAMETER',
- PCLZIP_ERR_MISSING_FILE => 'PCLZIP_ERR_MISSING_FILE',
- PCLZIP_ERR_FILENAME_TOO_LONG => 'PCLZIP_ERR_FILENAME_TOO_LONG',
- PCLZIP_ERR_INVALID_ZIP => 'PCLZIP_ERR_INVALID_ZIP',
- PCLZIP_ERR_BAD_EXTRACTED_FILE => 'PCLZIP_ERR_BAD_EXTRACTED_FILE',
- PCLZIP_ERR_DIR_CREATE_FAIL => 'PCLZIP_ERR_DIR_CREATE_FAIL',
- PCLZIP_ERR_BAD_EXTENSION => 'PCLZIP_ERR_BAD_EXTENSION',
- PCLZIP_ERR_BAD_FORMAT => 'PCLZIP_ERR_BAD_FORMAT',
- PCLZIP_ERR_DELETE_FILE_FAIL => 'PCLZIP_ERR_DELETE_FILE_FAIL',
- PCLZIP_ERR_RENAME_FILE_FAIL => 'PCLZIP_ERR_RENAME_FILE_FAIL',
- PCLZIP_ERR_BAD_CHECKSUM => 'PCLZIP_ERR_BAD_CHECKSUM',
- PCLZIP_ERR_INVALID_ARCHIVE_ZIP => 'PCLZIP_ERR_INVALID_ARCHIVE_ZIP',
- PCLZIP_ERR_MISSING_OPTION_VALUE => 'PCLZIP_ERR_MISSING_OPTION_VALUE',
- PCLZIP_ERR_INVALID_OPTION_VALUE => 'PCLZIP_ERR_INVALID_OPTION_VALUE',
- PCLZIP_ERR_UNSUPPORTED_COMPRESSION => 'PCLZIP_ERR_UNSUPPORTED_COMPRESSION',
- PCLZIP_ERR_UNSUPPORTED_ENCRYPTION => 'PCLZIP_ERR_UNSUPPORTED_ENCRYPTION'
- ,PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE => 'PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE'
- ,PCLZIP_ERR_DIRECTORY_RESTRICTION => 'PCLZIP_ERR_DIRECTORY_RESTRICTION'
- );
-
- if (isset($v_name[$this->error_code])) {
- $v_value = $v_name[$this->error_code];
- }
- else {
- $v_value = 'NoName';
- }
-
- if ($p_with_code) {
- return($v_value.' ('.$this->error_code.')');
- }
- else {
- return($v_value);
- }
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : errorInfo()
- // Description :
- // Parameters :
- // --------------------------------------------------------------------------------
- function errorInfo($p_full=false)
- {
- if (PCLZIP_ERROR_EXTERNAL == 1) {
- return(PclErrorString());
- }
- else {
- if ($p_full) {
- return($this->errorName(true)." : ".$this->error_string);
- }
- else {
- return($this->error_string." [code ".$this->error_code."]");
- }
- }
- }
- // --------------------------------------------------------------------------------
-
-
-// --------------------------------------------------------------------------------
-// ***** UNDER THIS LINE ARE DEFINED PRIVATE INTERNAL FUNCTIONS *****
-// ***** *****
-// ***** THESES FUNCTIONS MUST NOT BE USED DIRECTLY *****
-// --------------------------------------------------------------------------------
-
-
-
- // --------------------------------------------------------------------------------
- // Function : privCheckFormat()
- // Description :
- // This method check that the archive exists and is a valid zip archive.
- // Several level of check exists. (futur)
- // Parameters :
- // $p_level : Level of check. Default 0.
- // 0 : Check the first bytes (magic codes) (default value))
- // 1 : 0 + Check the central directory (futur)
- // 2 : 1 + Check each file header (futur)
- // Return Values :
- // true on success,
- // false on error, the error code is set.
- // --------------------------------------------------------------------------------
- function privCheckFormat($p_level=0)
- {
- $v_result = true;
-
- // ----- Reset the file system cache
- clearstatcache();
-
- // ----- Reset the error handler
- $this->privErrorReset();
-
- // ----- Look if the file exits
- if (!is_file($this->zipname)) {
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "Missing archive file '".$this->zipname."'");
- return(false);
- }
-
- // ----- Check that the file is readeable
- if (!is_readable($this->zipname)) {
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to read archive '".$this->zipname."'");
- return(false);
- }
-
- // ----- Check the magic code
- // TBC
-
- // ----- Check the central header
- // TBC
-
- // ----- Check each file header
- // TBC
-
- // ----- Return
- return $v_result;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : privParseOptions()
- // Description :
- // This internal methods reads the variable list of arguments ($p_options_list,
- // $p_size) and generate an array with the options and values ($v_result_list).
- // $v_requested_options contains the options that can be present and those that
- // must be present.
- // $v_requested_options is an array, with the option value as key, and 'optional',
- // or 'mandatory' as value.
- // Parameters :
- // See above.
- // Return Values :
- // 1 on success.
- // 0 on failure.
- // --------------------------------------------------------------------------------
- function privParseOptions(&$p_options_list, $p_size, &$v_result_list, $v_requested_options=false)
- {
- $v_result=1;
-
- // ----- Read the options
- $i=0;
- while ($i<$p_size) {
-
- // ----- Check if the option is supported
- if (!isset($v_requested_options[$p_options_list[$i]])) {
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid optional parameter '".$p_options_list[$i]."' for this method");
-
- // ----- Return
- return PclZip::errorCode();
- }
-
- // ----- Look for next option
- switch ($p_options_list[$i]) {
- // ----- Look for options that request a path value
- case PCLZIP_OPT_PATH :
- case PCLZIP_OPT_REMOVE_PATH :
- case PCLZIP_OPT_ADD_PATH :
- // ----- Check the number of parameters
- if (($i+1) >= $p_size) {
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
-
- // ----- Return
- return PclZip::errorCode();
- }
-
- // ----- Get the value
- $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i+1], FALSE);
- $i++;
- break;
-
- case PCLZIP_OPT_TEMP_FILE_THRESHOLD :
- // ----- Check the number of parameters
- if (($i+1) >= $p_size) {
- PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
- return PclZip::errorCode();
- }
-
- // ----- Check for incompatible options
- if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) {
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'");
- return PclZip::errorCode();
- }
-
- // ----- Check the value
- $v_value = $p_options_list[$i+1];
- if ((!is_integer($v_value)) || ($v_value<0)) {
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Integer expected for option '".PclZipUtilOptionText($p_options_list[$i])."'");
- return PclZip::errorCode();
- }
-
- // ----- Get the value (and convert it in bytes)
- $v_result_list[$p_options_list[$i]] = $v_value*1048576;
- $i++;
- break;
-
- case PCLZIP_OPT_TEMP_FILE_ON :
- // ----- Check for incompatible options
- if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) {
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'");
- return PclZip::errorCode();
- }
-
- $v_result_list[$p_options_list[$i]] = true;
- break;
-
- case PCLZIP_OPT_TEMP_FILE_OFF :
- // ----- Check for incompatible options
- if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_ON])) {
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_ON'");
- return PclZip::errorCode();
- }
- // ----- Check for incompatible options
- if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) {
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_THRESHOLD'");
- return PclZip::errorCode();
- }
-
- $v_result_list[$p_options_list[$i]] = true;
- break;
-
- case PCLZIP_OPT_EXTRACT_DIR_RESTRICTION :
- // ----- Check the number of parameters
- if (($i+1) >= $p_size) {
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
-
- // ----- Return
- return PclZip::errorCode();
- }
-
- // ----- Get the value
- if ( is_string($p_options_list[$i+1])
- && ($p_options_list[$i+1] != '')) {
- $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i+1], FALSE);
- $i++;
- }
- else {
- }
- break;
-
- // ----- Look for options that request an array of string for value
- case PCLZIP_OPT_BY_NAME :
- // ----- Check the number of parameters
- if (($i+1) >= $p_size) {
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
-
- // ----- Return
- return PclZip::errorCode();
- }
-
- // ----- Get the value
- if (is_string($p_options_list[$i+1])) {
- $v_result_list[$p_options_list[$i]][0] = $p_options_list[$i+1];
- }
- else if (is_array($p_options_list[$i+1])) {
- $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1];
- }
- else {
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
-
- // ----- Return
- return PclZip::errorCode();
- }
- $i++;
- break;
-
- // ----- Look for options that request an EREG or PREG expression
- case PCLZIP_OPT_BY_EREG :
- // ereg() is deprecated starting with PHP 5.3. Move PCLZIP_OPT_BY_EREG
- // to PCLZIP_OPT_BY_PREG
- $p_options_list[$i] = PCLZIP_OPT_BY_PREG;
- case PCLZIP_OPT_BY_PREG :
- //case PCLZIP_OPT_CRYPT :
- // ----- Check the number of parameters
- if (($i+1) >= $p_size) {
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
-
- // ----- Return
- return PclZip::errorCode();
- }
-
- // ----- Get the value
- if (is_string($p_options_list[$i+1])) {
- $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1];
- }
- else {
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
-
- // ----- Return
- return PclZip::errorCode();
- }
- $i++;
- break;
-
- // ----- Look for options that takes a string
- case PCLZIP_OPT_COMMENT :
- case PCLZIP_OPT_ADD_COMMENT :
- case PCLZIP_OPT_PREPEND_COMMENT :
- // ----- Check the number of parameters
- if (($i+1) >= $p_size) {
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE,
- "Missing parameter value for option '"
- .PclZipUtilOptionText($p_options_list[$i])
- ."'");
-
- // ----- Return
- return PclZip::errorCode();
- }
-
- // ----- Get the value
- if (is_string($p_options_list[$i+1])) {
- $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1];
- }
- else {
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE,
- "Wrong parameter value for option '"
- .PclZipUtilOptionText($p_options_list[$i])
- ."'");
-
- // ----- Return
- return PclZip::errorCode();
- }
- $i++;
- break;
-
- // ----- Look for options that request an array of index
- case PCLZIP_OPT_BY_INDEX :
- // ----- Check the number of parameters
- if (($i+1) >= $p_size) {
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
-
- // ----- Return
- return PclZip::errorCode();
- }
-
- // ----- Get the value
- $v_work_list = array();
- if (is_string($p_options_list[$i+1])) {
-
- // ----- Remove spaces
- $p_options_list[$i+1] = strtr($p_options_list[$i+1], ' ', '');
-
- // ----- Parse items
- $v_work_list = explode(",", $p_options_list[$i+1]);
- }
- else if (is_integer($p_options_list[$i+1])) {
- $v_work_list[0] = $p_options_list[$i+1].'-'.$p_options_list[$i+1];
- }
- else if (is_array($p_options_list[$i+1])) {
- $v_work_list = $p_options_list[$i+1];
- }
- else {
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Value must be integer, string or array for option '".PclZipUtilOptionText($p_options_list[$i])."'");
-
- // ----- Return
- return PclZip::errorCode();
- }
-
- // ----- Reduce the index list
- // each index item in the list must be a couple with a start and
- // an end value : [0,3], [5-5], [8-10], ...
- // ----- Check the format of each item
- $v_sort_flag=false;
- $v_sort_value=0;
- for ($j=0; $j= $p_size) {
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
-
- // ----- Return
- return PclZip::errorCode();
- }
-
- // ----- Get the value
- $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1];
- $i++;
- break;
-
- // ----- Look for options that request a call-back
- case PCLZIP_CB_PRE_EXTRACT :
- case PCLZIP_CB_POST_EXTRACT :
- case PCLZIP_CB_PRE_ADD :
- case PCLZIP_CB_POST_ADD :
- /* for futur use
- case PCLZIP_CB_PRE_DELETE :
- case PCLZIP_CB_POST_DELETE :
- case PCLZIP_CB_PRE_LIST :
- case PCLZIP_CB_POST_LIST :
- */
- // ----- Check the number of parameters
- if (($i+1) >= $p_size) {
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
-
- // ----- Return
- return PclZip::errorCode();
- }
-
- // ----- Get the value
- $v_function_name = $p_options_list[$i+1];
-
- // ----- Check that the value is a valid existing function
- if (!function_exists($v_function_name)) {
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Function '".$v_function_name."()' is not an existing function for option '".PclZipUtilOptionText($p_options_list[$i])."'");
-
- // ----- Return
- return PclZip::errorCode();
- }
-
- // ----- Set the attribute
- $v_result_list[$p_options_list[$i]] = $v_function_name;
- $i++;
- break;
-
- default :
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER,
- "Unknown parameter '"
- .$p_options_list[$i]."'");
-
- // ----- Return
- return PclZip::errorCode();
- }
-
- // ----- Next options
- $i++;
- }
-
- // ----- Look for mandatory options
- if ($v_requested_options !== false) {
- for ($key=reset($v_requested_options); $key=key($v_requested_options); $key=next($v_requested_options)) {
- // ----- Look for mandatory option
- if ($v_requested_options[$key] == 'mandatory') {
- // ----- Look if present
- if (!isset($v_result_list[$key])) {
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter ".PclZipUtilOptionText($key)."(".$key.")");
-
- // ----- Return
- return PclZip::errorCode();
- }
- }
- }
- }
-
- // ----- Look for default values
- if (!isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) {
-
- }
-
- // ----- Return
- return $v_result;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : privOptionDefaultThreshold()
- // Description :
- // Parameters :
- // Return Values :
- // --------------------------------------------------------------------------------
- function privOptionDefaultThreshold(&$p_options)
- {
- $v_result=1;
-
- if (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD])
- || isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) {
- return $v_result;
- }
-
- // ----- Get 'memory_limit' configuration value
- $v_memory_limit = ini_get('memory_limit');
- $v_memory_limit = trim($v_memory_limit);
- $last = strtolower(substr($v_memory_limit, -1));
-
- if($last == 'g')
- //$v_memory_limit = $v_memory_limit*1024*1024*1024;
- $v_memory_limit = $v_memory_limit*1073741824;
- if($last == 'm')
- //$v_memory_limit = $v_memory_limit*1024*1024;
- $v_memory_limit = $v_memory_limit*1048576;
- if($last == 'k')
- $v_memory_limit = $v_memory_limit*1024;
-
- $p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] = floor($v_memory_limit*PCLZIP_TEMPORARY_FILE_RATIO);
-
-
- // ----- Sanity check : No threshold if value lower than 1M
- if ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] < 1048576) {
- unset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]);
- }
-
- // ----- Return
- return $v_result;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : privFileDescrParseAtt()
- // Description :
- // Parameters :
- // Return Values :
- // 1 on success.
- // 0 on failure.
- // --------------------------------------------------------------------------------
- function privFileDescrParseAtt(&$p_file_list, &$p_filedescr, $v_options, $v_requested_options=false)
- {
- $v_result=1;
-
- // ----- For each file in the list check the attributes
- foreach ($p_file_list as $v_key => $v_value) {
-
- // ----- Check if the option is supported
- if (!isset($v_requested_options[$v_key])) {
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file attribute '".$v_key."' for this file");
-
- // ----- Return
- return PclZip::errorCode();
- }
-
- // ----- Look for attribute
- switch ($v_key) {
- case PCLZIP_ATT_FILE_NAME :
- if (!is_string($v_value)) {
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'");
- return PclZip::errorCode();
- }
-
- $p_filedescr['filename'] = PclZipUtilPathReduction($v_value);
-
- if ($p_filedescr['filename'] == '') {
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty filename for attribute '".PclZipUtilOptionText($v_key)."'");
- return PclZip::errorCode();
- }
-
- break;
-
- case PCLZIP_ATT_FILE_NEW_SHORT_NAME :
- if (!is_string($v_value)) {
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'");
- return PclZip::errorCode();
- }
-
- $p_filedescr['new_short_name'] = PclZipUtilPathReduction($v_value);
-
- if ($p_filedescr['new_short_name'] == '') {
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty short filename for attribute '".PclZipUtilOptionText($v_key)."'");
- return PclZip::errorCode();
- }
- break;
-
- case PCLZIP_ATT_FILE_NEW_FULL_NAME :
- if (!is_string($v_value)) {
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'");
- return PclZip::errorCode();
- }
-
- $p_filedescr['new_full_name'] = PclZipUtilPathReduction($v_value);
-
- if ($p_filedescr['new_full_name'] == '') {
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty full filename for attribute '".PclZipUtilOptionText($v_key)."'");
- return PclZip::errorCode();
- }
- break;
-
- // ----- Look for options that takes a string
- case PCLZIP_ATT_FILE_COMMENT :
- if (!is_string($v_value)) {
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'");
- return PclZip::errorCode();
- }
-
- $p_filedescr['comment'] = $v_value;
- break;
-
- case PCLZIP_ATT_FILE_MTIME :
- if (!is_integer($v_value)) {
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". Integer expected for attribute '".PclZipUtilOptionText($v_key)."'");
- return PclZip::errorCode();
- }
-
- $p_filedescr['mtime'] = $v_value;
- break;
-
- case PCLZIP_ATT_FILE_CONTENT :
- $p_filedescr['content'] = $v_value;
- break;
-
- default :
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER,
- "Unknown parameter '".$v_key."'");
-
- // ----- Return
- return PclZip::errorCode();
- }
-
- // ----- Look for mandatory options
- if ($v_requested_options !== false) {
- for ($key=reset($v_requested_options); $key=key($v_requested_options); $key=next($v_requested_options)) {
- // ----- Look for mandatory option
- if ($v_requested_options[$key] == 'mandatory') {
- // ----- Look if present
- if (!isset($p_file_list[$key])) {
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter ".PclZipUtilOptionText($key)."(".$key.")");
- return PclZip::errorCode();
- }
- }
- }
- }
-
- // end foreach
- }
-
- // ----- Return
- return $v_result;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : privFileDescrExpand()
- // Description :
- // This method look for each item of the list to see if its a file, a folder
- // or a string to be added as file. For any other type of files (link, other)
- // just ignore the item.
- // Then prepare the information that will be stored for that file.
- // When its a folder, expand the folder with all the files that are in that
- // folder (recursively).
- // Parameters :
- // Return Values :
- // 1 on success.
- // 0 on failure.
- // --------------------------------------------------------------------------------
- function privFileDescrExpand(&$p_filedescr_list, &$p_options)
- {
- $v_result=1;
-
- // ----- Create a result list
- $v_result_list = array();
-
- // ----- Look each entry
- for ($i=0; $iprivCalculateStoredFilename($v_descr, $p_options);
-
- // ----- Add the descriptor in result list
- $v_result_list[sizeof($v_result_list)] = $v_descr;
-
- // ----- Look for folder
- if ($v_descr['type'] == 'folder') {
- // ----- List of items in folder
- $v_dirlist_descr = array();
- $v_dirlist_nb = 0;
- if ($v_folder_handler = @opendir($v_descr['filename'])) {
- while (($v_item_handler = @readdir($v_folder_handler)) !== false) {
-
- // ----- Skip '.' and '..'
- if (($v_item_handler == '.') || ($v_item_handler == '..')) {
- continue;
- }
-
- // ----- Compose the full filename
- $v_dirlist_descr[$v_dirlist_nb]['filename'] = $v_descr['filename'].'/'.$v_item_handler;
-
- // ----- Look for different stored filename
- // Because the name of the folder was changed, the name of the
- // files/sub-folders also change
- if (($v_descr['stored_filename'] != $v_descr['filename'])
- && (!isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH]))) {
- if ($v_descr['stored_filename'] != '') {
- $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_descr['stored_filename'].'/'.$v_item_handler;
- }
- else {
- $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_item_handler;
- }
- }
-
- $v_dirlist_nb++;
- }
-
- @closedir($v_folder_handler);
- }
- else {
- // TBC : unable to open folder in read mode
- }
-
- // ----- Expand each element of the list
- if ($v_dirlist_nb != 0) {
- // ----- Expand
- if (($v_result = $this->privFileDescrExpand($v_dirlist_descr, $p_options)) != 1) {
- return $v_result;
- }
-
- // ----- Concat the resulting list
- $v_result_list = array_merge($v_result_list, $v_dirlist_descr);
- }
- else {
- }
-
- // ----- Free local array
- unset($v_dirlist_descr);
- }
- }
-
- // ----- Get the result list
- $p_filedescr_list = $v_result_list;
-
- // ----- Return
- return $v_result;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : privCreate()
- // Description :
- // Parameters :
- // Return Values :
- // --------------------------------------------------------------------------------
- function privCreate($p_filedescr_list, &$p_result_list, &$p_options)
- {
- $v_result=1;
- $v_list_detail = array();
-
- // ----- Magic quotes trick
- $this->privDisableMagicQuotes();
-
- // ----- Open the file in write mode
- if (($v_result = $this->privOpenFd('wb')) != 1)
- {
- // ----- Return
- return $v_result;
- }
-
- // ----- Add the list of files
- $v_result = $this->privAddList($p_filedescr_list, $p_result_list, $p_options);
-
- // ----- Close
- $this->privCloseFd();
-
- // ----- Magic quotes trick
- $this->privSwapBackMagicQuotes();
-
- // ----- Return
- return $v_result;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : privAdd()
- // Description :
- // Parameters :
- // Return Values :
- // --------------------------------------------------------------------------------
- function privAdd($p_filedescr_list, &$p_result_list, &$p_options)
- {
- $v_result=1;
- $v_list_detail = array();
-
- // ----- Look if the archive exists or is empty
- if ((!is_file($this->zipname)) || (filesize($this->zipname) == 0))
- {
-
- // ----- Do a create
- $v_result = $this->privCreate($p_filedescr_list, $p_result_list, $p_options);
-
- // ----- Return
- return $v_result;
- }
- // ----- Magic quotes trick
- $this->privDisableMagicQuotes();
-
- // ----- Open the zip file
- if (($v_result=$this->privOpenFd('rb')) != 1)
- {
- // ----- Magic quotes trick
- $this->privSwapBackMagicQuotes();
-
- // ----- Return
- return $v_result;
- }
-
- // ----- Read the central directory informations
- $v_central_dir = array();
- if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1)
- {
- $this->privCloseFd();
- $this->privSwapBackMagicQuotes();
- return $v_result;
- }
-
- // ----- Go to beginning of File
- @rewind($this->zip_fd);
-
- // ----- Creates a temporay file
- $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp';
-
- // ----- Open the temporary file in write mode
- if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0)
- {
- $this->privCloseFd();
- $this->privSwapBackMagicQuotes();
-
- PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_zip_temp_name.'\' in binary write mode');
-
- // ----- Return
- return PclZip::errorCode();
- }
-
- // ----- Copy the files from the archive to the temporary file
- // TBC : Here I should better append the file and go back to erase the central dir
- $v_size = $v_central_dir['offset'];
- while ($v_size != 0)
- {
- $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
- $v_buffer = fread($this->zip_fd, $v_read_size);
- @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
- $v_size -= $v_read_size;
- }
-
- // ----- Swap the file descriptor
- // Here is a trick : I swap the temporary fd with the zip fd, in order to use
- // the following methods on the temporary fil and not the real archive
- $v_swap = $this->zip_fd;
- $this->zip_fd = $v_zip_temp_fd;
- $v_zip_temp_fd = $v_swap;
-
- // ----- Add the files
- $v_header_list = array();
- if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1)
- {
- fclose($v_zip_temp_fd);
- $this->privCloseFd();
- @unlink($v_zip_temp_name);
- $this->privSwapBackMagicQuotes();
-
- // ----- Return
- return $v_result;
- }
-
- // ----- Store the offset of the central dir
- $v_offset = @ftell($this->zip_fd);
-
- // ----- Copy the block of file headers from the old archive
- $v_size = $v_central_dir['size'];
- while ($v_size != 0)
- {
- $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
- $v_buffer = @fread($v_zip_temp_fd, $v_read_size);
- @fwrite($this->zip_fd, $v_buffer, $v_read_size);
- $v_size -= $v_read_size;
- }
-
- // ----- Create the Central Dir files header
- for ($i=0, $v_count=0; $iprivWriteCentralFileHeader($v_header_list[$i])) != 1) {
- fclose($v_zip_temp_fd);
- $this->privCloseFd();
- @unlink($v_zip_temp_name);
- $this->privSwapBackMagicQuotes();
-
- // ----- Return
- return $v_result;
- }
- $v_count++;
- }
-
- // ----- Transform the header to a 'usable' info
- $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]);
- }
-
- // ----- Zip file comment
- $v_comment = $v_central_dir['comment'];
- if (isset($p_options[PCLZIP_OPT_COMMENT])) {
- $v_comment = $p_options[PCLZIP_OPT_COMMENT];
- }
- if (isset($p_options[PCLZIP_OPT_ADD_COMMENT])) {
- $v_comment = $v_comment.$p_options[PCLZIP_OPT_ADD_COMMENT];
- }
- if (isset($p_options[PCLZIP_OPT_PREPEND_COMMENT])) {
- $v_comment = $p_options[PCLZIP_OPT_PREPEND_COMMENT].$v_comment;
- }
-
- // ----- Calculate the size of the central header
- $v_size = @ftell($this->zip_fd)-$v_offset;
-
- // ----- Create the central dir footer
- if (($v_result = $this->privWriteCentralHeader($v_count+$v_central_dir['entries'], $v_size, $v_offset, $v_comment)) != 1)
- {
- // ----- Reset the file list
- unset($v_header_list);
- $this->privSwapBackMagicQuotes();
-
- // ----- Return
- return $v_result;
- }
-
- // ----- Swap back the file descriptor
- $v_swap = $this->zip_fd;
- $this->zip_fd = $v_zip_temp_fd;
- $v_zip_temp_fd = $v_swap;
-
- // ----- Close
- $this->privCloseFd();
-
- // ----- Close the temporary file
- @fclose($v_zip_temp_fd);
-
- // ----- Magic quotes trick
- $this->privSwapBackMagicQuotes();
-
- // ----- Delete the zip file
- // TBC : I should test the result ...
- @unlink($this->zipname);
-
- // ----- Rename the temporary file
- // TBC : I should test the result ...
- //@rename($v_zip_temp_name, $this->zipname);
- PclZipUtilRename($v_zip_temp_name, $this->zipname);
-
- // ----- Return
- return $v_result;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : privOpenFd()
- // Description :
- // Parameters :
- // --------------------------------------------------------------------------------
- function privOpenFd($p_mode)
- {
- $v_result=1;
-
- // ----- Look if already open
- if ($this->zip_fd != 0)
- {
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Zip file \''.$this->zipname.'\' already open');
-
- // ----- Return
- return PclZip::errorCode();
- }
-
- // ----- Open the zip file
- if (($this->zip_fd = @fopen($this->zipname, $p_mode)) == 0)
- {
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in '.$p_mode.' mode');
-
- // ----- Return
- return PclZip::errorCode();
- }
-
- // ----- Return
- return $v_result;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : privCloseFd()
- // Description :
- // Parameters :
- // --------------------------------------------------------------------------------
- function privCloseFd()
- {
- $v_result=1;
-
- if ($this->zip_fd != 0)
- @fclose($this->zip_fd);
- $this->zip_fd = 0;
-
- // ----- Return
- return $v_result;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : privAddList()
- // Description :
- // $p_add_dir and $p_remove_dir will give the ability to memorize a path which is
- // different from the real path of the file. This is usefull if you want to have PclTar
- // running in any directory, and memorize relative path from an other directory.
- // Parameters :
- // $p_list : An array containing the file or directory names to add in the tar
- // $p_result_list : list of added files with their properties (specially the status field)
- // $p_add_dir : Path to add in the filename path archived
- // $p_remove_dir : Path to remove in the filename path archived
- // Return Values :
- // --------------------------------------------------------------------------------
-// function privAddList($p_list, &$p_result_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, &$p_options)
- function privAddList($p_filedescr_list, &$p_result_list, &$p_options)
- {
- $v_result=1;
-
- // ----- Add the files
- $v_header_list = array();
- if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1)
- {
- // ----- Return
- return $v_result;
- }
-
- // ----- Store the offset of the central dir
- $v_offset = @ftell($this->zip_fd);
-
- // ----- Create the Central Dir files header
- for ($i=0,$v_count=0; $iprivWriteCentralFileHeader($v_header_list[$i])) != 1) {
- // ----- Return
- return $v_result;
- }
- $v_count++;
- }
-
- // ----- Transform the header to a 'usable' info
- $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]);
- }
-
- // ----- Zip file comment
- $v_comment = '';
- if (isset($p_options[PCLZIP_OPT_COMMENT])) {
- $v_comment = $p_options[PCLZIP_OPT_COMMENT];
- }
-
- // ----- Calculate the size of the central header
- $v_size = @ftell($this->zip_fd)-$v_offset;
-
- // ----- Create the central dir footer
- if (($v_result = $this->privWriteCentralHeader($v_count, $v_size, $v_offset, $v_comment)) != 1)
- {
- // ----- Reset the file list
- unset($v_header_list);
-
- // ----- Return
- return $v_result;
- }
-
- // ----- Return
- return $v_result;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : privAddFileList()
- // Description :
- // Parameters :
- // $p_filedescr_list : An array containing the file description
- // or directory names to add in the zip
- // $p_result_list : list of added files with their properties (specially the status field)
- // Return Values :
- // --------------------------------------------------------------------------------
- function privAddFileList($p_filedescr_list, &$p_result_list, &$p_options)
- {
- $v_result=1;
- $v_header = array();
-
- // ----- Recuperate the current number of elt in list
- $v_nb = sizeof($p_result_list);
-
- // ----- Loop on the files
- for ($j=0; ($jprivAddFile($p_filedescr_list[$j], $v_header,
- $p_options);
- if ($v_result != 1) {
- return $v_result;
- }
-
- // ----- Store the file infos
- $p_result_list[$v_nb++] = $v_header;
- }
- }
-
- // ----- Return
- return $v_result;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : privAddFile()
- // Description :
- // Parameters :
- // Return Values :
- // --------------------------------------------------------------------------------
- function privAddFile($p_filedescr, &$p_header, &$p_options)
- {
- $v_result=1;
-
- // ----- Working variable
- $p_filename = $p_filedescr['filename'];
-
- // TBC : Already done in the fileAtt check ... ?
- if ($p_filename == "") {
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file list parameter (invalid or empty list)");
-
- // ----- Return
- return PclZip::errorCode();
- }
-
- // ----- Look for a stored different filename
- /* TBC : Removed
- if (isset($p_filedescr['stored_filename'])) {
- $v_stored_filename = $p_filedescr['stored_filename'];
- }
- else {
- $v_stored_filename = $p_filedescr['stored_filename'];
- }
- */
-
- // ----- Set the file properties
- clearstatcache();
- $p_header['version'] = 20;
- $p_header['version_extracted'] = 10;
- $p_header['flag'] = 0;
- $p_header['compression'] = 0;
- $p_header['crc'] = 0;
- $p_header['compressed_size'] = 0;
- $p_header['filename_len'] = strlen($p_filename);
- $p_header['extra_len'] = 0;
- $p_header['disk'] = 0;
- $p_header['internal'] = 0;
- $p_header['offset'] = 0;
- $p_header['filename'] = $p_filename;
-// TBC : Removed $p_header['stored_filename'] = $v_stored_filename;
- $p_header['stored_filename'] = $p_filedescr['stored_filename'];
- $p_header['extra'] = '';
- $p_header['status'] = 'ok';
- $p_header['index'] = -1;
-
- // ----- Look for regular file
- if ($p_filedescr['type']=='file') {
- $p_header['external'] = 0x00000000;
- $p_header['size'] = filesize($p_filename);
- }
-
- // ----- Look for regular folder
- else if ($p_filedescr['type']=='folder') {
- $p_header['external'] = 0x00000010;
- $p_header['mtime'] = filemtime($p_filename);
- $p_header['size'] = filesize($p_filename);
- }
-
- // ----- Look for virtual file
- else if ($p_filedescr['type'] == 'virtual_file') {
- $p_header['external'] = 0x00000000;
- $p_header['size'] = strlen($p_filedescr['content']);
- }
-
-
- // ----- Look for filetime
- if (isset($p_filedescr['mtime'])) {
- $p_header['mtime'] = $p_filedescr['mtime'];
- }
- else if ($p_filedescr['type'] == 'virtual_file') {
- $p_header['mtime'] = time();
- }
- else {
- $p_header['mtime'] = filemtime($p_filename);
- }
-
- // ------ Look for file comment
- if (isset($p_filedescr['comment'])) {
- $p_header['comment_len'] = strlen($p_filedescr['comment']);
- $p_header['comment'] = $p_filedescr['comment'];
- }
- else {
- $p_header['comment_len'] = 0;
- $p_header['comment'] = '';
- }
-
- // ----- Look for pre-add callback
- if (isset($p_options[PCLZIP_CB_PRE_ADD])) {
-
- // ----- Generate a local information
- $v_local_header = array();
- $this->privConvertHeader2FileInfo($p_header, $v_local_header);
-
- // ----- Call the callback
- // Here I do not use call_user_func() because I need to send a reference to the
- // header.
-// eval('$v_result = '.$p_options[PCLZIP_CB_PRE_ADD].'(PCLZIP_CB_PRE_ADD, $v_local_header);');
- $v_result = $p_options[PCLZIP_CB_PRE_ADD](PCLZIP_CB_PRE_ADD, $v_local_header);
- if ($v_result == 0) {
- // ----- Change the file status
- $p_header['status'] = "skipped";
- $v_result = 1;
- }
-
- // ----- Update the informations
- // Only some fields can be modified
- if ($p_header['stored_filename'] != $v_local_header['stored_filename']) {
- $p_header['stored_filename'] = PclZipUtilPathReduction($v_local_header['stored_filename']);
- }
- }
-
- // ----- Look for empty stored filename
- if ($p_header['stored_filename'] == "") {
- $p_header['status'] = "filtered";
- }
-
- // ----- Check the path length
- if (strlen($p_header['stored_filename']) > 0xFF) {
- $p_header['status'] = 'filename_too_long';
- }
-
- // ----- Look if no error, or file not skipped
- if ($p_header['status'] == 'ok') {
-
- // ----- Look for a file
- if ($p_filedescr['type'] == 'file') {
- // ----- Look for using temporary file to zip
- if ( (!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF]))
- && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON])
- || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD])
- && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_header['size'])) ) ) {
- $v_result = $this->privAddFileUsingTempFile($p_filedescr, $p_header, $p_options);
- if ($v_result < PCLZIP_ERR_NO_ERROR) {
- return $v_result;
- }
- }
-
- // ----- Use "in memory" zip algo
- else {
-
- // ----- Open the source file
- if (($v_file = @fopen($p_filename, "rb")) == 0) {
- PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode");
- return PclZip::errorCode();
- }
-
- // ----- Read the file content
- $v_content = @fread($v_file, $p_header['size']);
-
- // ----- Close the file
- @fclose($v_file);
-
- // ----- Calculate the CRC
- $p_header['crc'] = @crc32($v_content);
-
- // ----- Look for no compression
- if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) {
- // ----- Set header parameters
- $p_header['compressed_size'] = $p_header['size'];
- $p_header['compression'] = 0;
- }
-
- // ----- Look for normal compression
- else {
- // ----- Compress the content
- $v_content = @gzdeflate($v_content);
-
- // ----- Set header parameters
- $p_header['compressed_size'] = strlen($v_content);
- $p_header['compression'] = 8;
- }
-
- // ----- Call the header generation
- if (($v_result = $this->privWriteFileHeader($p_header)) != 1) {
- @fclose($v_file);
- return $v_result;
- }
-
- // ----- Write the compressed (or not) content
- @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']);
-
- }
-
- }
-
- // ----- Look for a virtual file (a file from string)
- else if ($p_filedescr['type'] == 'virtual_file') {
-
- $v_content = $p_filedescr['content'];
-
- // ----- Calculate the CRC
- $p_header['crc'] = @crc32($v_content);
-
- // ----- Look for no compression
- if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) {
- // ----- Set header parameters
- $p_header['compressed_size'] = $p_header['size'];
- $p_header['compression'] = 0;
- }
-
- // ----- Look for normal compression
- else {
- // ----- Compress the content
- $v_content = @gzdeflate($v_content);
-
- // ----- Set header parameters
- $p_header['compressed_size'] = strlen($v_content);
- $p_header['compression'] = 8;
- }
-
- // ----- Call the header generation
- if (($v_result = $this->privWriteFileHeader($p_header)) != 1) {
- @fclose($v_file);
- return $v_result;
- }
-
- // ----- Write the compressed (or not) content
- @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']);
- }
-
- // ----- Look for a directory
- else if ($p_filedescr['type'] == 'folder') {
- // ----- Look for directory last '/'
- if (@substr($p_header['stored_filename'], -1) != '/') {
- $p_header['stored_filename'] .= '/';
- }
-
- // ----- Set the file properties
- $p_header['size'] = 0;
- //$p_header['external'] = 0x41FF0010; // Value for a folder : to be checked
- $p_header['external'] = 0x00000010; // Value for a folder : to be checked
-
- // ----- Call the header generation
- if (($v_result = $this->privWriteFileHeader($p_header)) != 1)
- {
- return $v_result;
- }
- }
- }
-
- // ----- Look for post-add callback
- if (isset($p_options[PCLZIP_CB_POST_ADD])) {
-
- // ----- Generate a local information
- $v_local_header = array();
- $this->privConvertHeader2FileInfo($p_header, $v_local_header);
-
- // ----- Call the callback
- // Here I do not use call_user_func() because I need to send a reference to the
- // header.
-// eval('$v_result = '.$p_options[PCLZIP_CB_POST_ADD].'(PCLZIP_CB_POST_ADD, $v_local_header);');
- $v_result = $p_options[PCLZIP_CB_POST_ADD](PCLZIP_CB_POST_ADD, $v_local_header);
- if ($v_result == 0) {
- // ----- Ignored
- $v_result = 1;
- }
-
- // ----- Update the informations
- // Nothing can be modified
- }
-
- // ----- Return
- return $v_result;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : privAddFileUsingTempFile()
- // Description :
- // Parameters :
- // Return Values :
- // --------------------------------------------------------------------------------
- function privAddFileUsingTempFile($p_filedescr, &$p_header, &$p_options)
- {
- $v_result=PCLZIP_ERR_NO_ERROR;
-
- // ----- Working variable
- $p_filename = $p_filedescr['filename'];
-
-
- // ----- Open the source file
- if (($v_file = @fopen($p_filename, "rb")) == 0) {
- PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode");
- return PclZip::errorCode();
- }
-
- // ----- Creates a compressed temporary file
- $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.gz';
- if (($v_file_compressed = @gzopen($v_gzip_temp_name, "wb")) == 0) {
- fclose($v_file);
- PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary write mode');
- return PclZip::errorCode();
- }
-
- // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
- $v_size = filesize($p_filename);
- while ($v_size != 0) {
- $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
- $v_buffer = @fread($v_file, $v_read_size);
- //$v_binary_data = pack('a'.$v_read_size, $v_buffer);
- @gzputs($v_file_compressed, $v_buffer, $v_read_size);
- $v_size -= $v_read_size;
- }
-
- // ----- Close the file
- @fclose($v_file);
- @gzclose($v_file_compressed);
-
- // ----- Check the minimum file size
- if (filesize($v_gzip_temp_name) < 18) {
- PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'gzip temporary file \''.$v_gzip_temp_name.'\' has invalid filesize - should be minimum 18 bytes');
- return PclZip::errorCode();
- }
-
- // ----- Extract the compressed attributes
- if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0) {
- PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode');
- return PclZip::errorCode();
- }
-
- // ----- Read the gzip file header
- $v_binary_data = @fread($v_file_compressed, 10);
- $v_data_header = unpack('a1id1/a1id2/a1cm/a1flag/Vmtime/a1xfl/a1os', $v_binary_data);
-
- // ----- Check some parameters
- $v_data_header['os'] = bin2hex($v_data_header['os']);
-
- // ----- Read the gzip file footer
- @fseek($v_file_compressed, filesize($v_gzip_temp_name)-8);
- $v_binary_data = @fread($v_file_compressed, 8);
- $v_data_footer = unpack('Vcrc/Vcompressed_size', $v_binary_data);
-
- // ----- Set the attributes
- $p_header['compression'] = ord($v_data_header['cm']);
- //$p_header['mtime'] = $v_data_header['mtime'];
- $p_header['crc'] = $v_data_footer['crc'];
- $p_header['compressed_size'] = filesize($v_gzip_temp_name)-18;
-
- // ----- Close the file
- @fclose($v_file_compressed);
-
- // ----- Call the header generation
- if (($v_result = $this->privWriteFileHeader($p_header)) != 1) {
- return $v_result;
- }
-
- // ----- Add the compressed data
- if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0)
- {
- PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode');
- return PclZip::errorCode();
- }
-
- // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
- fseek($v_file_compressed, 10);
- $v_size = $p_header['compressed_size'];
- while ($v_size != 0)
- {
- $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
- $v_buffer = @fread($v_file_compressed, $v_read_size);
- //$v_binary_data = pack('a'.$v_read_size, $v_buffer);
- @fwrite($this->zip_fd, $v_buffer, $v_read_size);
- $v_size -= $v_read_size;
- }
-
- // ----- Close the file
- @fclose($v_file_compressed);
-
- // ----- Unlink the temporary file
- @unlink($v_gzip_temp_name);
-
- // ----- Return
- return $v_result;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : privCalculateStoredFilename()
- // Description :
- // Based on file descriptor properties and global options, this method
- // calculate the filename that will be stored in the archive.
- // Parameters :
- // Return Values :
- // --------------------------------------------------------------------------------
- function privCalculateStoredFilename(&$p_filedescr, &$p_options)
- {
- $v_result=1;
-
- // ----- Working variables
- $p_filename = $p_filedescr['filename'];
- if (isset($p_options[PCLZIP_OPT_ADD_PATH])) {
- $p_add_dir = $p_options[PCLZIP_OPT_ADD_PATH];
- }
- else {
- $p_add_dir = '';
- }
- if (isset($p_options[PCLZIP_OPT_REMOVE_PATH])) {
- $p_remove_dir = $p_options[PCLZIP_OPT_REMOVE_PATH];
- }
- else {
- $p_remove_dir = '';
- }
- if (isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH])) {
- $p_remove_all_dir = $p_options[PCLZIP_OPT_REMOVE_ALL_PATH];
- }
- else {
- $p_remove_all_dir = 0;
- }
-
-
- // ----- Look for full name change
- if (isset($p_filedescr['new_full_name'])) {
- // ----- Remove drive letter if any
- $v_stored_filename = PclZipUtilTranslateWinPath($p_filedescr['new_full_name']);
- }
-
- // ----- Look for path and/or short name change
- else {
-
- // ----- Look for short name change
- // Its when we cahnge just the filename but not the path
- if (isset($p_filedescr['new_short_name'])) {
- $v_path_info = pathinfo($p_filename);
- $v_dir = '';
- if ($v_path_info['dirname'] != '') {
- $v_dir = $v_path_info['dirname'].'/';
- }
- $v_stored_filename = $v_dir.$p_filedescr['new_short_name'];
- }
- else {
- // ----- Calculate the stored filename
- $v_stored_filename = $p_filename;
- }
-
- // ----- Look for all path to remove
- if ($p_remove_all_dir) {
- $v_stored_filename = basename($p_filename);
- }
- // ----- Look for partial path remove
- else if ($p_remove_dir != "") {
- if (substr($p_remove_dir, -1) != '/')
- $p_remove_dir .= "/";
-
- if ( (substr($p_filename, 0, 2) == "./")
- || (substr($p_remove_dir, 0, 2) == "./")) {
-
- if ( (substr($p_filename, 0, 2) == "./")
- && (substr($p_remove_dir, 0, 2) != "./")) {
- $p_remove_dir = "./".$p_remove_dir;
- }
- if ( (substr($p_filename, 0, 2) != "./")
- && (substr($p_remove_dir, 0, 2) == "./")) {
- $p_remove_dir = substr($p_remove_dir, 2);
- }
- }
-
- $v_compare = PclZipUtilPathInclusion($p_remove_dir,
- $v_stored_filename);
- if ($v_compare > 0) {
- if ($v_compare == 2) {
- $v_stored_filename = "";
- }
- else {
- $v_stored_filename = substr($v_stored_filename,
- strlen($p_remove_dir));
- }
- }
- }
-
- // ----- Remove drive letter if any
- $v_stored_filename = PclZipUtilTranslateWinPath($v_stored_filename);
-
- // ----- Look for path to add
- if ($p_add_dir != "") {
- if (substr($p_add_dir, -1) == "/")
- $v_stored_filename = $p_add_dir.$v_stored_filename;
- else
- $v_stored_filename = $p_add_dir."/".$v_stored_filename;
- }
- }
-
- // ----- Filename (reduce the path of stored name)
- $v_stored_filename = PclZipUtilPathReduction($v_stored_filename);
- $p_filedescr['stored_filename'] = $v_stored_filename;
-
- // ----- Return
- return $v_result;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : privWriteFileHeader()
- // Description :
- // Parameters :
- // Return Values :
- // --------------------------------------------------------------------------------
- function privWriteFileHeader(&$p_header)
- {
- $v_result=1;
-
- // ----- Store the offset position of the file
- $p_header['offset'] = ftell($this->zip_fd);
-
- // ----- Transform UNIX mtime to DOS format mdate/mtime
- $v_date = getdate($p_header['mtime']);
- $v_mtime = ($v_date['hours']<<11) + ($v_date['minutes']<<5) + $v_date['seconds']/2;
- $v_mdate = (($v_date['year']-1980)<<9) + ($v_date['mon']<<5) + $v_date['mday'];
-
- // ----- Packed data
- $v_binary_data = pack("VvvvvvVVVvv", 0x04034b50,
- $p_header['version_extracted'], $p_header['flag'],
- $p_header['compression'], $v_mtime, $v_mdate,
- $p_header['crc'], $p_header['compressed_size'],
- $p_header['size'],
- strlen($p_header['stored_filename']),
- $p_header['extra_len']);
-
- // ----- Write the first 148 bytes of the header in the archive
- fputs($this->zip_fd, $v_binary_data, 30);
-
- // ----- Write the variable fields
- if (strlen($p_header['stored_filename']) != 0)
- {
- fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename']));
- }
- if ($p_header['extra_len'] != 0)
- {
- fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']);
- }
-
- // ----- Return
- return $v_result;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : privWriteCentralFileHeader()
- // Description :
- // Parameters :
- // Return Values :
- // --------------------------------------------------------------------------------
- function privWriteCentralFileHeader(&$p_header)
- {
- $v_result=1;
-
- // TBC
- //for(reset($p_header); $key = key($p_header); next($p_header)) {
- //}
-
- // ----- Transform UNIX mtime to DOS format mdate/mtime
- $v_date = getdate($p_header['mtime']);
- $v_mtime = ($v_date['hours']<<11) + ($v_date['minutes']<<5) + $v_date['seconds']/2;
- $v_mdate = (($v_date['year']-1980)<<9) + ($v_date['mon']<<5) + $v_date['mday'];
-
-
- // ----- Packed data
- $v_binary_data = pack("VvvvvvvVVVvvvvvVV", 0x02014b50,
- $p_header['version'], $p_header['version_extracted'],
- $p_header['flag'], $p_header['compression'],
- $v_mtime, $v_mdate, $p_header['crc'],
- $p_header['compressed_size'], $p_header['size'],
- strlen($p_header['stored_filename']),
- $p_header['extra_len'], $p_header['comment_len'],
- $p_header['disk'], $p_header['internal'],
- $p_header['external'], $p_header['offset']);
-
- // ----- Write the 42 bytes of the header in the zip file
- fputs($this->zip_fd, $v_binary_data, 46);
-
- // ----- Write the variable fields
- if (strlen($p_header['stored_filename']) != 0)
- {
- fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename']));
- }
- if ($p_header['extra_len'] != 0)
- {
- fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']);
- }
- if ($p_header['comment_len'] != 0)
- {
- fputs($this->zip_fd, $p_header['comment'], $p_header['comment_len']);
- }
-
- // ----- Return
- return $v_result;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : privWriteCentralHeader()
- // Description :
- // Parameters :
- // Return Values :
- // --------------------------------------------------------------------------------
- function privWriteCentralHeader($p_nb_entries, $p_size, $p_offset, $p_comment)
- {
- $v_result=1;
-
- // ----- Packed data
- $v_binary_data = pack("VvvvvVVv", 0x06054b50, 0, 0, $p_nb_entries,
- $p_nb_entries, $p_size,
- $p_offset, strlen($p_comment));
-
- // ----- Write the 22 bytes of the header in the zip file
- fputs($this->zip_fd, $v_binary_data, 22);
-
- // ----- Write the variable fields
- if (strlen($p_comment) != 0)
- {
- fputs($this->zip_fd, $p_comment, strlen($p_comment));
- }
-
- // ----- Return
- return $v_result;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : privList()
- // Description :
- // Parameters :
- // Return Values :
- // --------------------------------------------------------------------------------
- function privList(&$p_list)
- {
- $v_result=1;
-
- // ----- Magic quotes trick
- $this->privDisableMagicQuotes();
-
- // ----- Open the zip file
- if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0)
- {
- // ----- Magic quotes trick
- $this->privSwapBackMagicQuotes();
-
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in binary read mode');
-
- // ----- Return
- return PclZip::errorCode();
- }
-
- // ----- Read the central directory informations
- $v_central_dir = array();
- if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1)
- {
- $this->privSwapBackMagicQuotes();
- return $v_result;
- }
-
- // ----- Go to beginning of Central Dir
- @rewind($this->zip_fd);
- if (@fseek($this->zip_fd, $v_central_dir['offset']))
- {
- $this->privSwapBackMagicQuotes();
-
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
-
- // ----- Return
- return PclZip::errorCode();
- }
-
- // ----- Read each entry
- for ($i=0; $i<$v_central_dir['entries']; $i++)
- {
- // ----- Read the file header
- if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1)
- {
- $this->privSwapBackMagicQuotes();
- return $v_result;
- }
- $v_header['index'] = $i;
-
- // ----- Get the only interesting attributes
- $this->privConvertHeader2FileInfo($v_header, $p_list[$i]);
- unset($v_header);
- }
-
- // ----- Close the zip file
- $this->privCloseFd();
-
- // ----- Magic quotes trick
- $this->privSwapBackMagicQuotes();
-
- // ----- Return
- return $v_result;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : privConvertHeader2FileInfo()
- // Description :
- // This function takes the file informations from the central directory
- // entries and extract the interesting parameters that will be given back.
- // The resulting file infos are set in the array $p_info
- // $p_info['filename'] : Filename with full path. Given by user (add),
- // extracted in the filesystem (extract).
- // $p_info['stored_filename'] : Stored filename in the archive.
- // $p_info['size'] = Size of the file.
- // $p_info['compressed_size'] = Compressed size of the file.
- // $p_info['mtime'] = Last modification date of the file.
- // $p_info['comment'] = Comment associated with the file.
- // $p_info['folder'] = true/false : indicates if the entry is a folder or not.
- // $p_info['status'] = status of the action on the file.
- // $p_info['crc'] = CRC of the file content.
- // Parameters :
- // Return Values :
- // --------------------------------------------------------------------------------
- function privConvertHeader2FileInfo($p_header, &$p_info)
- {
- $v_result=1;
-
- // ----- Get the interesting attributes
- $v_temp_path = PclZipUtilPathReduction($p_header['filename']);
- $p_info['filename'] = $v_temp_path;
- $v_temp_path = PclZipUtilPathReduction($p_header['stored_filename']);
- $p_info['stored_filename'] = $v_temp_path;
- $p_info['size'] = $p_header['size'];
- $p_info['compressed_size'] = $p_header['compressed_size'];
- $p_info['mtime'] = $p_header['mtime'];
- $p_info['comment'] = $p_header['comment'];
- $p_info['folder'] = (($p_header['external']&0x00000010)==0x00000010);
- $p_info['index'] = $p_header['index'];
- $p_info['status'] = $p_header['status'];
- $p_info['crc'] = $p_header['crc'];
-
- // ----- Return
- return $v_result;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : privExtractByRule()
- // Description :
- // Extract a file or directory depending of rules (by index, by name, ...)
- // Parameters :
- // $p_file_list : An array where will be placed the properties of each
- // extracted file
- // $p_path : Path to add while writing the extracted files
- // $p_remove_path : Path to remove (from the file memorized path) while writing the
- // extracted files. If the path does not match the file path,
- // the file is extracted with its memorized path.
- // $p_remove_path does not apply to 'list' mode.
- // $p_path and $p_remove_path are commulative.
- // Return Values :
- // 1 on success,0 or less on error (see error code list)
- // --------------------------------------------------------------------------------
- function privExtractByRule(&$p_file_list, $p_path, $p_remove_path, $p_remove_all_path, &$p_options)
- {
- $v_result=1;
-
- // ----- Magic quotes trick
- $this->privDisableMagicQuotes();
-
- // ----- Check the path
- if ( ($p_path == "")
- || ( (substr($p_path, 0, 1) != "/")
- && (substr($p_path, 0, 3) != "../")
- && (substr($p_path,1,2)!=":/")))
- $p_path = "./".$p_path;
-
- // ----- Reduce the path last (and duplicated) '/'
- if (($p_path != "./") && ($p_path != "/"))
- {
- // ----- Look for the path end '/'
- while (substr($p_path, -1) == "/")
- {
- $p_path = substr($p_path, 0, strlen($p_path)-1);
- }
- }
-
- // ----- Look for path to remove format (should end by /)
- if (($p_remove_path != "") && (substr($p_remove_path, -1) != '/'))
- {
- $p_remove_path .= '/';
- }
- $p_remove_path_size = strlen($p_remove_path);
-
- // ----- Open the zip file
- if (($v_result = $this->privOpenFd('rb')) != 1)
- {
- $this->privSwapBackMagicQuotes();
- return $v_result;
- }
-
- // ----- Read the central directory informations
- $v_central_dir = array();
- if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1)
- {
- // ----- Close the zip file
- $this->privCloseFd();
- $this->privSwapBackMagicQuotes();
-
- return $v_result;
- }
-
- // ----- Start at beginning of Central Dir
- $v_pos_entry = $v_central_dir['offset'];
-
- // ----- Read each entry
- $j_start = 0;
- for ($i=0, $v_nb_extracted=0; $i<$v_central_dir['entries']; $i++)
- {
-
- // ----- Read next Central dir entry
- @rewind($this->zip_fd);
- if (@fseek($this->zip_fd, $v_pos_entry))
- {
- // ----- Close the zip file
- $this->privCloseFd();
- $this->privSwapBackMagicQuotes();
-
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
-
- // ----- Return
- return PclZip::errorCode();
- }
-
- // ----- Read the file header
- $v_header = array();
- if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1)
- {
- // ----- Close the zip file
- $this->privCloseFd();
- $this->privSwapBackMagicQuotes();
-
- return $v_result;
- }
-
- // ----- Store the index
- $v_header['index'] = $i;
-
- // ----- Store the file position
- $v_pos_entry = ftell($this->zip_fd);
-
- // ----- Look for the specific extract rules
- $v_extract = false;
-
- // ----- Look for extract by name rule
- if ( (isset($p_options[PCLZIP_OPT_BY_NAME]))
- && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) {
-
- // ----- Look if the filename is in the list
- for ($j=0; ($j strlen($p_options[PCLZIP_OPT_BY_NAME][$j]))
- && (substr($v_header['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) {
- $v_extract = true;
- }
- }
- // ----- Look for a filename
- elseif ($v_header['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) {
- $v_extract = true;
- }
- }
- }
-
- // ----- Look for extract by ereg rule
- // ereg() is deprecated with PHP 5.3
- /*
- else if ( (isset($p_options[PCLZIP_OPT_BY_EREG]))
- && ($p_options[PCLZIP_OPT_BY_EREG] != "")) {
-
- if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header['stored_filename'])) {
- $v_extract = true;
- }
- }
- */
-
- // ----- Look for extract by preg rule
- else if ( (isset($p_options[PCLZIP_OPT_BY_PREG]))
- && ($p_options[PCLZIP_OPT_BY_PREG] != "")) {
-
- if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header['stored_filename'])) {
- $v_extract = true;
- }
- }
-
- // ----- Look for extract by index rule
- else if ( (isset($p_options[PCLZIP_OPT_BY_INDEX]))
- && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) {
-
- // ----- Look if the index is in the list
- for ($j=$j_start; ($j=$p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i<=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) {
- $v_extract = true;
- }
- if ($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) {
- $j_start = $j+1;
- }
-
- if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start']>$i) {
- break;
- }
- }
- }
-
- // ----- Look for no rule, which means extract all the archive
- else {
- $v_extract = true;
- }
-
- // ----- Check compression method
- if ( ($v_extract)
- && ( ($v_header['compression'] != 8)
- && ($v_header['compression'] != 0))) {
- $v_header['status'] = 'unsupported_compression';
-
- // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
- if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR]))
- && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) {
-
- $this->privSwapBackMagicQuotes();
-
- PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_COMPRESSION,
- "Filename '".$v_header['stored_filename']."' is "
- ."compressed by an unsupported compression "
- ."method (".$v_header['compression'].") ");
-
- return PclZip::errorCode();
- }
- }
-
- // ----- Check encrypted files
- if (($v_extract) && (($v_header['flag'] & 1) == 1)) {
- $v_header['status'] = 'unsupported_encryption';
-
- // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
- if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR]))
- && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) {
-
- $this->privSwapBackMagicQuotes();
-
- PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION,
- "Unsupported encryption for "
- ." filename '".$v_header['stored_filename']
- ."'");
-
- return PclZip::errorCode();
- }
- }
-
- // ----- Look for real extraction
- if (($v_extract) && ($v_header['status'] != 'ok')) {
- $v_result = $this->privConvertHeader2FileInfo($v_header,
- $p_file_list[$v_nb_extracted++]);
- if ($v_result != 1) {
- $this->privCloseFd();
- $this->privSwapBackMagicQuotes();
- return $v_result;
- }
-
- $v_extract = false;
- }
-
- // ----- Look for real extraction
- if ($v_extract)
- {
-
- // ----- Go to the file position
- @rewind($this->zip_fd);
- if (@fseek($this->zip_fd, $v_header['offset']))
- {
- // ----- Close the zip file
- $this->privCloseFd();
-
- $this->privSwapBackMagicQuotes();
-
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
-
- // ----- Return
- return PclZip::errorCode();
- }
-
- // ----- Look for extraction as string
- if ($p_options[PCLZIP_OPT_EXTRACT_AS_STRING]) {
-
- $v_string = '';
-
- // ----- Extracting the file
- $v_result1 = $this->privExtractFileAsString($v_header, $v_string, $p_options);
- if ($v_result1 < 1) {
- $this->privCloseFd();
- $this->privSwapBackMagicQuotes();
- return $v_result1;
- }
-
- // ----- Get the only interesting attributes
- if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted])) != 1)
- {
- // ----- Close the zip file
- $this->privCloseFd();
- $this->privSwapBackMagicQuotes();
-
- return $v_result;
- }
-
- // ----- Set the file content
- $p_file_list[$v_nb_extracted]['content'] = $v_string;
-
- // ----- Next extracted file
- $v_nb_extracted++;
-
- // ----- Look for user callback abort
- if ($v_result1 == 2) {
- break;
- }
- }
- // ----- Look for extraction in standard output
- elseif ( (isset($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT]))
- && ($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])) {
- // ----- Extracting the file in standard output
- $v_result1 = $this->privExtractFileInOutput($v_header, $p_options);
- if ($v_result1 < 1) {
- $this->privCloseFd();
- $this->privSwapBackMagicQuotes();
- return $v_result1;
- }
-
- // ----- Get the only interesting attributes
- if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) {
- $this->privCloseFd();
- $this->privSwapBackMagicQuotes();
- return $v_result;
- }
-
- // ----- Look for user callback abort
- if ($v_result1 == 2) {
- break;
- }
- }
- // ----- Look for normal extraction
- else {
- // ----- Extracting the file
- $v_result1 = $this->privExtractFile($v_header,
- $p_path, $p_remove_path,
- $p_remove_all_path,
- $p_options);
- if ($v_result1 < 1) {
- $this->privCloseFd();
- $this->privSwapBackMagicQuotes();
- return $v_result1;
- }
-
- // ----- Get the only interesting attributes
- if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1)
- {
- // ----- Close the zip file
- $this->privCloseFd();
- $this->privSwapBackMagicQuotes();
-
- return $v_result;
- }
-
- // ----- Look for user callback abort
- if ($v_result1 == 2) {
- break;
- }
- }
- }
- }
-
- // ----- Close the zip file
- $this->privCloseFd();
- $this->privSwapBackMagicQuotes();
-
- // ----- Return
- return $v_result;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : privExtractFile()
- // Description :
- // Parameters :
- // Return Values :
- //
- // 1 : ... ?
- // PCLZIP_ERR_USER_ABORTED(2) : User ask for extraction stop in callback
- // --------------------------------------------------------------------------------
- function privExtractFile(&$p_entry, $p_path, $p_remove_path, $p_remove_all_path, &$p_options)
- {
- $v_result=1;
-
- // ----- Read the file header
- if (($v_result = $this->privReadFileHeader($v_header)) != 1)
- {
- // ----- Return
- return $v_result;
- }
-
-
- // ----- Check that the file header is coherent with $p_entry info
- if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) {
- // TBC
- }
-
- // ----- Look for all path to remove
- if ($p_remove_all_path == true) {
- // ----- Look for folder entry that not need to be extracted
- if (($p_entry['external']&0x00000010)==0x00000010) {
-
- $p_entry['status'] = "filtered";
-
- return $v_result;
- }
-
- // ----- Get the basename of the path
- $p_entry['filename'] = basename($p_entry['filename']);
- }
-
- // ----- Look for path to remove
- else if ($p_remove_path != "")
- {
- if (PclZipUtilPathInclusion($p_remove_path, $p_entry['filename']) == 2)
- {
-
- // ----- Change the file status
- $p_entry['status'] = "filtered";
-
- // ----- Return
- return $v_result;
- }
-
- $p_remove_path_size = strlen($p_remove_path);
- if (substr($p_entry['filename'], 0, $p_remove_path_size) == $p_remove_path)
- {
-
- // ----- Remove the path
- $p_entry['filename'] = substr($p_entry['filename'], $p_remove_path_size);
-
- }
- }
-
- // ----- Add the path
- if ($p_path != '') {
- $p_entry['filename'] = $p_path."/".$p_entry['filename'];
- }
-
- // ----- Check a base_dir_restriction
- if (isset($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION])) {
- $v_inclusion
- = PclZipUtilPathInclusion($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION],
- $p_entry['filename']);
- if ($v_inclusion == 0) {
-
- PclZip::privErrorLog(PCLZIP_ERR_DIRECTORY_RESTRICTION,
- "Filename '".$p_entry['filename']."' is "
- ."outside PCLZIP_OPT_EXTRACT_DIR_RESTRICTION");
-
- return PclZip::errorCode();
- }
- }
-
- // ----- Look for pre-extract callback
- if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) {
-
- // ----- Generate a local information
- $v_local_header = array();
- $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
-
- // ----- Call the callback
- // Here I do not use call_user_func() because I need to send a reference to the
- // header.
-// eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);');
- $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header);
- if ($v_result == 0) {
- // ----- Change the file status
- $p_entry['status'] = "skipped";
- $v_result = 1;
- }
-
- // ----- Look for abort result
- if ($v_result == 2) {
- // ----- This status is internal and will be changed in 'skipped'
- $p_entry['status'] = "aborted";
- $v_result = PCLZIP_ERR_USER_ABORTED;
- }
-
- // ----- Update the informations
- // Only some fields can be modified
- $p_entry['filename'] = $v_local_header['filename'];
- }
-
-
- // ----- Look if extraction should be done
- if ($p_entry['status'] == 'ok') {
-
- // ----- Look for specific actions while the file exist
- if (file_exists($p_entry['filename']))
- {
-
- // ----- Look if file is a directory
- if (is_dir($p_entry['filename']))
- {
-
- // ----- Change the file status
- $p_entry['status'] = "already_a_directory";
-
- // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
- // For historical reason first PclZip implementation does not stop
- // when this kind of error occurs.
- if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR]))
- && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) {
-
- PclZip::privErrorLog(PCLZIP_ERR_ALREADY_A_DIRECTORY,
- "Filename '".$p_entry['filename']."' is "
- ."already used by an existing directory");
-
- return PclZip::errorCode();
- }
- }
- // ----- Look if file is write protected
- else if (!is_writeable($p_entry['filename']))
- {
-
- // ----- Change the file status
- $p_entry['status'] = "write_protected";
-
- // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
- // For historical reason first PclZip implementation does not stop
- // when this kind of error occurs.
- if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR]))
- && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) {
-
- PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL,
- "Filename '".$p_entry['filename']."' exists "
- ."and is write protected");
-
- return PclZip::errorCode();
- }
- }
-
- // ----- Look if the extracted file is older
- else if (filemtime($p_entry['filename']) > $p_entry['mtime'])
- {
- // ----- Change the file status
- if ( (isset($p_options[PCLZIP_OPT_REPLACE_NEWER]))
- && ($p_options[PCLZIP_OPT_REPLACE_NEWER]===true)) {
- }
- else {
- $p_entry['status'] = "newer_exist";
-
- // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
- // For historical reason first PclZip implementation does not stop
- // when this kind of error occurs.
- if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR]))
- && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) {
-
- PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL,
- "Newer version of '".$p_entry['filename']."' exists "
- ."and option PCLZIP_OPT_REPLACE_NEWER is not selected");
-
- return PclZip::errorCode();
- }
- }
- }
- else {
- }
- }
-
- // ----- Check the directory availability and create it if necessary
- else {
- if ((($p_entry['external']&0x00000010)==0x00000010) || (substr($p_entry['filename'], -1) == '/'))
- $v_dir_to_check = $p_entry['filename'];
- else if (!strstr($p_entry['filename'], "/"))
- $v_dir_to_check = "";
- else
- $v_dir_to_check = dirname($p_entry['filename']);
-
- if (($v_result = $this->privDirCheck($v_dir_to_check, (($p_entry['external']&0x00000010)==0x00000010))) != 1) {
-
- // ----- Change the file status
- $p_entry['status'] = "path_creation_fail";
-
- // ----- Return
- //return $v_result;
- $v_result = 1;
- }
- }
- }
-
- // ----- Look if extraction should be done
- if ($p_entry['status'] == 'ok') {
-
- // ----- Do the extraction (if not a folder)
- if (!(($p_entry['external']&0x00000010)==0x00000010))
- {
- // ----- Look for not compressed file
- if ($p_entry['compression'] == 0) {
-
- // ----- Opening destination file
- if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0)
- {
-
- // ----- Change the file status
- $p_entry['status'] = "write_error";
-
- // ----- Return
- return $v_result;
- }
-
-
- // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
- $v_size = $p_entry['compressed_size'];
- while ($v_size != 0)
- {
- $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
- $v_buffer = @fread($this->zip_fd, $v_read_size);
- /* Try to speed up the code
- $v_binary_data = pack('a'.$v_read_size, $v_buffer);
- @fwrite($v_dest_file, $v_binary_data, $v_read_size);
- */
- @fwrite($v_dest_file, $v_buffer, $v_read_size);
- $v_size -= $v_read_size;
- }
-
- // ----- Closing the destination file
- fclose($v_dest_file);
-
- // ----- Change the file mtime
- touch($p_entry['filename'], $p_entry['mtime']);
-
-
- }
- else {
- // ----- TBC
- // Need to be finished
- if (($p_entry['flag'] & 1) == 1) {
- PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, 'File \''.$p_entry['filename'].'\' is encrypted. Encrypted files are not supported.');
- return PclZip::errorCode();
- }
-
-
- // ----- Look for using temporary file to unzip
- if ( (!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF]))
- && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON])
- || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD])
- && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_entry['size'])) ) ) {
- $v_result = $this->privExtractFileUsingTempFile($p_entry, $p_options);
- if ($v_result < PCLZIP_ERR_NO_ERROR) {
- return $v_result;
- }
- }
-
- // ----- Look for extract in memory
- else {
-
-
- // ----- Read the compressed file in a buffer (one shot)
- $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']);
-
- // ----- Decompress the file
- $v_file_content = @gzinflate($v_buffer);
- unset($v_buffer);
- if ($v_file_content === FALSE) {
-
- // ----- Change the file status
- // TBC
- $p_entry['status'] = "error";
-
- return $v_result;
- }
-
- // ----- Opening destination file
- if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) {
-
- // ----- Change the file status
- $p_entry['status'] = "write_error";
-
- return $v_result;
- }
-
- // ----- Write the uncompressed data
- @fwrite($v_dest_file, $v_file_content, $p_entry['size']);
- unset($v_file_content);
-
- // ----- Closing the destination file
- @fclose($v_dest_file);
-
- }
-
- // ----- Change the file mtime
- @touch($p_entry['filename'], $p_entry['mtime']);
- }
-
- // ----- Look for chmod option
- if (isset($p_options[PCLZIP_OPT_SET_CHMOD])) {
-
- // ----- Change the mode of the file
- @chmod($p_entry['filename'], $p_options[PCLZIP_OPT_SET_CHMOD]);
- }
-
- }
- }
-
- // ----- Change abort status
- if ($p_entry['status'] == "aborted") {
- $p_entry['status'] = "skipped";
- }
-
- // ----- Look for post-extract callback
- elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) {
-
- // ----- Generate a local information
- $v_local_header = array();
- $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
-
- // ----- Call the callback
- // Here I do not use call_user_func() because I need to send a reference to the
- // header.
-// eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);');
- $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header);
-
- // ----- Look for abort result
- if ($v_result == 2) {
- $v_result = PCLZIP_ERR_USER_ABORTED;
- }
- }
-
- // ----- Return
- return $v_result;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : privExtractFileUsingTempFile()
- // Description :
- // Parameters :
- // Return Values :
- // --------------------------------------------------------------------------------
- function privExtractFileUsingTempFile(&$p_entry, &$p_options)
- {
- $v_result=1;
-
- // ----- Creates a temporary file
- $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.gz';
- if (($v_dest_file = @fopen($v_gzip_temp_name, "wb")) == 0) {
- fclose($v_file);
- PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary write mode');
- return PclZip::errorCode();
- }
-
-
- // ----- Write gz file format header
- $v_binary_data = pack('va1a1Va1a1', 0x8b1f, Chr($p_entry['compression']), Chr(0x00), time(), Chr(0x00), Chr(3));
- @fwrite($v_dest_file, $v_binary_data, 10);
-
- // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
- $v_size = $p_entry['compressed_size'];
- while ($v_size != 0)
- {
- $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
- $v_buffer = @fread($this->zip_fd, $v_read_size);
- //$v_binary_data = pack('a'.$v_read_size, $v_buffer);
- @fwrite($v_dest_file, $v_buffer, $v_read_size);
- $v_size -= $v_read_size;
- }
-
- // ----- Write gz file format footer
- $v_binary_data = pack('VV', $p_entry['crc'], $p_entry['size']);
- @fwrite($v_dest_file, $v_binary_data, 8);
-
- // ----- Close the temporary file
- @fclose($v_dest_file);
-
- // ----- Opening destination file
- if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) {
- $p_entry['status'] = "write_error";
- return $v_result;
- }
-
- // ----- Open the temporary gz file
- if (($v_src_file = @gzopen($v_gzip_temp_name, 'rb')) == 0) {
- @fclose($v_dest_file);
- $p_entry['status'] = "read_error";
- PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode');
- return PclZip::errorCode();
- }
-
-
- // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
- $v_size = $p_entry['size'];
- while ($v_size != 0) {
- $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
- $v_buffer = @gzread($v_src_file, $v_read_size);
- //$v_binary_data = pack('a'.$v_read_size, $v_buffer);
- @fwrite($v_dest_file, $v_buffer, $v_read_size);
- $v_size -= $v_read_size;
- }
- @fclose($v_dest_file);
- @gzclose($v_src_file);
-
- // ----- Delete the temporary file
- @unlink($v_gzip_temp_name);
-
- // ----- Return
- return $v_result;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : privExtractFileInOutput()
- // Description :
- // Parameters :
- // Return Values :
- // --------------------------------------------------------------------------------
- function privExtractFileInOutput(&$p_entry, &$p_options)
- {
- $v_result=1;
-
- // ----- Read the file header
- if (($v_result = $this->privReadFileHeader($v_header)) != 1) {
- return $v_result;
- }
-
-
- // ----- Check that the file header is coherent with $p_entry info
- if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) {
- // TBC
- }
-
- // ----- Look for pre-extract callback
- if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) {
-
- // ----- Generate a local information
- $v_local_header = array();
- $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
-
- // ----- Call the callback
- // Here I do not use call_user_func() because I need to send a reference to the
- // header.
-// eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);');
- $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header);
- if ($v_result == 0) {
- // ----- Change the file status
- $p_entry['status'] = "skipped";
- $v_result = 1;
- }
-
- // ----- Look for abort result
- if ($v_result == 2) {
- // ----- This status is internal and will be changed in 'skipped'
- $p_entry['status'] = "aborted";
- $v_result = PCLZIP_ERR_USER_ABORTED;
- }
-
- // ----- Update the informations
- // Only some fields can be modified
- $p_entry['filename'] = $v_local_header['filename'];
- }
-
- // ----- Trace
-
- // ----- Look if extraction should be done
- if ($p_entry['status'] == 'ok') {
-
- // ----- Do the extraction (if not a folder)
- if (!(($p_entry['external']&0x00000010)==0x00000010)) {
- // ----- Look for not compressed file
- if ($p_entry['compressed_size'] == $p_entry['size']) {
-
- // ----- Read the file in a buffer (one shot)
- $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']);
-
- // ----- Send the file to the output
- echo $v_buffer;
- unset($v_buffer);
- }
- else {
-
- // ----- Read the compressed file in a buffer (one shot)
- $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']);
-
- // ----- Decompress the file
- $v_file_content = gzinflate($v_buffer);
- unset($v_buffer);
-
- // ----- Send the file to the output
- echo $v_file_content;
- unset($v_file_content);
- }
- }
- }
-
- // ----- Change abort status
- if ($p_entry['status'] == "aborted") {
- $p_entry['status'] = "skipped";
- }
-
- // ----- Look for post-extract callback
- elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) {
-
- // ----- Generate a local information
- $v_local_header = array();
- $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
-
- // ----- Call the callback
- // Here I do not use call_user_func() because I need to send a reference to the
- // header.
-// eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);');
- $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header);
-
- // ----- Look for abort result
- if ($v_result == 2) {
- $v_result = PCLZIP_ERR_USER_ABORTED;
- }
- }
-
- return $v_result;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : privExtractFileAsString()
- // Description :
- // Parameters :
- // Return Values :
- // --------------------------------------------------------------------------------
- function privExtractFileAsString(&$p_entry, &$p_string, &$p_options)
- {
- $v_result=1;
-
- // ----- Read the file header
- $v_header = array();
- if (($v_result = $this->privReadFileHeader($v_header)) != 1)
- {
- // ----- Return
- return $v_result;
- }
-
-
- // ----- Check that the file header is coherent with $p_entry info
- if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) {
- // TBC
- }
-
- // ----- Look for pre-extract callback
- if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) {
-
- // ----- Generate a local information
- $v_local_header = array();
- $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
-
- // ----- Call the callback
- // Here I do not use call_user_func() because I need to send a reference to the
- // header.
-// eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);');
- $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header);
- if ($v_result == 0) {
- // ----- Change the file status
- $p_entry['status'] = "skipped";
- $v_result = 1;
- }
-
- // ----- Look for abort result
- if ($v_result == 2) {
- // ----- This status is internal and will be changed in 'skipped'
- $p_entry['status'] = "aborted";
- $v_result = PCLZIP_ERR_USER_ABORTED;
- }
-
- // ----- Update the informations
- // Only some fields can be modified
- $p_entry['filename'] = $v_local_header['filename'];
- }
-
-
- // ----- Look if extraction should be done
- if ($p_entry['status'] == 'ok') {
-
- // ----- Do the extraction (if not a folder)
- if (!(($p_entry['external']&0x00000010)==0x00000010)) {
- // ----- Look for not compressed file
- // if ($p_entry['compressed_size'] == $p_entry['size'])
- if ($p_entry['compression'] == 0) {
-
- // ----- Reading the file
- $p_string = @fread($this->zip_fd, $p_entry['compressed_size']);
- }
- else {
-
- // ----- Reading the file
- $v_data = @fread($this->zip_fd, $p_entry['compressed_size']);
-
- // ----- Decompress the file
- if (($p_string = @gzinflate($v_data)) === FALSE) {
- // TBC
- }
- }
-
- // ----- Trace
- }
- else {
- // TBC : error : can not extract a folder in a string
- }
-
- }
-
- // ----- Change abort status
- if ($p_entry['status'] == "aborted") {
- $p_entry['status'] = "skipped";
- }
-
- // ----- Look for post-extract callback
- elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) {
-
- // ----- Generate a local information
- $v_local_header = array();
- $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
-
- // ----- Swap the content to header
- $v_local_header['content'] = $p_string;
- $p_string = '';
-
- // ----- Call the callback
- // Here I do not use call_user_func() because I need to send a reference to the
- // header.
-// eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);');
- $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header);
-
- // ----- Swap back the content to header
- $p_string = $v_local_header['content'];
- unset($v_local_header['content']);
-
- // ----- Look for abort result
- if ($v_result == 2) {
- $v_result = PCLZIP_ERR_USER_ABORTED;
- }
- }
-
- // ----- Return
- return $v_result;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : privReadFileHeader()
- // Description :
- // Parameters :
- // Return Values :
- // --------------------------------------------------------------------------------
- function privReadFileHeader(&$p_header)
- {
- $v_result=1;
-
- // ----- Read the 4 bytes signature
- $v_binary_data = @fread($this->zip_fd, 4);
- $v_data = unpack('Vid', $v_binary_data);
-
- // ----- Check signature
- if ($v_data['id'] != 0x04034b50)
- {
-
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure');
-
- // ----- Return
- return PclZip::errorCode();
- }
-
- // ----- Read the first 42 bytes of the header
- $v_binary_data = fread($this->zip_fd, 26);
-
- // ----- Look for invalid block size
- if (strlen($v_binary_data) != 26)
- {
- $p_header['filename'] = "";
- $p_header['status'] = "invalid_header";
-
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : ".strlen($v_binary_data));
-
- // ----- Return
- return PclZip::errorCode();
- }
-
- // ----- Extract the values
- $v_data = unpack('vversion/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len', $v_binary_data);
-
- // ----- Get filename
- $p_header['filename'] = fread($this->zip_fd, $v_data['filename_len']);
-
- // ----- Get extra_fields
- if ($v_data['extra_len'] != 0) {
- $p_header['extra'] = fread($this->zip_fd, $v_data['extra_len']);
- }
- else {
- $p_header['extra'] = '';
- }
-
- // ----- Extract properties
- $p_header['version_extracted'] = $v_data['version'];
- $p_header['compression'] = $v_data['compression'];
- $p_header['size'] = $v_data['size'];
- $p_header['compressed_size'] = $v_data['compressed_size'];
- $p_header['crc'] = $v_data['crc'];
- $p_header['flag'] = $v_data['flag'];
- $p_header['filename_len'] = $v_data['filename_len'];
-
- // ----- Recuperate date in UNIX format
- $p_header['mdate'] = $v_data['mdate'];
- $p_header['mtime'] = $v_data['mtime'];
- if ($p_header['mdate'] && $p_header['mtime'])
- {
- // ----- Extract time
- $v_hour = ($p_header['mtime'] & 0xF800) >> 11;
- $v_minute = ($p_header['mtime'] & 0x07E0) >> 5;
- $v_seconde = ($p_header['mtime'] & 0x001F)*2;
-
- // ----- Extract date
- $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980;
- $v_month = ($p_header['mdate'] & 0x01E0) >> 5;
- $v_day = $p_header['mdate'] & 0x001F;
-
- // ----- Get UNIX date format
- $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year);
-
- }
- else
- {
- $p_header['mtime'] = time();
- }
-
- // TBC
- //for(reset($v_data); $key = key($v_data); next($v_data)) {
- //}
-
- // ----- Set the stored filename
- $p_header['stored_filename'] = $p_header['filename'];
-
- // ----- Set the status field
- $p_header['status'] = "ok";
-
- // ----- Return
- return $v_result;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : privReadCentralFileHeader()
- // Description :
- // Parameters :
- // Return Values :
- // --------------------------------------------------------------------------------
- function privReadCentralFileHeader(&$p_header)
- {
- $v_result=1;
-
- // ----- Read the 4 bytes signature
- $v_binary_data = @fread($this->zip_fd, 4);
- $v_data = unpack('Vid', $v_binary_data);
-
- // ----- Check signature
- if ($v_data['id'] != 0x02014b50)
- {
-
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure');
-
- // ----- Return
- return PclZip::errorCode();
- }
-
- // ----- Read the first 42 bytes of the header
- $v_binary_data = fread($this->zip_fd, 42);
-
- // ----- Look for invalid block size
- if (strlen($v_binary_data) != 42)
- {
- $p_header['filename'] = "";
- $p_header['status'] = "invalid_header";
-
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : ".strlen($v_binary_data));
-
- // ----- Return
- return PclZip::errorCode();
- }
-
- // ----- Extract the values
- $p_header = unpack('vversion/vversion_extracted/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len/vcomment_len/vdisk/vinternal/Vexternal/Voffset', $v_binary_data);
-
- // ----- Get filename
- if ($p_header['filename_len'] != 0)
- $p_header['filename'] = fread($this->zip_fd, $p_header['filename_len']);
- else
- $p_header['filename'] = '';
-
- // ----- Get extra
- if ($p_header['extra_len'] != 0)
- $p_header['extra'] = fread($this->zip_fd, $p_header['extra_len']);
- else
- $p_header['extra'] = '';
-
- // ----- Get comment
- if ($p_header['comment_len'] != 0)
- $p_header['comment'] = fread($this->zip_fd, $p_header['comment_len']);
- else
- $p_header['comment'] = '';
-
- // ----- Extract properties
-
- // ----- Recuperate date in UNIX format
- //if ($p_header['mdate'] && $p_header['mtime'])
- // TBC : bug : this was ignoring time with 0/0/0
- if (1)
- {
- // ----- Extract time
- $v_hour = ($p_header['mtime'] & 0xF800) >> 11;
- $v_minute = ($p_header['mtime'] & 0x07E0) >> 5;
- $v_seconde = ($p_header['mtime'] & 0x001F)*2;
-
- // ----- Extract date
- $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980;
- $v_month = ($p_header['mdate'] & 0x01E0) >> 5;
- $v_day = $p_header['mdate'] & 0x001F;
-
- // ----- Get UNIX date format
- $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year);
-
- }
- else
- {
- $p_header['mtime'] = time();
- }
-
- // ----- Set the stored filename
- $p_header['stored_filename'] = $p_header['filename'];
-
- // ----- Set default status to ok
- $p_header['status'] = 'ok';
-
- // ----- Look if it is a directory
- if (substr($p_header['filename'], -1) == '/') {
- //$p_header['external'] = 0x41FF0010;
- $p_header['external'] = 0x00000010;
- }
-
-
- // ----- Return
- return $v_result;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : privCheckFileHeaders()
- // Description :
- // Parameters :
- // Return Values :
- // 1 on success,
- // 0 on error;
- // --------------------------------------------------------------------------------
- function privCheckFileHeaders(&$p_local_header, &$p_central_header)
- {
- $v_result=1;
-
- // ----- Check the static values
- // TBC
- if ($p_local_header['filename'] != $p_central_header['filename']) {
- }
- if ($p_local_header['version_extracted'] != $p_central_header['version_extracted']) {
- }
- if ($p_local_header['flag'] != $p_central_header['flag']) {
- }
- if ($p_local_header['compression'] != $p_central_header['compression']) {
- }
- if ($p_local_header['mtime'] != $p_central_header['mtime']) {
- }
- if ($p_local_header['filename_len'] != $p_central_header['filename_len']) {
- }
-
- // ----- Look for flag bit 3
- if (($p_local_header['flag'] & 8) == 8) {
- $p_local_header['size'] = $p_central_header['size'];
- $p_local_header['compressed_size'] = $p_central_header['compressed_size'];
- $p_local_header['crc'] = $p_central_header['crc'];
- }
-
- // ----- Return
- return $v_result;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : privReadEndCentralDir()
- // Description :
- // Parameters :
- // Return Values :
- // --------------------------------------------------------------------------------
- function privReadEndCentralDir(&$p_central_dir)
- {
- $v_result=1;
-
- // ----- Go to the end of the zip file
- $v_size = filesize($this->zipname);
- @fseek($this->zip_fd, $v_size);
- if (@ftell($this->zip_fd) != $v_size)
- {
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to go to the end of the archive \''.$this->zipname.'\'');
-
- // ----- Return
- return PclZip::errorCode();
- }
-
- // ----- First try : look if this is an archive with no commentaries (most of the time)
- // in this case the end of central dir is at 22 bytes of the file end
- $v_found = 0;
- if ($v_size > 26) {
- @fseek($this->zip_fd, $v_size-22);
- if (($v_pos = @ftell($this->zip_fd)) != ($v_size-22))
- {
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \''.$this->zipname.'\'');
-
- // ----- Return
- return PclZip::errorCode();
- }
-
- // ----- Read for bytes
- $v_binary_data = @fread($this->zip_fd, 4);
- $v_data = @unpack('Vid', $v_binary_data);
-
- // ----- Check signature
- if ($v_data['id'] == 0x06054b50) {
- $v_found = 1;
- }
-
- $v_pos = ftell($this->zip_fd);
- }
-
- // ----- Go back to the maximum possible size of the Central Dir End Record
- if (!$v_found) {
- $v_maximum_size = 65557; // 0xFFFF + 22;
- if ($v_maximum_size > $v_size)
- $v_maximum_size = $v_size;
- @fseek($this->zip_fd, $v_size-$v_maximum_size);
- if (@ftell($this->zip_fd) != ($v_size-$v_maximum_size))
- {
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \''.$this->zipname.'\'');
-
- // ----- Return
- return PclZip::errorCode();
- }
-
- // ----- Read byte per byte in order to find the signature
- $v_pos = ftell($this->zip_fd);
- $v_bytes = 0x00000000;
- while ($v_pos < $v_size)
- {
- // ----- Read a byte
- $v_byte = @fread($this->zip_fd, 1);
-
- // ----- Add the byte
- //$v_bytes = ($v_bytes << 8) | Ord($v_byte);
- // Note we mask the old value down such that once shifted we can never end up with more than a 32bit number
- // Otherwise on systems where we have 64bit integers the check below for the magic number will fail.
- $v_bytes = ( ($v_bytes & 0xFFFFFF) << 8) | Ord($v_byte);
-
- // ----- Compare the bytes
- if ($v_bytes == 0x504b0506)
- {
- $v_pos++;
- break;
- }
-
- $v_pos++;
- }
-
- // ----- Look if not found end of central dir
- if ($v_pos == $v_size)
- {
-
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Unable to find End of Central Dir Record signature");
-
- // ----- Return
- return PclZip::errorCode();
- }
- }
-
- // ----- Read the first 18 bytes of the header
- $v_binary_data = fread($this->zip_fd, 18);
-
- // ----- Look for invalid block size
- if (strlen($v_binary_data) != 18)
- {
-
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid End of Central Dir Record size : ".strlen($v_binary_data));
-
- // ----- Return
- return PclZip::errorCode();
- }
-
- // ----- Extract the values
- $v_data = unpack('vdisk/vdisk_start/vdisk_entries/ventries/Vsize/Voffset/vcomment_size', $v_binary_data);
-
- // ----- Check the global size
- if (($v_pos + $v_data['comment_size'] + 18) != $v_size) {
-
- // ----- Removed in release 2.2 see readme file
- // The check of the file size is a little too strict.
- // Some bugs where found when a zip is encrypted/decrypted with 'crypt'.
- // While decrypted, zip has training 0 bytes
- if (0) {
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT,
- 'The central dir is not at the end of the archive.'
- .' Some trailing bytes exists after the archive.');
-
- // ----- Return
- return PclZip::errorCode();
- }
- }
-
- // ----- Get comment
- if ($v_data['comment_size'] != 0) {
- $p_central_dir['comment'] = fread($this->zip_fd, $v_data['comment_size']);
- }
- else
- $p_central_dir['comment'] = '';
-
- $p_central_dir['entries'] = $v_data['entries'];
- $p_central_dir['disk_entries'] = $v_data['disk_entries'];
- $p_central_dir['offset'] = $v_data['offset'];
- $p_central_dir['size'] = $v_data['size'];
- $p_central_dir['disk'] = $v_data['disk'];
- $p_central_dir['disk_start'] = $v_data['disk_start'];
-
- // TBC
- //for(reset($p_central_dir); $key = key($p_central_dir); next($p_central_dir)) {
- //}
-
- // ----- Return
- return $v_result;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : privDeleteByRule()
- // Description :
- // Parameters :
- // Return Values :
- // --------------------------------------------------------------------------------
- function privDeleteByRule(&$p_result_list, &$p_options)
- {
- $v_result=1;
- $v_list_detail = array();
-
- // ----- Open the zip file
- if (($v_result=$this->privOpenFd('rb')) != 1)
- {
- // ----- Return
- return $v_result;
- }
-
- // ----- Read the central directory informations
- $v_central_dir = array();
- if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1)
- {
- $this->privCloseFd();
- return $v_result;
- }
-
- // ----- Go to beginning of File
- @rewind($this->zip_fd);
-
- // ----- Scan all the files
- // ----- Start at beginning of Central Dir
- $v_pos_entry = $v_central_dir['offset'];
- @rewind($this->zip_fd);
- if (@fseek($this->zip_fd, $v_pos_entry))
- {
- // ----- Close the zip file
- $this->privCloseFd();
-
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
-
- // ----- Return
- return PclZip::errorCode();
- }
-
- // ----- Read each entry
- $v_header_list = array();
- $j_start = 0;
- for ($i=0, $v_nb_extracted=0; $i<$v_central_dir['entries']; $i++)
- {
-
- // ----- Read the file header
- $v_header_list[$v_nb_extracted] = array();
- if (($v_result = $this->privReadCentralFileHeader($v_header_list[$v_nb_extracted])) != 1)
- {
- // ----- Close the zip file
- $this->privCloseFd();
-
- return $v_result;
- }
-
-
- // ----- Store the index
- $v_header_list[$v_nb_extracted]['index'] = $i;
-
- // ----- Look for the specific extract rules
- $v_found = false;
-
- // ----- Look for extract by name rule
- if ( (isset($p_options[PCLZIP_OPT_BY_NAME]))
- && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) {
-
- // ----- Look if the filename is in the list
- for ($j=0; ($j strlen($p_options[PCLZIP_OPT_BY_NAME][$j]))
- && (substr($v_header_list[$v_nb_extracted]['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) {
- $v_found = true;
- }
- elseif ( (($v_header_list[$v_nb_extracted]['external']&0x00000010)==0x00000010) /* Indicates a folder */
- && ($v_header_list[$v_nb_extracted]['stored_filename'].'/' == $p_options[PCLZIP_OPT_BY_NAME][$j])) {
- $v_found = true;
- }
- }
- // ----- Look for a filename
- elseif ($v_header_list[$v_nb_extracted]['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) {
- $v_found = true;
- }
- }
- }
-
- // ----- Look for extract by ereg rule
- // ereg() is deprecated with PHP 5.3
- /*
- else if ( (isset($p_options[PCLZIP_OPT_BY_EREG]))
- && ($p_options[PCLZIP_OPT_BY_EREG] != "")) {
-
- if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header_list[$v_nb_extracted]['stored_filename'])) {
- $v_found = true;
- }
- }
- */
-
- // ----- Look for extract by preg rule
- else if ( (isset($p_options[PCLZIP_OPT_BY_PREG]))
- && ($p_options[PCLZIP_OPT_BY_PREG] != "")) {
-
- if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header_list[$v_nb_extracted]['stored_filename'])) {
- $v_found = true;
- }
- }
-
- // ----- Look for extract by index rule
- else if ( (isset($p_options[PCLZIP_OPT_BY_INDEX]))
- && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) {
-
- // ----- Look if the index is in the list
- for ($j=$j_start; ($j=$p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i<=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) {
- $v_found = true;
- }
- if ($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) {
- $j_start = $j+1;
- }
-
- if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start']>$i) {
- break;
- }
- }
- }
- else {
- $v_found = true;
- }
-
- // ----- Look for deletion
- if ($v_found)
- {
- unset($v_header_list[$v_nb_extracted]);
- }
- else
- {
- $v_nb_extracted++;
- }
- }
-
- // ----- Look if something need to be deleted
- if ($v_nb_extracted > 0) {
-
- // ----- Creates a temporay file
- $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp';
-
- // ----- Creates a temporary zip archive
- $v_temp_zip = new PclZip($v_zip_temp_name);
-
- // ----- Open the temporary zip file in write mode
- if (($v_result = $v_temp_zip->privOpenFd('wb')) != 1) {
- $this->privCloseFd();
-
- // ----- Return
- return $v_result;
- }
-
- // ----- Look which file need to be kept
- for ($i=0; $izip_fd);
- if (@fseek($this->zip_fd, $v_header_list[$i]['offset'])) {
- // ----- Close the zip file
- $this->privCloseFd();
- $v_temp_zip->privCloseFd();
- @unlink($v_zip_temp_name);
-
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
-
- // ----- Return
- return PclZip::errorCode();
- }
-
- // ----- Read the file header
- $v_local_header = array();
- if (($v_result = $this->privReadFileHeader($v_local_header)) != 1) {
- // ----- Close the zip file
- $this->privCloseFd();
- $v_temp_zip->privCloseFd();
- @unlink($v_zip_temp_name);
-
- // ----- Return
- return $v_result;
- }
-
- // ----- Check that local file header is same as central file header
- if ($this->privCheckFileHeaders($v_local_header,
- $v_header_list[$i]) != 1) {
- // TBC
- }
- unset($v_local_header);
-
- // ----- Write the file header
- if (($v_result = $v_temp_zip->privWriteFileHeader($v_header_list[$i])) != 1) {
- // ----- Close the zip file
- $this->privCloseFd();
- $v_temp_zip->privCloseFd();
- @unlink($v_zip_temp_name);
-
- // ----- Return
- return $v_result;
- }
-
- // ----- Read/write the data block
- if (($v_result = PclZipUtilCopyBlock($this->zip_fd, $v_temp_zip->zip_fd, $v_header_list[$i]['compressed_size'])) != 1) {
- // ----- Close the zip file
- $this->privCloseFd();
- $v_temp_zip->privCloseFd();
- @unlink($v_zip_temp_name);
-
- // ----- Return
- return $v_result;
- }
- }
-
- // ----- Store the offset of the central dir
- $v_offset = @ftell($v_temp_zip->zip_fd);
-
- // ----- Re-Create the Central Dir files header
- for ($i=0; $iprivWriteCentralFileHeader($v_header_list[$i])) != 1) {
- $v_temp_zip->privCloseFd();
- $this->privCloseFd();
- @unlink($v_zip_temp_name);
-
- // ----- Return
- return $v_result;
- }
-
- // ----- Transform the header to a 'usable' info
- $v_temp_zip->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]);
- }
-
-
- // ----- Zip file comment
- $v_comment = '';
- if (isset($p_options[PCLZIP_OPT_COMMENT])) {
- $v_comment = $p_options[PCLZIP_OPT_COMMENT];
- }
-
- // ----- Calculate the size of the central header
- $v_size = @ftell($v_temp_zip->zip_fd)-$v_offset;
-
- // ----- Create the central dir footer
- if (($v_result = $v_temp_zip->privWriteCentralHeader(sizeof($v_header_list), $v_size, $v_offset, $v_comment)) != 1) {
- // ----- Reset the file list
- unset($v_header_list);
- $v_temp_zip->privCloseFd();
- $this->privCloseFd();
- @unlink($v_zip_temp_name);
-
- // ----- Return
- return $v_result;
- }
-
- // ----- Close
- $v_temp_zip->privCloseFd();
- $this->privCloseFd();
-
- // ----- Delete the zip file
- // TBC : I should test the result ...
- @unlink($this->zipname);
-
- // ----- Rename the temporary file
- // TBC : I should test the result ...
- //@rename($v_zip_temp_name, $this->zipname);
- PclZipUtilRename($v_zip_temp_name, $this->zipname);
-
- // ----- Destroy the temporary archive
- unset($v_temp_zip);
- }
-
- // ----- Remove every files : reset the file
- else if ($v_central_dir['entries'] != 0) {
- $this->privCloseFd();
-
- if (($v_result = $this->privOpenFd('wb')) != 1) {
- return $v_result;
- }
-
- if (($v_result = $this->privWriteCentralHeader(0, 0, 0, '')) != 1) {
- return $v_result;
- }
-
- $this->privCloseFd();
- }
-
- // ----- Return
- return $v_result;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : privDirCheck()
- // Description :
- // Check if a directory exists, if not it creates it and all the parents directory
- // which may be useful.
- // Parameters :
- // $p_dir : Directory path to check.
- // Return Values :
- // 1 : OK
- // -1 : Unable to create directory
- // --------------------------------------------------------------------------------
- function privDirCheck($p_dir, $p_is_dir=false)
- {
- $v_result = 1;
-
-
- // ----- Remove the final '/'
- if (($p_is_dir) && (substr($p_dir, -1)=='/'))
- {
- $p_dir = substr($p_dir, 0, strlen($p_dir)-1);
- }
-
- // ----- Check the directory availability
- if ((is_dir($p_dir)) || ($p_dir == ""))
- {
- return 1;
- }
-
- // ----- Extract parent directory
- $p_parent_dir = dirname($p_dir);
-
- // ----- Just a check
- if ($p_parent_dir != $p_dir)
- {
- // ----- Look for parent directory
- if ($p_parent_dir != "")
- {
- if (($v_result = $this->privDirCheck($p_parent_dir)) != 1)
- {
- return $v_result;
- }
- }
- }
-
- // ----- Create the directory
- if (!@mkdir($p_dir, 0777))
- {
- // ----- Error log
- PclZip::privErrorLog(PCLZIP_ERR_DIR_CREATE_FAIL, "Unable to create directory '$p_dir'");
-
- // ----- Return
- return PclZip::errorCode();
- }
-
- // ----- Return
- return $v_result;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : privMerge()
- // Description :
- // If $p_archive_to_add does not exist, the function exit with a success result.
- // Parameters :
- // Return Values :
- // --------------------------------------------------------------------------------
- function privMerge(&$p_archive_to_add)
- {
- $v_result=1;
-
- // ----- Look if the archive_to_add exists
- if (!is_file($p_archive_to_add->zipname))
- {
-
- // ----- Nothing to merge, so merge is a success
- $v_result = 1;
-
- // ----- Return
- return $v_result;
- }
-
- // ----- Look if the archive exists
- if (!is_file($this->zipname))
- {
-
- // ----- Do a duplicate
- $v_result = $this->privDuplicate($p_archive_to_add->zipname);
-
- // ----- Return
- return $v_result;
- }
-
- // ----- Open the zip file
- if (($v_result=$this->privOpenFd('rb')) != 1)
- {
- // ----- Return
- return $v_result;
- }
-
- // ----- Read the central directory informations
- $v_central_dir = array();
- if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1)
- {
- $this->privCloseFd();
- return $v_result;
- }
-
- // ----- Go to beginning of File
- @rewind($this->zip_fd);
-
- // ----- Open the archive_to_add file
- if (($v_result=$p_archive_to_add->privOpenFd('rb')) != 1)
- {
- $this->privCloseFd();
-
- // ----- Return
- return $v_result;
- }
-
- // ----- Read the central directory informations
- $v_central_dir_to_add = array();
- if (($v_result = $p_archive_to_add->privReadEndCentralDir($v_central_dir_to_add)) != 1)
- {
- $this->privCloseFd();
- $p_archive_to_add->privCloseFd();
-
- return $v_result;
- }
-
- // ----- Go to beginning of File
- @rewind($p_archive_to_add->zip_fd);
-
- // ----- Creates a temporay file
- $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp';
-
- // ----- Open the temporary file in write mode
- if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0)
- {
- $this->privCloseFd();
- $p_archive_to_add->privCloseFd();
-
- PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_zip_temp_name.'\' in binary write mode');
-
- // ----- Return
- return PclZip::errorCode();
- }
-
- // ----- Copy the files from the archive to the temporary file
- // TBC : Here I should better append the file and go back to erase the central dir
- $v_size = $v_central_dir['offset'];
- while ($v_size != 0)
- {
- $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
- $v_buffer = fread($this->zip_fd, $v_read_size);
- @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
- $v_size -= $v_read_size;
- }
-
- // ----- Copy the files from the archive_to_add into the temporary file
- $v_size = $v_central_dir_to_add['offset'];
- while ($v_size != 0)
- {
- $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
- $v_buffer = fread($p_archive_to_add->zip_fd, $v_read_size);
- @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
- $v_size -= $v_read_size;
- }
-
- // ----- Store the offset of the central dir
- $v_offset = @ftell($v_zip_temp_fd);
-
- // ----- Copy the block of file headers from the old archive
- $v_size = $v_central_dir['size'];
- while ($v_size != 0)
- {
- $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
- $v_buffer = @fread($this->zip_fd, $v_read_size);
- @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
- $v_size -= $v_read_size;
- }
-
- // ----- Copy the block of file headers from the archive_to_add
- $v_size = $v_central_dir_to_add['size'];
- while ($v_size != 0)
- {
- $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
- $v_buffer = @fread($p_archive_to_add->zip_fd, $v_read_size);
- @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
- $v_size -= $v_read_size;
- }
-
- // ----- Merge the file comments
- $v_comment = $v_central_dir['comment'].' '.$v_central_dir_to_add['comment'];
-
- // ----- Calculate the size of the (new) central header
- $v_size = @ftell($v_zip_temp_fd)-$v_offset;
-
- // ----- Swap the file descriptor
- // Here is a trick : I swap the temporary fd with the zip fd, in order to use
- // the following methods on the temporary fil and not the real archive fd
- $v_swap = $this->zip_fd;
- $this->zip_fd = $v_zip_temp_fd;
- $v_zip_temp_fd = $v_swap;
-
- // ----- Create the central dir footer
- if (($v_result = $this->privWriteCentralHeader($v_central_dir['entries']+$v_central_dir_to_add['entries'], $v_size, $v_offset, $v_comment)) != 1)
- {
- $this->privCloseFd();
- $p_archive_to_add->privCloseFd();
- @fclose($v_zip_temp_fd);
- $this->zip_fd = null;
-
- // ----- Reset the file list
- unset($v_header_list);
-
- // ----- Return
- return $v_result;
- }
-
- // ----- Swap back the file descriptor
- $v_swap = $this->zip_fd;
- $this->zip_fd = $v_zip_temp_fd;
- $v_zip_temp_fd = $v_swap;
-
- // ----- Close
- $this->privCloseFd();
- $p_archive_to_add->privCloseFd();
-
- // ----- Close the temporary file
- @fclose($v_zip_temp_fd);
-
- // ----- Delete the zip file
- // TBC : I should test the result ...
- @unlink($this->zipname);
-
- // ----- Rename the temporary file
- // TBC : I should test the result ...
- //@rename($v_zip_temp_name, $this->zipname);
- PclZipUtilRename($v_zip_temp_name, $this->zipname);
-
- // ----- Return
- return $v_result;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : privDuplicate()
- // Description :
- // Parameters :
- // Return Values :
- // --------------------------------------------------------------------------------
- function privDuplicate($p_archive_filename)
- {
- $v_result=1;
-
- // ----- Look if the $p_archive_filename exists
- if (!is_file($p_archive_filename))
- {
-
- // ----- Nothing to duplicate, so duplicate is a success.
- $v_result = 1;
-
- // ----- Return
- return $v_result;
- }
-
- // ----- Open the zip file
- if (($v_result=$this->privOpenFd('wb')) != 1)
- {
- // ----- Return
- return $v_result;
- }
-
- // ----- Open the temporary file in write mode
- if (($v_zip_temp_fd = @fopen($p_archive_filename, 'rb')) == 0)
- {
- $this->privCloseFd();
-
- PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive file \''.$p_archive_filename.'\' in binary write mode');
-
- // ----- Return
- return PclZip::errorCode();
- }
-
- // ----- Copy the files from the archive to the temporary file
- // TBC : Here I should better append the file and go back to erase the central dir
- $v_size = filesize($p_archive_filename);
- while ($v_size != 0)
- {
- $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
- $v_buffer = fread($v_zip_temp_fd, $v_read_size);
- @fwrite($this->zip_fd, $v_buffer, $v_read_size);
- $v_size -= $v_read_size;
- }
-
- // ----- Close
- $this->privCloseFd();
-
- // ----- Close the temporary file
- @fclose($v_zip_temp_fd);
-
- // ----- Return
- return $v_result;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : privErrorLog()
- // Description :
- // Parameters :
- // --------------------------------------------------------------------------------
- function privErrorLog($p_error_code=0, $p_error_string='')
- {
- if (PCLZIP_ERROR_EXTERNAL == 1) {
- PclError($p_error_code, $p_error_string);
- }
- else {
- $this->error_code = $p_error_code;
- $this->error_string = $p_error_string;
- }
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : privErrorReset()
- // Description :
- // Parameters :
- // --------------------------------------------------------------------------------
- function privErrorReset()
- {
- if (PCLZIP_ERROR_EXTERNAL == 1) {
- PclErrorReset();
- }
- else {
- $this->error_code = 0;
- $this->error_string = '';
- }
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : privDisableMagicQuotes()
- // Description :
- // Parameters :
- // Return Values :
- // --------------------------------------------------------------------------------
- function privDisableMagicQuotes()
- {
- $v_result=1;
-
- // ----- Look if function exists
- if ( (!function_exists("get_magic_quotes_runtime"))
- || (!function_exists("set_magic_quotes_runtime"))) {
- return $v_result;
- }
-
- // ----- Look if already done
- if ($this->magic_quotes_status != -1) {
- return $v_result;
- }
-
- // ----- Get and memorize the magic_quote value
- $this->magic_quotes_status = @get_magic_quotes_runtime();
-
- // ----- Disable magic_quotes
- if ($this->magic_quotes_status == 1) {
- @set_magic_quotes_runtime(0);
- }
-
- // ----- Return
- return $v_result;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : privSwapBackMagicQuotes()
- // Description :
- // Parameters :
- // Return Values :
- // --------------------------------------------------------------------------------
- function privSwapBackMagicQuotes()
- {
- $v_result=1;
-
- // ----- Look if function exists
- if ( (!function_exists("get_magic_quotes_runtime"))
- || (!function_exists("set_magic_quotes_runtime"))) {
- return $v_result;
- }
-
- // ----- Look if something to do
- if ($this->magic_quotes_status != -1) {
- return $v_result;
- }
-
- // ----- Swap back magic_quotes
- if ($this->magic_quotes_status == 1) {
- @set_magic_quotes_runtime($this->magic_quotes_status);
- }
-
- // ----- Return
- return $v_result;
- }
- // --------------------------------------------------------------------------------
-
- }
- // End of class
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : PclZipUtilPathReduction()
- // Description :
- // Parameters :
- // Return Values :
- // --------------------------------------------------------------------------------
- function PclZipUtilPathReduction($p_dir)
- {
- $v_result = "";
-
- // ----- Look for not empty path
- if ($p_dir != "") {
- // ----- Explode path by directory names
- $v_list = explode("/", $p_dir);
-
- // ----- Study directories from last to first
- $v_skip = 0;
- for ($i=sizeof($v_list)-1; $i>=0; $i--) {
- // ----- Look for current path
- if ($v_list[$i] == ".") {
- // ----- Ignore this directory
- // Should be the first $i=0, but no check is done
- }
- else if ($v_list[$i] == "..") {
- $v_skip++;
- }
- else if ($v_list[$i] == "") {
- // ----- First '/' i.e. root slash
- if ($i == 0) {
- $v_result = "/".$v_result;
- if ($v_skip > 0) {
- // ----- It is an invalid path, so the path is not modified
- // TBC
- $v_result = $p_dir;
- $v_skip = 0;
- }
- }
- // ----- Last '/' i.e. indicates a directory
- else if ($i == (sizeof($v_list)-1)) {
- $v_result = $v_list[$i];
- }
- // ----- Double '/' inside the path
- else {
- // ----- Ignore only the double '//' in path,
- // but not the first and last '/'
- }
- }
- else {
- // ----- Look for item to skip
- if ($v_skip > 0) {
- $v_skip--;
- }
- else {
- $v_result = $v_list[$i].($i!=(sizeof($v_list)-1)?"/".$v_result:"");
- }
- }
- }
-
- // ----- Look for skip
- if ($v_skip > 0) {
- while ($v_skip > 0) {
- $v_result = '../'.$v_result;
- $v_skip--;
- }
- }
- }
-
- // ----- Return
- return $v_result;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : PclZipUtilPathInclusion()
- // Description :
- // This function indicates if the path $p_path is under the $p_dir tree. Or,
- // said in an other way, if the file or sub-dir $p_path is inside the dir
- // $p_dir.
- // The function indicates also if the path is exactly the same as the dir.
- // This function supports path with duplicated '/' like '//', but does not
- // support '.' or '..' statements.
- // Parameters :
- // Return Values :
- // 0 if $p_path is not inside directory $p_dir
- // 1 if $p_path is inside directory $p_dir
- // 2 if $p_path is exactly the same as $p_dir
- // --------------------------------------------------------------------------------
- function PclZipUtilPathInclusion($p_dir, $p_path)
- {
- $v_result = 1;
-
- // ----- Look for path beginning by ./
- if ( ($p_dir == '.')
- || ((strlen($p_dir) >=2) && (substr($p_dir, 0, 2) == './'))) {
- $p_dir = PclZipUtilTranslateWinPath(getcwd(), FALSE).'/'.substr($p_dir, 1);
- }
- if ( ($p_path == '.')
- || ((strlen($p_path) >=2) && (substr($p_path, 0, 2) == './'))) {
- $p_path = PclZipUtilTranslateWinPath(getcwd(), FALSE).'/'.substr($p_path, 1);
- }
-
- // ----- Explode dir and path by directory separator
- $v_list_dir = explode("/", $p_dir);
- $v_list_dir_size = sizeof($v_list_dir);
- $v_list_path = explode("/", $p_path);
- $v_list_path_size = sizeof($v_list_path);
-
- // ----- Study directories paths
- $i = 0;
- $j = 0;
- while (($i < $v_list_dir_size) && ($j < $v_list_path_size) && ($v_result)) {
-
- // ----- Look for empty dir (path reduction)
- if ($v_list_dir[$i] == '') {
- $i++;
- continue;
- }
- if ($v_list_path[$j] == '') {
- $j++;
- continue;
- }
-
- // ----- Compare the items
- if (($v_list_dir[$i] != $v_list_path[$j]) && ($v_list_dir[$i] != '') && ( $v_list_path[$j] != '')) {
- $v_result = 0;
- }
-
- // ----- Next items
- $i++;
- $j++;
- }
-
- // ----- Look if everything seems to be the same
- if ($v_result) {
- // ----- Skip all the empty items
- while (($j < $v_list_path_size) && ($v_list_path[$j] == '')) $j++;
- while (($i < $v_list_dir_size) && ($v_list_dir[$i] == '')) $i++;
-
- if (($i >= $v_list_dir_size) && ($j >= $v_list_path_size)) {
- // ----- There are exactly the same
- $v_result = 2;
- }
- else if ($i < $v_list_dir_size) {
- // ----- The path is shorter than the dir
- $v_result = 0;
- }
- }
-
- // ----- Return
- return $v_result;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : PclZipUtilCopyBlock()
- // Description :
- // Parameters :
- // $p_mode : read/write compression mode
- // 0 : src & dest normal
- // 1 : src gzip, dest normal
- // 2 : src normal, dest gzip
- // 3 : src & dest gzip
- // Return Values :
- // --------------------------------------------------------------------------------
- function PclZipUtilCopyBlock($p_src, $p_dest, $p_size, $p_mode=0)
- {
- $v_result = 1;
-
- if ($p_mode==0)
- {
- while ($p_size != 0)
- {
- $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE);
- $v_buffer = @fread($p_src, $v_read_size);
- @fwrite($p_dest, $v_buffer, $v_read_size);
- $p_size -= $v_read_size;
- }
- }
- else if ($p_mode==1)
- {
- while ($p_size != 0)
- {
- $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE);
- $v_buffer = @gzread($p_src, $v_read_size);
- @fwrite($p_dest, $v_buffer, $v_read_size);
- $p_size -= $v_read_size;
- }
- }
- else if ($p_mode==2)
- {
- while ($p_size != 0)
- {
- $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE);
- $v_buffer = @fread($p_src, $v_read_size);
- @gzwrite($p_dest, $v_buffer, $v_read_size);
- $p_size -= $v_read_size;
- }
- }
- else if ($p_mode==3)
- {
- while ($p_size != 0)
- {
- $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE);
- $v_buffer = @gzread($p_src, $v_read_size);
- @gzwrite($p_dest, $v_buffer, $v_read_size);
- $p_size -= $v_read_size;
- }
- }
-
- // ----- Return
- return $v_result;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : PclZipUtilRename()
- // Description :
- // This function tries to do a simple rename() function. If it fails, it
- // tries to copy the $p_src file in a new $p_dest file and then unlink the
- // first one.
- // Parameters :
- // $p_src : Old filename
- // $p_dest : New filename
- // Return Values :
- // 1 on success, 0 on failure.
- // --------------------------------------------------------------------------------
- function PclZipUtilRename($p_src, $p_dest)
- {
- $v_result = 1;
-
- // ----- Try to rename the files
- if (!@rename($p_src, $p_dest)) {
-
- // ----- Try to copy & unlink the src
- if (!@copy($p_src, $p_dest)) {
- $v_result = 0;
- }
- else if (!@unlink($p_src)) {
- $v_result = 0;
- }
- }
-
- // ----- Return
- return $v_result;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : PclZipUtilOptionText()
- // Description :
- // Translate option value in text. Mainly for debug purpose.
- // Parameters :
- // $p_option : the option value.
- // Return Values :
- // The option text value.
- // --------------------------------------------------------------------------------
- function PclZipUtilOptionText($p_option)
- {
-
- $v_list = get_defined_constants();
- for (reset($v_list); $v_key = key($v_list); next($v_list)) {
- $v_prefix = substr($v_key, 0, 10);
- if (( ($v_prefix == 'PCLZIP_OPT')
- || ($v_prefix == 'PCLZIP_CB_')
- || ($v_prefix == 'PCLZIP_ATT'))
- && ($v_list[$v_key] == $p_option)) {
- return $v_key;
- }
- }
-
- $v_result = 'Unknown';
-
- return $v_result;
- }
- // --------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------
- // Function : PclZipUtilTranslateWinPath()
- // Description :
- // Translate windows path by replacing '\' by '/' and optionally removing
- // drive letter.
- // Parameters :
- // $p_path : path to translate.
- // $p_remove_disk_letter : true | false
- // Return Values :
- // The path translated.
- // --------------------------------------------------------------------------------
- function PclZipUtilTranslateWinPath($p_path, $p_remove_disk_letter=true)
- {
- if (stristr(php_uname(), 'windows')) {
- // ----- Look for potential disk letter
- if (($p_remove_disk_letter) && (($v_position = strpos($p_path, ':')) != false)) {
- $p_path = substr($p_path, $v_position+1);
- }
- // ----- Change potential windows directory separator
- if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0,1) == '\\')) {
- $p_path = strtr($p_path, '\\', '/');
- }
- }
- return $p_path;
- }
- // --------------------------------------------------------------------------------
-
-
-?>
+zipname = $p_zipname;
+ $this->zip_fd = 0;
+ $this->magic_quotes_status = -1;
+
+ // ----- Return
+ return;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function :
+ // create($p_filelist, $p_add_dir="", $p_remove_dir="")
+ // create($p_filelist, $p_option, $p_option_value, ...)
+ // Description :
+ // This method supports two different synopsis. The first one is historical.
+ // This method creates a Zip Archive. The Zip file is created in the
+ // filesystem. The files and directories indicated in $p_filelist
+ // are added in the archive. See the parameters description for the
+ // supported format of $p_filelist.
+ // When a directory is in the list, the directory and its content is added
+ // in the archive.
+ // In this synopsis, the function takes an optional variable list of
+ // options. See bellow the supported options.
+ // Parameters :
+ // $p_filelist : An array containing file or directory names, or
+ // a string containing one filename or one directory name, or
+ // a string containing a list of filenames and/or directory
+ // names separated by spaces.
+ // $p_add_dir : A path to add before the real path of the archived file,
+ // in order to have it memorized in the archive.
+ // $p_remove_dir : A path to remove from the real path of the file to archive,
+ // in order to have a shorter path memorized in the archive.
+ // When $p_add_dir and $p_remove_dir are set, $p_remove_dir
+ // is removed first, before $p_add_dir is added.
+ // Options :
+ // PCLZIP_OPT_ADD_PATH :
+ // PCLZIP_OPT_REMOVE_PATH :
+ // PCLZIP_OPT_REMOVE_ALL_PATH :
+ // PCLZIP_OPT_COMMENT :
+ // PCLZIP_CB_PRE_ADD :
+ // PCLZIP_CB_POST_ADD :
+ // Return Values :
+ // 0 on failure,
+ // The list of the added files, with a status of the add action.
+ // (see PclZip::listContent() for list entry format)
+ // --------------------------------------------------------------------------------
+ public function create($p_filelist)
+ {
+ $v_result = 1;
+
+ // ----- Reset the error handler
+ $this->privErrorReset();
+
+ // ----- Set default values
+ $v_options = array();
+ $v_options[PCLZIP_OPT_NO_COMPRESSION] = false;
+
+ // ----- Look for variable options arguments
+ $v_size = func_num_args();
+
+ // ----- Look for arguments
+ if ($v_size > 1) {
+ // ----- Get the arguments
+ $v_arg_list = func_get_args();
+
+ // ----- Remove from the options list the first argument
+ array_shift($v_arg_list);
+ $v_size--;
+
+ // ----- Look for first arg
+ if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
+
+ // ----- Parse the options
+ $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, array(
+ PCLZIP_OPT_REMOVE_PATH => 'optional',
+ PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
+ PCLZIP_OPT_ADD_PATH => 'optional',
+ PCLZIP_CB_PRE_ADD => 'optional',
+ PCLZIP_CB_POST_ADD => 'optional',
+ PCLZIP_OPT_NO_COMPRESSION => 'optional',
+ PCLZIP_OPT_COMMENT => 'optional',
+ PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
+ PCLZIP_OPT_TEMP_FILE_ON => 'optional',
+ PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
+ //, PCLZIP_OPT_CRYPT => 'optional'
+ ));
+ if ($v_result != 1) {
+ return 0;
+ }
+
+ // ----- Look for 2 args
+ // Here we need to support the first historic synopsis of the
+ // method.
+ } else {
+
+ // ----- Get the first argument
+ $v_options[PCLZIP_OPT_ADD_PATH] = $v_arg_list[0];
+
+ // ----- Look for the optional second argument
+ if ($v_size == 2) {
+ $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1];
+ } elseif ($v_size > 2) {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments");
+
+ return 0;
+ }
+ }
+ }
+
+ // ----- Look for default option values
+ $this->privOptionDefaultThreshold($v_options);
+
+ // ----- Init
+ $v_string_list = array();
+ $v_att_list = array();
+ $v_filedescr_list = array();
+ $p_result_list = array();
+
+ // ----- Look if the $p_filelist is really an array
+ if (is_array($p_filelist)) {
+
+ // ----- Look if the first element is also an array
+ // This will mean that this is a file description entry
+ if (isset($p_filelist[0]) && is_array($p_filelist[0])) {
+ $v_att_list = $p_filelist;
+
+ // ----- The list is a list of string names
+ } else {
+ $v_string_list = $p_filelist;
+ }
+
+ // ----- Look if the $p_filelist is a string
+ } elseif (is_string($p_filelist)) {
+ // ----- Create a list from the string
+ $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist);
+
+ // ----- Invalid variable type for $p_filelist
+ } else {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_filelist");
+
+ return 0;
+ }
+
+ // ----- Reformat the string list
+ if (sizeof($v_string_list) != 0) {
+ foreach ($v_string_list as $v_string) {
+ if ($v_string != '') {
+ $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string;
+ } else {
+ }
+ }
+ }
+
+ // ----- For each file in the list check the attributes
+ $v_supported_attributes = array(
+ PCLZIP_ATT_FILE_NAME => 'mandatory',
+ PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional',
+ PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional',
+ PCLZIP_ATT_FILE_MTIME => 'optional',
+ PCLZIP_ATT_FILE_CONTENT => 'optional',
+ PCLZIP_ATT_FILE_COMMENT => 'optional'
+ );
+ foreach ($v_att_list as $v_entry) {
+ $v_result = $this->privFileDescrParseAtt($v_entry, $v_filedescr_list[], $v_options, $v_supported_attributes);
+ if ($v_result != 1) {
+ return 0;
+ }
+ }
+
+ // ----- Expand the filelist (expand directories)
+ $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options);
+ if ($v_result != 1) {
+ return 0;
+ }
+
+ // ----- Call the create fct
+ $v_result = $this->privCreate($v_filedescr_list, $p_result_list, $v_options);
+ if ($v_result != 1) {
+ return 0;
+ }
+
+ // ----- Return
+ return $p_result_list;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function :
+ // add($p_filelist, $p_add_dir="", $p_remove_dir="")
+ // add($p_filelist, $p_option, $p_option_value, ...)
+ // Description :
+ // This method supports two synopsis. The first one is historical.
+ // This methods add the list of files in an existing archive.
+ // If a file with the same name already exists, it is added at the end of the
+ // archive, the first one is still present.
+ // If the archive does not exist, it is created.
+ // Parameters :
+ // $p_filelist : An array containing file or directory names, or
+ // a string containing one filename or one directory name, or
+ // a string containing a list of filenames and/or directory
+ // names separated by spaces.
+ // $p_add_dir : A path to add before the real path of the archived file,
+ // in order to have it memorized in the archive.
+ // $p_remove_dir : A path to remove from the real path of the file to archive,
+ // in order to have a shorter path memorized in the archive.
+ // When $p_add_dir and $p_remove_dir are set, $p_remove_dir
+ // is removed first, before $p_add_dir is added.
+ // Options :
+ // PCLZIP_OPT_ADD_PATH :
+ // PCLZIP_OPT_REMOVE_PATH :
+ // PCLZIP_OPT_REMOVE_ALL_PATH :
+ // PCLZIP_OPT_COMMENT :
+ // PCLZIP_OPT_ADD_COMMENT :
+ // PCLZIP_OPT_PREPEND_COMMENT :
+ // PCLZIP_CB_PRE_ADD :
+ // PCLZIP_CB_POST_ADD :
+ // Return Values :
+ // 0 on failure,
+ // The list of the added files, with a status of the add action.
+ // (see PclZip::listContent() for list entry format)
+ // --------------------------------------------------------------------------------
+ public function add($p_filelist)
+ {
+ $v_result = 1;
+
+ // ----- Reset the error handler
+ $this->privErrorReset();
+
+ // ----- Set default values
+ $v_options = array();
+ $v_options[PCLZIP_OPT_NO_COMPRESSION] = false;
+
+ // ----- Look for variable options arguments
+ $v_size = func_num_args();
+
+ // ----- Look for arguments
+ if ($v_size > 1) {
+ // ----- Get the arguments
+ $v_arg_list = func_get_args();
+
+ // ----- Remove form the options list the first argument
+ array_shift($v_arg_list);
+ $v_size--;
+
+ // ----- Look for first arg
+ if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
+
+ // ----- Parse the options
+ $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, array(
+ PCLZIP_OPT_REMOVE_PATH => 'optional',
+ PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
+ PCLZIP_OPT_ADD_PATH => 'optional',
+ PCLZIP_CB_PRE_ADD => 'optional',
+ PCLZIP_CB_POST_ADD => 'optional',
+ PCLZIP_OPT_NO_COMPRESSION => 'optional',
+ PCLZIP_OPT_COMMENT => 'optional',
+ PCLZIP_OPT_ADD_COMMENT => 'optional',
+ PCLZIP_OPT_PREPEND_COMMENT => 'optional',
+ PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
+ PCLZIP_OPT_TEMP_FILE_ON => 'optional',
+ PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
+ //, PCLZIP_OPT_CRYPT => 'optional'
+ ));
+ if ($v_result != 1) {
+ return 0;
+ }
+
+ // ----- Look for 2 args
+ // Here we need to support the first historic synopsis of the
+ // method.
+ } else {
+
+ // ----- Get the first argument
+ $v_options[PCLZIP_OPT_ADD_PATH] = $v_add_path = $v_arg_list[0];
+
+ // ----- Look for the optional second argument
+ if ($v_size == 2) {
+ $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1];
+ } elseif ($v_size > 2) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments");
+
+ // ----- Return
+ return 0;
+ }
+ }
+ }
+
+ // ----- Look for default option values
+ $this->privOptionDefaultThreshold($v_options);
+
+ // ----- Init
+ $v_string_list = array();
+ $v_att_list = array();
+ $v_filedescr_list = array();
+ $p_result_list = array();
+
+ // ----- Look if the $p_filelist is really an array
+ if (is_array($p_filelist)) {
+
+ // ----- Look if the first element is also an array
+ // This will mean that this is a file description entry
+ if (isset($p_filelist[0]) && is_array($p_filelist[0])) {
+ $v_att_list = $p_filelist;
+
+ // ----- The list is a list of string names
+ } else {
+ $v_string_list = $p_filelist;
+ }
+
+ // ----- Look if the $p_filelist is a string
+ } elseif (is_string($p_filelist)) {
+ // ----- Create a list from the string
+ $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist);
+
+ // ----- Invalid variable type for $p_filelist
+ } else {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type '" . gettype($p_filelist) . "' for p_filelist");
+
+ return 0;
+ }
+
+ // ----- Reformat the string list
+ if (sizeof($v_string_list) != 0) {
+ foreach ($v_string_list as $v_string) {
+ $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string;
+ }
+ }
+
+ // ----- For each file in the list check the attributes
+ $v_supported_attributes = array(
+ PCLZIP_ATT_FILE_NAME => 'mandatory',
+ PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional',
+ PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional',
+ PCLZIP_ATT_FILE_MTIME => 'optional',
+ PCLZIP_ATT_FILE_CONTENT => 'optional',
+ PCLZIP_ATT_FILE_COMMENT => 'optional'
+ );
+ foreach ($v_att_list as $v_entry) {
+ $v_result = $this->privFileDescrParseAtt($v_entry, $v_filedescr_list[], $v_options, $v_supported_attributes);
+ if ($v_result != 1) {
+ return 0;
+ }
+ }
+
+ // ----- Expand the filelist (expand directories)
+ $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options);
+ if ($v_result != 1) {
+ return 0;
+ }
+
+ // ----- Call the create fct
+ $v_result = $this->privAdd($v_filedescr_list, $p_result_list, $v_options);
+ if ($v_result != 1) {
+ return 0;
+ }
+
+ // ----- Return
+ return $p_result_list;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : listContent()
+ // Description :
+ // This public method, gives the list of the files and directories, with their
+ // properties.
+ // The properties of each entries in the list are (used also in other functions) :
+ // filename : Name of the file. For a create or add action it is the filename
+ // given by the user. For an extract function it is the filename
+ // of the extracted file.
+ // stored_filename : Name of the file / directory stored in the archive.
+ // size : Size of the stored file.
+ // compressed_size : Size of the file's data compressed in the archive
+ // (without the headers overhead)
+ // mtime : Last known modification date of the file (UNIX timestamp)
+ // comment : Comment associated with the file
+ // folder : true | false
+ // index : index of the file in the archive
+ // status : status of the action (depending of the action) :
+ // Values are :
+ // ok : OK !
+ // filtered : the file / dir is not extracted (filtered by user)
+ // already_a_directory : the file can not be extracted because a
+ // directory with the same name already exists
+ // write_protected : the file can not be extracted because a file
+ // with the same name already exists and is
+ // write protected
+ // newer_exist : the file was not extracted because a newer file exists
+ // path_creation_fail : the file is not extracted because the folder
+ // does not exist and can not be created
+ // write_error : the file was not extracted because there was a
+ // error while writing the file
+ // read_error : the file was not extracted because there was a error
+ // while reading the file
+ // invalid_header : the file was not extracted because of an archive
+ // format error (bad file header)
+ // Note that each time a method can continue operating when there
+ // is an action error on a file, the error is only logged in the file status.
+ // Return Values :
+ // 0 on an unrecoverable failure,
+ // The list of the files in the archive.
+ // --------------------------------------------------------------------------------
+ public function listContent()
+ {
+ $v_result = 1;
+
+ // ----- Reset the error handler
+ $this->privErrorReset();
+
+ // ----- Check archive
+ if (!$this->privCheckFormat()) {
+ return (0);
+ }
+
+ // ----- Call the extracting fct
+ $p_list = array();
+ if (($v_result = $this->privList($p_list)) != 1) {
+ unset($p_list);
+
+ return (0);
+ }
+
+ // ----- Return
+ return $p_list;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function :
+ // extract($p_path="./", $p_remove_path="")
+ // extract([$p_option, $p_option_value, ...])
+ // Description :
+ // This method supports two synopsis. The first one is historical.
+ // This method extract all the files / directories from the archive to the
+ // folder indicated in $p_path.
+ // If you want to ignore the 'root' part of path of the memorized files
+ // you can indicate this in the optional $p_remove_path parameter.
+ // By default, if a newer file with the same name already exists, the
+ // file is not extracted.
+ //
+ // If both PCLZIP_OPT_PATH and PCLZIP_OPT_ADD_PATH aoptions
+ // are used, the path indicated in PCLZIP_OPT_ADD_PATH is append
+ // at the end of the path value of PCLZIP_OPT_PATH.
+ // Parameters :
+ // $p_path : Path where the files and directories are to be extracted
+ // $p_remove_path : First part ('root' part) of the memorized path
+ // (if any similar) to remove while extracting.
+ // Options :
+ // PCLZIP_OPT_PATH :
+ // PCLZIP_OPT_ADD_PATH :
+ // PCLZIP_OPT_REMOVE_PATH :
+ // PCLZIP_OPT_REMOVE_ALL_PATH :
+ // PCLZIP_CB_PRE_EXTRACT :
+ // PCLZIP_CB_POST_EXTRACT :
+ // Return Values :
+ // 0 or a negative value on failure,
+ // The list of the extracted files, with a status of the action.
+ // (see PclZip::listContent() for list entry format)
+ // --------------------------------------------------------------------------------
+ public function extract()
+ {
+ $v_result = 1;
+
+ // ----- Reset the error handler
+ $this->privErrorReset();
+
+ // ----- Check archive
+ if (!$this->privCheckFormat()) {
+ return (0);
+ }
+
+ // ----- Set default values
+ $v_options = array();
+ // $v_path = "./";
+ $v_path = '';
+ $v_remove_path = "";
+ $v_remove_all_path = false;
+
+ // ----- Look for variable options arguments
+ $v_size = func_num_args();
+
+ // ----- Default values for option
+ $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = false;
+
+ // ----- Look for arguments
+ if ($v_size > 0) {
+ // ----- Get the arguments
+ $v_arg_list = func_get_args();
+
+ // ----- Look for first arg
+ if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
+
+ // ----- Parse the options
+ $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, array(
+ PCLZIP_OPT_PATH => 'optional',
+ PCLZIP_OPT_REMOVE_PATH => 'optional',
+ PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
+ PCLZIP_OPT_ADD_PATH => 'optional',
+ PCLZIP_CB_PRE_EXTRACT => 'optional',
+ PCLZIP_CB_POST_EXTRACT => 'optional',
+ PCLZIP_OPT_SET_CHMOD => 'optional',
+ PCLZIP_OPT_BY_NAME => 'optional',
+ PCLZIP_OPT_BY_EREG => 'optional',
+ PCLZIP_OPT_BY_PREG => 'optional',
+ PCLZIP_OPT_BY_INDEX => 'optional',
+ PCLZIP_OPT_EXTRACT_AS_STRING => 'optional',
+ PCLZIP_OPT_EXTRACT_IN_OUTPUT => 'optional',
+ PCLZIP_OPT_REPLACE_NEWER => 'optional',
+ PCLZIP_OPT_STOP_ON_ERROR => 'optional',
+ PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional',
+ PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
+ PCLZIP_OPT_TEMP_FILE_ON => 'optional',
+ PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
+ ));
+ if ($v_result != 1) {
+ return 0;
+ }
+
+ // ----- Set the arguments
+ if (isset($v_options[PCLZIP_OPT_PATH])) {
+ $v_path = $v_options[PCLZIP_OPT_PATH];
+ }
+ if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) {
+ $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH];
+ }
+ if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) {
+ $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH];
+ }
+ if (isset($v_options[PCLZIP_OPT_ADD_PATH])) {
+ // ----- Check for '/' in last path char
+ if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) {
+ $v_path .= '/';
+ }
+ $v_path .= $v_options[PCLZIP_OPT_ADD_PATH];
+ }
+
+ // ----- Look for 2 args
+ // Here we need to support the first historic synopsis of the
+ // method.
+ } else {
+
+ // ----- Get the first argument
+ $v_path = $v_arg_list[0];
+
+ // ----- Look for the optional second argument
+ if ($v_size == 2) {
+ $v_remove_path = $v_arg_list[1];
+ } elseif ($v_size > 2) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments");
+
+ // ----- Return
+ return 0;
+ }
+ }
+ }
+
+ // ----- Look for default option values
+ $this->privOptionDefaultThreshold($v_options);
+
+ // ----- Trace
+
+ // ----- Call the extracting fct
+ $p_list = array();
+ $v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, $v_remove_all_path, $v_options);
+ if ($v_result < 1) {
+ unset($p_list);
+
+ return (0);
+ }
+
+ // ----- Return
+ return $p_list;
+ }
+ // --------------------------------------------------------------------------------
+
+
+ // --------------------------------------------------------------------------------
+ // Function :
+ // extractByIndex($p_index, $p_path="./", $p_remove_path="")
+ // extractByIndex($p_index, [$p_option, $p_option_value, ...])
+ // Description :
+ // This method supports two synopsis. The first one is historical.
+ // This method is doing a partial extract of the archive.
+ // The extracted files or folders are identified by their index in the
+ // archive (from 0 to n).
+ // Note that if the index identify a folder, only the folder entry is
+ // extracted, not all the files included in the archive.
+ // Parameters :
+ // $p_index : A single index (integer) or a string of indexes of files to
+ // extract. The form of the string is "0,4-6,8-12" with only numbers
+ // and '-' for range or ',' to separate ranges. No spaces or ';'
+ // are allowed.
+ // $p_path : Path where the files and directories are to be extracted
+ // $p_remove_path : First part ('root' part) of the memorized path
+ // (if any similar) to remove while extracting.
+ // Options :
+ // PCLZIP_OPT_PATH :
+ // PCLZIP_OPT_ADD_PATH :
+ // PCLZIP_OPT_REMOVE_PATH :
+ // PCLZIP_OPT_REMOVE_ALL_PATH :
+ // PCLZIP_OPT_EXTRACT_AS_STRING : The files are extracted as strings and
+ // not as files.
+ // The resulting content is in a new field 'content' in the file
+ // structure.
+ // This option must be used alone (any other options are ignored).
+ // PCLZIP_CB_PRE_EXTRACT :
+ // PCLZIP_CB_POST_EXTRACT :
+ // Return Values :
+ // 0 on failure,
+ // The list of the extracted files, with a status of the action.
+ // (see PclZip::listContent() for list entry format)
+ // --------------------------------------------------------------------------------
+ //function extractByIndex($p_index, options...)
+ public function extractByIndex($p_index)
+ {
+ $v_result = 1;
+
+ // ----- Reset the error handler
+ $this->privErrorReset();
+
+ // ----- Check archive
+ if (!$this->privCheckFormat()) {
+ return (0);
+ }
+
+ // ----- Set default values
+ $v_options = array();
+ // $v_path = "./";
+ $v_path = '';
+ $v_remove_path = "";
+ $v_remove_all_path = false;
+
+ // ----- Look for variable options arguments
+ $v_size = func_num_args();
+
+ // ----- Default values for option
+ $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = false;
+
+ // ----- Look for arguments
+ if ($v_size > 1) {
+ // ----- Get the arguments
+ $v_arg_list = func_get_args();
+
+ // ----- Remove form the options list the first argument
+ array_shift($v_arg_list);
+ $v_size--;
+
+ // ----- Look for first arg
+ if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
+
+ // ----- Parse the options
+ $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, array(
+ PCLZIP_OPT_PATH => 'optional',
+ PCLZIP_OPT_REMOVE_PATH => 'optional',
+ PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
+ PCLZIP_OPT_EXTRACT_AS_STRING => 'optional',
+ PCLZIP_OPT_ADD_PATH => 'optional',
+ PCLZIP_CB_PRE_EXTRACT => 'optional',
+ PCLZIP_CB_POST_EXTRACT => 'optional',
+ PCLZIP_OPT_SET_CHMOD => 'optional',
+ PCLZIP_OPT_REPLACE_NEWER => 'optional',
+ PCLZIP_OPT_STOP_ON_ERROR => 'optional',
+ PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional',
+ PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
+ PCLZIP_OPT_TEMP_FILE_ON => 'optional',
+ PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
+ ));
+ if ($v_result != 1) {
+ return 0;
+ }
+
+ // ----- Set the arguments
+ if (isset($v_options[PCLZIP_OPT_PATH])) {
+ $v_path = $v_options[PCLZIP_OPT_PATH];
+ }
+ if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) {
+ $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH];
+ }
+ if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) {
+ $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH];
+ }
+ if (isset($v_options[PCLZIP_OPT_ADD_PATH])) {
+ // ----- Check for '/' in last path char
+ if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) {
+ $v_path .= '/';
+ }
+ $v_path .= $v_options[PCLZIP_OPT_ADD_PATH];
+ }
+ if (!isset($v_options[PCLZIP_OPT_EXTRACT_AS_STRING])) {
+ $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = false;
+ } else {
+ }
+
+ // ----- Look for 2 args
+ // Here we need to support the first historic synopsis of the
+ // method.
+ } else {
+
+ // ----- Get the first argument
+ $v_path = $v_arg_list[0];
+
+ // ----- Look for the optional second argument
+ if ($v_size == 2) {
+ $v_remove_path = $v_arg_list[1];
+ } elseif ($v_size > 2) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments");
+
+ // ----- Return
+ return 0;
+ }
+ }
+ }
+
+ // ----- Trace
+
+ // ----- Trick
+ // Here I want to reuse extractByRule(), so I need to parse the $p_index
+ // with privParseOptions()
+ $v_arg_trick = array(
+ PCLZIP_OPT_BY_INDEX,
+ $p_index
+ );
+ $v_options_trick = array();
+ $v_result = $this->privParseOptions($v_arg_trick, sizeof($v_arg_trick), $v_options_trick, array(
+ PCLZIP_OPT_BY_INDEX => 'optional'
+ ));
+ if ($v_result != 1) {
+ return 0;
+ }
+ $v_options[PCLZIP_OPT_BY_INDEX] = $v_options_trick[PCLZIP_OPT_BY_INDEX];
+
+ // ----- Look for default option values
+ $this->privOptionDefaultThreshold($v_options);
+
+ // ----- Call the extracting fct
+ if (($v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, $v_remove_all_path, $v_options)) < 1) {
+ return (0);
+ }
+
+ // ----- Return
+ return $p_list;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function :
+ // delete([$p_option, $p_option_value, ...])
+ // Description :
+ // This method removes files from the archive.
+ // If no parameters are given, then all the archive is emptied.
+ // Parameters :
+ // None or optional arguments.
+ // Options :
+ // PCLZIP_OPT_BY_INDEX :
+ // PCLZIP_OPT_BY_NAME :
+ // PCLZIP_OPT_BY_EREG :
+ // PCLZIP_OPT_BY_PREG :
+ // Return Values :
+ // 0 on failure,
+ // The list of the files which are still present in the archive.
+ // (see PclZip::listContent() for list entry format)
+ // --------------------------------------------------------------------------------
+ public function delete()
+ {
+ $v_result = 1;
+
+ // ----- Reset the error handler
+ $this->privErrorReset();
+
+ // ----- Check archive
+ if (!$this->privCheckFormat()) {
+ return (0);
+ }
+
+ // ----- Set default values
+ $v_options = array();
+
+ // ----- Look for variable options arguments
+ $v_size = func_num_args();
+
+ // ----- Look for arguments
+ if ($v_size > 0) {
+ // ----- Get the arguments
+ $v_arg_list = func_get_args();
+
+ // ----- Parse the options
+ $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, array(
+ PCLZIP_OPT_BY_NAME => 'optional',
+ PCLZIP_OPT_BY_EREG => 'optional',
+ PCLZIP_OPT_BY_PREG => 'optional',
+ PCLZIP_OPT_BY_INDEX => 'optional'
+ ));
+ if ($v_result != 1) {
+ return 0;
+ }
+ }
+
+ // ----- Magic quotes trick
+ $this->privDisableMagicQuotes();
+
+ // ----- Call the delete fct
+ $v_list = array();
+ if (($v_result = $this->privDeleteByRule($v_list, $v_options)) != 1) {
+ $this->privSwapBackMagicQuotes();
+ unset($v_list);
+
+ return (0);
+ }
+
+ // ----- Magic quotes trick
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Return
+ return $v_list;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : deleteByIndex()
+ // Description :
+ // ***** Deprecated *****
+ // delete(PCLZIP_OPT_BY_INDEX, $p_index) should be prefered.
+ // --------------------------------------------------------------------------------
+ public function deleteByIndex($p_index)
+ {
+
+ $p_list = $this->delete(PCLZIP_OPT_BY_INDEX, $p_index);
+
+ // ----- Return
+ return $p_list;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : properties()
+ // Description :
+ // This method gives the properties of the archive.
+ // The properties are :
+ // nb : Number of files in the archive
+ // comment : Comment associated with the archive file
+ // status : not_exist, ok
+ // Parameters :
+ // None
+ // Return Values :
+ // 0 on failure,
+ // An array with the archive properties.
+ // --------------------------------------------------------------------------------
+ public function properties()
+ {
+
+ // ----- Reset the error handler
+ $this->privErrorReset();
+
+ // ----- Magic quotes trick
+ $this->privDisableMagicQuotes();
+
+ // ----- Check archive
+ if (!$this->privCheckFormat()) {
+ $this->privSwapBackMagicQuotes();
+
+ return (0);
+ }
+
+ // ----- Default properties
+ $v_prop = array();
+ $v_prop['comment'] = '';
+ $v_prop['nb'] = 0;
+ $v_prop['status'] = 'not_exist';
+
+ // ----- Look if file exists
+ if (@is_file($this->zipname)) {
+ // ----- Open the zip file
+ if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0) {
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \'' . $this->zipname . '\' in binary read mode');
+
+ // ----- Return
+ return 0;
+ }
+
+ // ----- Read the central directory informations
+ $v_central_dir = array();
+ if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) {
+ $this->privSwapBackMagicQuotes();
+
+ return 0;
+ }
+
+ // ----- Close the zip file
+ $this->privCloseFd();
+
+ // ----- Set the user attributes
+ $v_prop['comment'] = $v_central_dir['comment'];
+ $v_prop['nb'] = $v_central_dir['entries'];
+ $v_prop['status'] = 'ok';
+ }
+
+ // ----- Magic quotes trick
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Return
+ return $v_prop;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : duplicate()
+ // Description :
+ // This method creates an archive by copying the content of an other one. If
+ // the archive already exist, it is replaced by the new one without any warning.
+ // Parameters :
+ // $p_archive : The filename of a valid archive, or
+ // a valid PclZip object.
+ // Return Values :
+ // 1 on success.
+ // 0 or a negative value on error (error code).
+ // --------------------------------------------------------------------------------
+ public function duplicate($p_archive)
+ {
+ $v_result = 1;
+
+ // ----- Reset the error handler
+ $this->privErrorReset();
+
+ // ----- Look if the $p_archive is a PclZip object
+ if ((is_object($p_archive)) && (get_class($p_archive) == 'pclzip')) {
+
+ // ----- Duplicate the archive
+ $v_result = $this->privDuplicate($p_archive->zipname);
+
+ // ----- Look if the $p_archive is a string (so a filename)
+ } elseif (is_string($p_archive)) {
+
+ // ----- Check that $p_archive is a valid zip file
+ // TBC : Should also check the archive format
+ if (!is_file($p_archive)) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "No file with filename '" . $p_archive . "'");
+ $v_result = PCLZIP_ERR_MISSING_FILE;
+ } else {
+ // ----- Duplicate the archive
+ $v_result = $this->privDuplicate($p_archive);
+ }
+
+ // ----- Invalid variable
+ } else {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add");
+ $v_result = PCLZIP_ERR_INVALID_PARAMETER;
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : merge()
+ // Description :
+ // This method merge the $p_archive_to_add archive at the end of the current
+ // one ($this).
+ // If the archive ($this) does not exist, the merge becomes a duplicate.
+ // If the $p_archive_to_add archive does not exist, the merge is a success.
+ // Parameters :
+ // $p_archive_to_add : It can be directly the filename of a valid zip archive,
+ // or a PclZip object archive.
+ // Return Values :
+ // 1 on success,
+ // 0 or negative values on error (see below).
+ // --------------------------------------------------------------------------------
+ public function merge($p_archive_to_add)
+ {
+ $v_result = 1;
+
+ // ----- Reset the error handler
+ $this->privErrorReset();
+
+ // ----- Check archive
+ if (!$this->privCheckFormat()) {
+ return (0);
+ }
+
+ // ----- Look if the $p_archive_to_add is a PclZip object
+ if ((is_object($p_archive_to_add)) && (get_class($p_archive_to_add) == 'pclzip')) {
+
+ // ----- Merge the archive
+ $v_result = $this->privMerge($p_archive_to_add);
+
+ // ----- Look if the $p_archive_to_add is a string (so a filename)
+ } elseif (is_string($p_archive_to_add)) {
+
+ // ----- Create a temporary archive
+ $v_object_archive = new PclZip($p_archive_to_add);
+
+ // ----- Merge the archive
+ $v_result = $this->privMerge($v_object_archive);
+
+ // ----- Invalid variable
+ } else {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add");
+ $v_result = PCLZIP_ERR_INVALID_PARAMETER;
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : errorCode()
+ // Description :
+ // Parameters :
+ // --------------------------------------------------------------------------------
+ public function errorCode()
+ {
+ if (PCLZIP_ERROR_EXTERNAL == 1) {
+ return (PclErrorCode());
+ } else {
+ return ($this->error_code);
+ }
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : errorName()
+ // Description :
+ // Parameters :
+ // --------------------------------------------------------------------------------
+ public function errorName($p_with_code = false)
+ {
+ $v_name = array(
+ PCLZIP_ERR_NO_ERROR => 'PCLZIP_ERR_NO_ERROR',
+ PCLZIP_ERR_WRITE_OPEN_FAIL => 'PCLZIP_ERR_WRITE_OPEN_FAIL',
+ PCLZIP_ERR_READ_OPEN_FAIL => 'PCLZIP_ERR_READ_OPEN_FAIL',
+ PCLZIP_ERR_INVALID_PARAMETER => 'PCLZIP_ERR_INVALID_PARAMETER',
+ PCLZIP_ERR_MISSING_FILE => 'PCLZIP_ERR_MISSING_FILE',
+ PCLZIP_ERR_FILENAME_TOO_LONG => 'PCLZIP_ERR_FILENAME_TOO_LONG',
+ PCLZIP_ERR_INVALID_ZIP => 'PCLZIP_ERR_INVALID_ZIP',
+ PCLZIP_ERR_BAD_EXTRACTED_FILE => 'PCLZIP_ERR_BAD_EXTRACTED_FILE',
+ PCLZIP_ERR_DIR_CREATE_FAIL => 'PCLZIP_ERR_DIR_CREATE_FAIL',
+ PCLZIP_ERR_BAD_EXTENSION => 'PCLZIP_ERR_BAD_EXTENSION',
+ PCLZIP_ERR_BAD_FORMAT => 'PCLZIP_ERR_BAD_FORMAT',
+ PCLZIP_ERR_DELETE_FILE_FAIL => 'PCLZIP_ERR_DELETE_FILE_FAIL',
+ PCLZIP_ERR_RENAME_FILE_FAIL => 'PCLZIP_ERR_RENAME_FILE_FAIL',
+ PCLZIP_ERR_BAD_CHECKSUM => 'PCLZIP_ERR_BAD_CHECKSUM',
+ PCLZIP_ERR_INVALID_ARCHIVE_ZIP => 'PCLZIP_ERR_INVALID_ARCHIVE_ZIP',
+ PCLZIP_ERR_MISSING_OPTION_VALUE => 'PCLZIP_ERR_MISSING_OPTION_VALUE',
+ PCLZIP_ERR_INVALID_OPTION_VALUE => 'PCLZIP_ERR_INVALID_OPTION_VALUE',
+ PCLZIP_ERR_UNSUPPORTED_COMPRESSION => 'PCLZIP_ERR_UNSUPPORTED_COMPRESSION',
+ PCLZIP_ERR_UNSUPPORTED_ENCRYPTION => 'PCLZIP_ERR_UNSUPPORTED_ENCRYPTION',
+ PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE => 'PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE',
+ PCLZIP_ERR_DIRECTORY_RESTRICTION => 'PCLZIP_ERR_DIRECTORY_RESTRICTION'
+ );
+
+ if (isset($v_name[$this->error_code])) {
+ $v_value = $v_name[$this->error_code];
+ } else {
+ $v_value = 'NoName';
+ }
+
+ if ($p_with_code) {
+ return ($v_value . ' (' . $this->error_code . ')');
+ } else {
+ return ($v_value);
+ }
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : errorInfo()
+ // Description :
+ // Parameters :
+ // --------------------------------------------------------------------------------
+ public function errorInfo($p_full = false)
+ {
+ if (PCLZIP_ERROR_EXTERNAL == 1) {
+ return (PclErrorString());
+ } else {
+ if ($p_full) {
+ return ($this->errorName(true) . " : " . $this->error_string);
+ } else {
+ return ($this->error_string . " [code " . $this->error_code . "]");
+ }
+ }
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // ***** UNDER THIS LINE ARE DEFINED PRIVATE INTERNAL FUNCTIONS *****
+ // ***** *****
+ // ***** THESES FUNCTIONS MUST NOT BE USED DIRECTLY *****
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privCheckFormat()
+ // Description :
+ // This method check that the archive exists and is a valid zip archive.
+ // Several level of check exists. (futur)
+ // Parameters :
+ // $p_level : Level of check. Default 0.
+ // 0 : Check the first bytes (magic codes) (default value))
+ // 1 : 0 + Check the central directory (futur)
+ // 2 : 1 + Check each file header (futur)
+ // Return Values :
+ // true on success,
+ // false on error, the error code is set.
+ // --------------------------------------------------------------------------------
+ public function privCheckFormat($p_level = 0)
+ {
+ $v_result = true;
+
+ // ----- Reset the file system cache
+ clearstatcache();
+
+ // ----- Reset the error handler
+ $this->privErrorReset();
+
+ // ----- Look if the file exits
+ if (!is_file($this->zipname)) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "Missing archive file '" . $this->zipname . "'");
+
+ return (false);
+ }
+
+ // ----- Check that the file is readeable
+ if (!is_readable($this->zipname)) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to read archive '" . $this->zipname . "'");
+
+ return (false);
+ }
+
+ // ----- Check the magic code
+ // TBC
+
+ // ----- Check the central header
+ // TBC
+
+ // ----- Check each file header
+ // TBC
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privParseOptions()
+ // Description :
+ // This internal methods reads the variable list of arguments ($p_options_list,
+ // $p_size) and generate an array with the options and values ($v_result_list).
+ // $v_requested_options contains the options that can be present and those that
+ // must be present.
+ // $v_requested_options is an array, with the option value as key, and 'optional',
+ // or 'mandatory' as value.
+ // Parameters :
+ // See above.
+ // Return Values :
+ // 1 on success.
+ // 0 on failure.
+ // --------------------------------------------------------------------------------
+ public function privParseOptions(&$p_options_list, $p_size, &$v_result_list, $v_requested_options = false)
+ {
+ $v_result = 1;
+
+ // ----- Read the options
+ $i = 0;
+ while ($i < $p_size) {
+
+ // ----- Check if the option is supported
+ if (!isset($v_requested_options[$p_options_list[$i]])) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid optional parameter '" . $p_options_list[$i] . "' for this method");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Look for next option
+ switch ($p_options_list[$i]) {
+ // ----- Look for options that request a path value
+ case PCLZIP_OPT_PATH:
+ case PCLZIP_OPT_REMOVE_PATH:
+ case PCLZIP_OPT_ADD_PATH:
+ // ----- Check the number of parameters
+ if (($i + 1) >= $p_size) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Get the value
+ $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i + 1], false);
+ $i++;
+ break;
+
+ case PCLZIP_OPT_TEMP_FILE_THRESHOLD:
+ // ----- Check the number of parameters
+ if (($i + 1) >= $p_size) {
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'");
+
+ return PclZip::errorCode();
+ }
+
+ // ----- Check for incompatible options
+ if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '" . PclZipUtilOptionText($p_options_list[$i]) . "' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'");
+
+ return PclZip::errorCode();
+ }
+
+ // ----- Check the value
+ $v_value = $p_options_list[$i + 1];
+ if ((!is_integer($v_value)) || ($v_value < 0)) {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Integer expected for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'");
+
+ return PclZip::errorCode();
+ }
+
+ // ----- Get the value (and convert it in bytes)
+ $v_result_list[$p_options_list[$i]] = $v_value * 1048576;
+ $i++;
+ break;
+
+ case PCLZIP_OPT_TEMP_FILE_ON:
+ // ----- Check for incompatible options
+ if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '" . PclZipUtilOptionText($p_options_list[$i]) . "' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'");
+
+ return PclZip::errorCode();
+ }
+
+ $v_result_list[$p_options_list[$i]] = true;
+ break;
+
+ case PCLZIP_OPT_TEMP_FILE_OFF:
+ // ----- Check for incompatible options
+ if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_ON])) {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '" . PclZipUtilOptionText($p_options_list[$i]) . "' can not be used with option 'PCLZIP_OPT_TEMP_FILE_ON'");
+
+ return PclZip::errorCode();
+ }
+ // ----- Check for incompatible options
+ if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '" . PclZipUtilOptionText($p_options_list[$i]) . "' can not be used with option 'PCLZIP_OPT_TEMP_FILE_THRESHOLD'");
+
+ return PclZip::errorCode();
+ }
+
+ $v_result_list[$p_options_list[$i]] = true;
+ break;
+
+ case PCLZIP_OPT_EXTRACT_DIR_RESTRICTION:
+ // ----- Check the number of parameters
+ if (($i + 1) >= $p_size) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Get the value
+ if (is_string($p_options_list[$i + 1]) && ($p_options_list[$i + 1] != '')) {
+ $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i + 1], false);
+ $i++;
+ } else {
+ }
+ break;
+
+ // ----- Look for options that request an array of string for value
+ case PCLZIP_OPT_BY_NAME:
+ // ----- Check the number of parameters
+ if (($i + 1) >= $p_size) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Get the value
+ if (is_string($p_options_list[$i + 1])) {
+ $v_result_list[$p_options_list[$i]][0] = $p_options_list[$i + 1];
+ } elseif (is_array($p_options_list[$i + 1])) {
+ $v_result_list[$p_options_list[$i]] = $p_options_list[$i + 1];
+ } else {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+ $i++;
+ break;
+
+ // ----- Look for options that request an EREG or PREG expression
+ case PCLZIP_OPT_BY_EREG:
+ $p_options_list[$i] = PCLZIP_OPT_BY_PREG;
+ // ereg() is deprecated starting with PHP 5.3. Move PCLZIP_OPT_BY_EREG
+ // to PCLZIP_OPT_BY_PREG
+ case PCLZIP_OPT_BY_PREG:
+ //case PCLZIP_OPT_CRYPT :
+ // ----- Check the number of parameters
+ if (($i + 1) >= $p_size) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Get the value
+ if (is_string($p_options_list[$i + 1])) {
+ $v_result_list[$p_options_list[$i]] = $p_options_list[$i + 1];
+ } else {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+ $i++;
+ break;
+
+ // ----- Look for options that takes a string
+ case PCLZIP_OPT_COMMENT:
+ case PCLZIP_OPT_ADD_COMMENT:
+ case PCLZIP_OPT_PREPEND_COMMENT:
+ // ----- Check the number of parameters
+ if (($i + 1) >= $p_size) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Get the value
+ if (is_string($p_options_list[$i + 1])) {
+ $v_result_list[$p_options_list[$i]] = $p_options_list[$i + 1];
+ } else {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+ $i++;
+ break;
+
+ // ----- Look for options that request an array of index
+ case PCLZIP_OPT_BY_INDEX:
+ // ----- Check the number of parameters
+ if (($i + 1) >= $p_size) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Get the value
+ $v_work_list = array();
+ if (is_string($p_options_list[$i + 1])) {
+
+ // ----- Remove spaces
+ $p_options_list[$i + 1] = strtr($p_options_list[$i + 1], ' ', '');
+
+ // ----- Parse items
+ $v_work_list = explode(",", $p_options_list[$i + 1]);
+ } elseif (is_integer($p_options_list[$i + 1])) {
+ $v_work_list[0] = $p_options_list[$i + 1] . '-' . $p_options_list[$i + 1];
+ } elseif (is_array($p_options_list[$i + 1])) {
+ $v_work_list = $p_options_list[$i + 1];
+ } else {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Value must be integer, string or array for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Reduce the index list
+ // each index item in the list must be a couple with a start and
+ // an end value : [0,3], [5-5], [8-10], ...
+ // ----- Check the format of each item
+ $v_sort_flag = false;
+ $v_sort_value = 0;
+ for ($j = 0; $j < sizeof($v_work_list); $j++) {
+ // ----- Explode the item
+ $v_item_list = explode("-", $v_work_list[$j]);
+ $v_size_item_list = sizeof($v_item_list);
+
+ // ----- TBC : Here we might check that each item is a
+ // real integer ...
+
+ // ----- Look for single value
+ if ($v_size_item_list == 1) {
+ // ----- Set the option value
+ $v_result_list[$p_options_list[$i]][$j]['start'] = $v_item_list[0];
+ $v_result_list[$p_options_list[$i]][$j]['end'] = $v_item_list[0];
+ } elseif ($v_size_item_list == 2) {
+ // ----- Set the option value
+ $v_result_list[$p_options_list[$i]][$j]['start'] = $v_item_list[0];
+ $v_result_list[$p_options_list[$i]][$j]['end'] = $v_item_list[1];
+ } else {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Too many values in index range for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Look for list sort
+ if ($v_result_list[$p_options_list[$i]][$j]['start'] < $v_sort_value) {
+ $v_sort_flag = true;
+
+ // ----- TBC : An automatic sort should be writen ...
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Invalid order of index range for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+ $v_sort_value = $v_result_list[$p_options_list[$i]][$j]['start'];
+ }
+
+ // ----- Sort the items
+ if ($v_sort_flag) {
+ // TBC : To Be Completed
+ }
+
+ // ----- Next option
+ $i++;
+ break;
+
+ // ----- Look for options that request no value
+ case PCLZIP_OPT_REMOVE_ALL_PATH:
+ case PCLZIP_OPT_EXTRACT_AS_STRING:
+ case PCLZIP_OPT_NO_COMPRESSION:
+ case PCLZIP_OPT_EXTRACT_IN_OUTPUT:
+ case PCLZIP_OPT_REPLACE_NEWER:
+ case PCLZIP_OPT_STOP_ON_ERROR:
+ $v_result_list[$p_options_list[$i]] = true;
+ break;
+
+ // ----- Look for options that request an octal value
+ case PCLZIP_OPT_SET_CHMOD:
+ // ----- Check the number of parameters
+ if (($i + 1) >= $p_size) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Get the value
+ $v_result_list[$p_options_list[$i]] = $p_options_list[$i + 1];
+ $i++;
+ break;
+
+ // ----- Look for options that request a call-back
+ case PCLZIP_CB_PRE_EXTRACT:
+ case PCLZIP_CB_POST_EXTRACT:
+ case PCLZIP_CB_PRE_ADD:
+ case PCLZIP_CB_POST_ADD:
+ /* for futur use
+ case PCLZIP_CB_PRE_DELETE :
+ case PCLZIP_CB_POST_DELETE :
+ case PCLZIP_CB_PRE_LIST :
+ case PCLZIP_CB_POST_LIST :
+ */
+ // ----- Check the number of parameters
+ if (($i + 1) >= $p_size) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Get the value
+ $v_function_name = $p_options_list[$i + 1];
+
+ // ----- Check that the value is a valid existing function
+ if (!function_exists($v_function_name)) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Function '" . $v_function_name . "()' is not an existing function for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Set the attribute
+ $v_result_list[$p_options_list[$i]] = $v_function_name;
+ $i++;
+ break;
+
+ default:
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Unknown parameter '" . $p_options_list[$i] . "'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Next options
+ $i++;
+ }
+
+ // ----- Look for mandatory options
+ if ($v_requested_options !== false) {
+ for ($key = reset($v_requested_options); $key = key($v_requested_options); $key = next($v_requested_options)) {
+ // ----- Look for mandatory option
+ if ($v_requested_options[$key] == 'mandatory') {
+ // ----- Look if present
+ if (!isset($v_result_list[$key])) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter " . PclZipUtilOptionText($key) . "(" . $key . ")");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+ }
+ }
+ }
+
+ // ----- Look for default values
+ if (!isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) {
+
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privOptionDefaultThreshold()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ public function privOptionDefaultThreshold(&$p_options)
+ {
+ $v_result = 1;
+
+ if (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) || isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) {
+ return $v_result;
+ }
+
+ // ----- Get 'memory_limit' configuration value
+ $v_memory_limit = ini_get('memory_limit');
+ $v_memory_limit = trim($v_memory_limit);
+ $last = strtolower(substr($v_memory_limit, -1));
+ $v_memory_limit = preg_replace('/\s*[KkMmGg]$/', '', $v_memory_limit);
+
+ if ($last == 'g') {
+ //$v_memory_limit = $v_memory_limit*1024*1024*1024;
+ $v_memory_limit = $v_memory_limit * 1073741824;
+ }
+ if ($last == 'm') {
+ //$v_memory_limit = $v_memory_limit*1024*1024;
+ $v_memory_limit = $v_memory_limit * 1048576;
+ }
+ if ($last == 'k') {
+ $v_memory_limit = $v_memory_limit * 1024;
+ }
+
+ $p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] = floor($v_memory_limit * PCLZIP_TEMPORARY_FILE_RATIO);
+
+ // ----- Sanity check : No threshold if value lower than 1M
+ if ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] < 1048576) {
+ unset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]);
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privFileDescrParseAtt()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // 1 on success.
+ // 0 on failure.
+ // --------------------------------------------------------------------------------
+ public function privFileDescrParseAtt(&$p_file_list, &$p_filedescr, $v_options, $v_requested_options = false)
+ {
+ $v_result = 1;
+
+ // ----- For each file in the list check the attributes
+ foreach ($p_file_list as $v_key => $v_value) {
+
+ // ----- Check if the option is supported
+ if (!isset($v_requested_options[$v_key])) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file attribute '" . $v_key . "' for this file");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Look for attribute
+ switch ($v_key) {
+ case PCLZIP_ATT_FILE_NAME:
+ if (!is_string($v_value)) {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type " . gettype($v_value) . ". String expected for attribute '" . PclZipUtilOptionText($v_key) . "'");
+
+ return PclZip::errorCode();
+ }
+
+ $p_filedescr['filename'] = PclZipUtilPathReduction($v_value);
+
+ if ($p_filedescr['filename'] == '') {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty filename for attribute '" . PclZipUtilOptionText($v_key) . "'");
+
+ return PclZip::errorCode();
+ }
+
+ break;
+
+ case PCLZIP_ATT_FILE_NEW_SHORT_NAME:
+ if (!is_string($v_value)) {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type " . gettype($v_value) . ". String expected for attribute '" . PclZipUtilOptionText($v_key) . "'");
+
+ return PclZip::errorCode();
+ }
+
+ $p_filedescr['new_short_name'] = PclZipUtilPathReduction($v_value);
+
+ if ($p_filedescr['new_short_name'] == '') {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty short filename for attribute '" . PclZipUtilOptionText($v_key) . "'");
+
+ return PclZip::errorCode();
+ }
+ break;
+
+ case PCLZIP_ATT_FILE_NEW_FULL_NAME:
+ if (!is_string($v_value)) {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type " . gettype($v_value) . ". String expected for attribute '" . PclZipUtilOptionText($v_key) . "'");
+
+ return PclZip::errorCode();
+ }
+
+ $p_filedescr['new_full_name'] = PclZipUtilPathReduction($v_value);
+
+ if ($p_filedescr['new_full_name'] == '') {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty full filename for attribute '" . PclZipUtilOptionText($v_key) . "'");
+
+ return PclZip::errorCode();
+ }
+ break;
+
+ // ----- Look for options that takes a string
+ case PCLZIP_ATT_FILE_COMMENT:
+ if (!is_string($v_value)) {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type " . gettype($v_value) . ". String expected for attribute '" . PclZipUtilOptionText($v_key) . "'");
+
+ return PclZip::errorCode();
+ }
+
+ $p_filedescr['comment'] = $v_value;
+ break;
+
+ case PCLZIP_ATT_FILE_MTIME:
+ if (!is_integer($v_value)) {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type " . gettype($v_value) . ". Integer expected for attribute '" . PclZipUtilOptionText($v_key) . "'");
+
+ return PclZip::errorCode();
+ }
+
+ $p_filedescr['mtime'] = $v_value;
+ break;
+
+ case PCLZIP_ATT_FILE_CONTENT:
+ $p_filedescr['content'] = $v_value;
+ break;
+
+ default:
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Unknown parameter '" . $v_key . "'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Look for mandatory options
+ if ($v_requested_options !== false) {
+ for ($key = reset($v_requested_options); $key = key($v_requested_options); $key = next($v_requested_options)) {
+ // ----- Look for mandatory option
+ if ($v_requested_options[$key] == 'mandatory') {
+ // ----- Look if present
+ if (!isset($p_file_list[$key])) {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter " . PclZipUtilOptionText($key) . "(" . $key . ")");
+
+ return PclZip::errorCode();
+ }
+ }
+ }
+ }
+
+ // end foreach
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privFileDescrExpand()
+ // Description :
+ // This method look for each item of the list to see if its a file, a folder
+ // or a string to be added as file. For any other type of files (link, other)
+ // just ignore the item.
+ // Then prepare the information that will be stored for that file.
+ // When its a folder, expand the folder with all the files that are in that
+ // folder (recursively).
+ // Parameters :
+ // Return Values :
+ // 1 on success.
+ // 0 on failure.
+ // --------------------------------------------------------------------------------
+ public function privFileDescrExpand(&$p_filedescr_list, &$p_options)
+ {
+ $v_result = 1;
+
+ // ----- Create a result list
+ $v_result_list = array();
+
+ // ----- Look each entry
+ for ($i = 0; $i < sizeof($p_filedescr_list); $i++) {
+
+ // ----- Get filedescr
+ $v_descr = $p_filedescr_list[$i];
+
+ // ----- Reduce the filename
+ $v_descr['filename'] = PclZipUtilTranslateWinPath($v_descr['filename'], false);
+ $v_descr['filename'] = PclZipUtilPathReduction($v_descr['filename']);
+
+ // ----- Look for real file or folder
+ if (file_exists($v_descr['filename'])) {
+ if (@is_file($v_descr['filename'])) {
+ $v_descr['type'] = 'file';
+ } elseif (@is_dir($v_descr['filename'])) {
+ $v_descr['type'] = 'folder';
+ } elseif (@is_link($v_descr['filename'])) {
+ // skip
+ continue;
+ } else {
+ // skip
+ continue;
+ }
+
+ // ----- Look for string added as file
+ } elseif (isset($v_descr['content'])) {
+ $v_descr['type'] = 'virtual_file';
+
+ // ----- Missing file
+ } else {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "File '" . $v_descr['filename'] . "' does not exist");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Calculate the stored filename
+ $this->privCalculateStoredFilename($v_descr, $p_options);
+
+ // ----- Add the descriptor in result list
+ $v_result_list[sizeof($v_result_list)] = $v_descr;
+
+ // ----- Look for folder
+ if ($v_descr['type'] == 'folder') {
+ // ----- List of items in folder
+ $v_dirlist_descr = array();
+ $v_dirlist_nb = 0;
+ if ($v_folder_handler = @opendir($v_descr['filename'])) {
+ while (($v_item_handler = @readdir($v_folder_handler)) !== false) {
+
+ // ----- Skip '.' and '..'
+ if (($v_item_handler == '.') || ($v_item_handler == '..')) {
+ continue;
+ }
+
+ // ----- Compose the full filename
+ $v_dirlist_descr[$v_dirlist_nb]['filename'] = $v_descr['filename'] . '/' . $v_item_handler;
+
+ // ----- Look for different stored filename
+ // Because the name of the folder was changed, the name of the
+ // files/sub-folders also change
+ if (($v_descr['stored_filename'] != $v_descr['filename']) && (!isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH]))) {
+ if ($v_descr['stored_filename'] != '') {
+ $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_descr['stored_filename'] . '/' . $v_item_handler;
+ } else {
+ $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_item_handler;
+ }
+ }
+
+ $v_dirlist_nb++;
+ }
+
+ @closedir($v_folder_handler);
+ } else {
+ // TBC : unable to open folder in read mode
+ }
+
+ // ----- Expand each element of the list
+ if ($v_dirlist_nb != 0) {
+ // ----- Expand
+ if (($v_result = $this->privFileDescrExpand($v_dirlist_descr, $p_options)) != 1) {
+ return $v_result;
+ }
+
+ // ----- Concat the resulting list
+ $v_result_list = array_merge($v_result_list, $v_dirlist_descr);
+ } else {
+ }
+
+ // ----- Free local array
+ unset($v_dirlist_descr);
+ }
+ }
+
+ // ----- Get the result list
+ $p_filedescr_list = $v_result_list;
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privCreate()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ public function privCreate($p_filedescr_list, &$p_result_list, &$p_options)
+ {
+ $v_result = 1;
+ $v_list_detail = array();
+
+ // ----- Magic quotes trick
+ $this->privDisableMagicQuotes();
+
+ // ----- Open the file in write mode
+ if (($v_result = $this->privOpenFd('wb')) != 1) {
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Add the list of files
+ $v_result = $this->privAddList($p_filedescr_list, $p_result_list, $p_options);
+
+ // ----- Close
+ $this->privCloseFd();
+
+ // ----- Magic quotes trick
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privAdd()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ public function privAdd($p_filedescr_list, &$p_result_list, &$p_options)
+ {
+ $v_result = 1;
+ $v_list_detail = array();
+
+ // ----- Look if the archive exists or is empty
+ if ((!is_file($this->zipname)) || (filesize($this->zipname) == 0)) {
+
+ // ----- Do a create
+ $v_result = $this->privCreate($p_filedescr_list, $p_result_list, $p_options);
+
+ // ----- Return
+ return $v_result;
+ }
+ // ----- Magic quotes trick
+ $this->privDisableMagicQuotes();
+
+ // ----- Open the zip file
+ if (($v_result = $this->privOpenFd('rb')) != 1) {
+ // ----- Magic quotes trick
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Read the central directory information
+ $v_central_dir = array();
+ if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) {
+ $this->privCloseFd();
+ $this->privSwapBackMagicQuotes();
+
+ return $v_result;
+ }
+
+ // ----- Go to beginning of File
+ @rewind($this->zip_fd);
+
+ // ----- Creates a temporary file
+ $v_zip_temp_name = PCLZIP_TEMPORARY_DIR . $this->createUniqueName('pclzip-') . '.tmp';
+
+ // ----- Open the temporary file in write mode
+ if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) {
+ $this->privCloseFd();
+ $this->privSwapBackMagicQuotes();
+
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \'' . $v_zip_temp_name . '\' in binary write mode');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Copy the files from the archive to the temporary file
+ // TBC : Here I should better append the file and go back to erase the central dir
+ $v_size = $v_central_dir['offset'];
+ while ($v_size != 0) {
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = fread($this->zip_fd, $v_read_size);
+ @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
+ $v_size -= $v_read_size;
+ }
+
+ // ----- Swap the file descriptor
+ // Here is a trick : I swap the temporary fd with the zip fd, in order to use
+ // the following methods on the temporary fil and not the real archive
+ $v_swap = $this->zip_fd;
+ $this->zip_fd = $v_zip_temp_fd;
+ $v_zip_temp_fd = $v_swap;
+
+ // ----- Add the files
+ $v_header_list = array();
+ if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1) {
+ fclose($v_zip_temp_fd);
+ $this->privCloseFd();
+ @unlink($v_zip_temp_name);
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Store the offset of the central dir
+ $v_offset = @ftell($this->zip_fd);
+
+ // ----- Copy the block of file headers from the old archive
+ $v_size = $v_central_dir['size'];
+ while ($v_size != 0) {
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = @fread($v_zip_temp_fd, $v_read_size);
+ @fwrite($this->zip_fd, $v_buffer, $v_read_size);
+ $v_size -= $v_read_size;
+ }
+
+ // ----- Create the Central Dir files header
+ for ($i = 0, $v_count = 0; $i < sizeof($v_header_list); $i++) {
+ // ----- Create the file header
+ if ($v_header_list[$i]['status'] == 'ok') {
+ if (($v_result = $this->privWriteCentralFileHeader($v_header_list[$i])) != 1) {
+ fclose($v_zip_temp_fd);
+ $this->privCloseFd();
+ @unlink($v_zip_temp_name);
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Return
+ return $v_result;
+ }
+ $v_count++;
+ }
+
+ // ----- Transform the header to a 'usable' info
+ $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]);
+ }
+
+ // ----- Zip file comment
+ $v_comment = $v_central_dir['comment'];
+ if (isset($p_options[PCLZIP_OPT_COMMENT])) {
+ $v_comment = $p_options[PCLZIP_OPT_COMMENT];
+ }
+ if (isset($p_options[PCLZIP_OPT_ADD_COMMENT])) {
+ $v_comment = $v_comment . $p_options[PCLZIP_OPT_ADD_COMMENT];
+ }
+ if (isset($p_options[PCLZIP_OPT_PREPEND_COMMENT])) {
+ $v_comment = $p_options[PCLZIP_OPT_PREPEND_COMMENT] . $v_comment;
+ }
+
+ // ----- Calculate the size of the central header
+ $v_size = @ftell($this->zip_fd) - $v_offset;
+
+ // ----- Create the central dir footer
+ if (($v_result = $this->privWriteCentralHeader($v_count + $v_central_dir['entries'], $v_size, $v_offset, $v_comment)) != 1) {
+ // ----- Reset the file list
+ unset($v_header_list);
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Swap back the file descriptor
+ $v_swap = $this->zip_fd;
+ $this->zip_fd = $v_zip_temp_fd;
+ $v_zip_temp_fd = $v_swap;
+
+ // ----- Close
+ $this->privCloseFd();
+
+ // ----- Close the temporary file
+ @fclose($v_zip_temp_fd);
+
+ // ----- Magic quotes trick
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Delete the zip file
+ // TBC : I should test the result ...
+ @unlink($this->zipname);
+
+ // ----- Rename the temporary file
+ // TBC : I should test the result ...
+ //@rename($v_zip_temp_name, $this->zipname);
+ PclZipUtilRename($v_zip_temp_name, $this->zipname);
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privOpenFd()
+ // Description :
+ // Parameters :
+ // --------------------------------------------------------------------------------
+ public function privOpenFd($p_mode)
+ {
+ $v_result = 1;
+
+ // ----- Look if already open
+ if ($this->zip_fd != 0) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Zip file \'' . $this->zipname . '\' already open');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Open the zip file
+ if (($this->zip_fd = @fopen($this->zipname, $p_mode)) == 0) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \'' . $this->zipname . '\' in ' . $p_mode . ' mode');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privCloseFd()
+ // Description :
+ // Parameters :
+ // --------------------------------------------------------------------------------
+ public function privCloseFd()
+ {
+ $v_result = 1;
+
+ if ($this->zip_fd != 0) {
+ @fclose($this->zip_fd);
+ }
+ $this->zip_fd = 0;
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privAddList()
+ // Description :
+ // $p_add_dir and $p_remove_dir will give the ability to memorize a path which is
+ // different from the real path of the file. This is usefull if you want to have PclTar
+ // running in any directory, and memorize relative path from an other directory.
+ // Parameters :
+ // $p_list : An array containing the file or directory names to add in the tar
+ // $p_result_list : list of added files with their properties (specially the status field)
+ // $p_add_dir : Path to add in the filename path archived
+ // $p_remove_dir : Path to remove in the filename path archived
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ // function privAddList($p_list, &$p_result_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, &$p_options)
+ public function privAddList($p_filedescr_list, &$p_result_list, &$p_options)
+ {
+ $v_result = 1;
+
+ // ----- Add the files
+ $v_header_list = array();
+ if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1) {
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Store the offset of the central dir
+ $v_offset = @ftell($this->zip_fd);
+
+ // ----- Create the Central Dir files header
+ for ($i = 0, $v_count = 0; $i < sizeof($v_header_list); $i++) {
+ // ----- Create the file header
+ if ($v_header_list[$i]['status'] == 'ok') {
+ if (($v_result = $this->privWriteCentralFileHeader($v_header_list[$i])) != 1) {
+ // ----- Return
+ return $v_result;
+ }
+ $v_count++;
+ }
+
+ // ----- Transform the header to a 'usable' info
+ $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]);
+ }
+
+ // ----- Zip file comment
+ $v_comment = '';
+ if (isset($p_options[PCLZIP_OPT_COMMENT])) {
+ $v_comment = $p_options[PCLZIP_OPT_COMMENT];
+ }
+
+ // ----- Calculate the size of the central header
+ $v_size = @ftell($this->zip_fd) - $v_offset;
+
+ // ----- Create the central dir footer
+ if (($v_result = $this->privWriteCentralHeader($v_count, $v_size, $v_offset, $v_comment)) != 1) {
+ // ----- Reset the file list
+ unset($v_header_list);
+
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privAddFileList()
+ // Description :
+ // Parameters :
+ // $p_filedescr_list : An array containing the file description
+ // or directory names to add in the zip
+ // $p_result_list : list of added files with their properties (specially the status field)
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ public function privAddFileList($p_filedescr_list, &$p_result_list, &$p_options)
+ {
+ $v_result = 1;
+ $v_header = array();
+
+ // ----- Recuperate the current number of elt in list
+ $v_nb = sizeof($p_result_list);
+
+ // ----- Loop on the files
+ for ($j = 0; ($j < sizeof($p_filedescr_list)) && ($v_result == 1); $j++) {
+ // ----- Format the filename
+ $p_filedescr_list[$j]['filename'] = PclZipUtilTranslateWinPath($p_filedescr_list[$j]['filename'], false);
+
+ // ----- Skip empty file names
+ // TBC : Can this be possible ? not checked in DescrParseAtt ?
+ if ($p_filedescr_list[$j]['filename'] == "") {
+ continue;
+ }
+
+ // ----- Check the filename
+ if (($p_filedescr_list[$j]['type'] != 'virtual_file') && (!file_exists($p_filedescr_list[$j]['filename']))) {
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "File '" . $p_filedescr_list[$j]['filename'] . "' does not exist");
+
+ return PclZip::errorCode();
+ }
+
+ // ----- Look if it is a file or a dir with no all path remove option
+ // or a dir with all its path removed
+ // if ( (is_file($p_filedescr_list[$j]['filename']))
+ // || ( is_dir($p_filedescr_list[$j]['filename'])
+ if (($p_filedescr_list[$j]['type'] == 'file') || ($p_filedescr_list[$j]['type'] == 'virtual_file') || (($p_filedescr_list[$j]['type'] == 'folder') && (!isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH]) || !$p_options[PCLZIP_OPT_REMOVE_ALL_PATH]))) {
+
+ // ----- Add the file
+ $v_result = $this->privAddFile($p_filedescr_list[$j], $v_header, $p_options);
+ if ($v_result != 1) {
+ return $v_result;
+ }
+
+ // ----- Store the file infos
+ $p_result_list[$v_nb++] = $v_header;
+ }
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privAddFile()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ public function privAddFile($p_filedescr, &$p_header, &$p_options)
+ {
+ $v_result = 1;
+
+ // ----- Working variable
+ $p_filename = $p_filedescr['filename'];
+
+ // TBC : Already done in the fileAtt check ... ?
+ if ($p_filename == "") {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file list parameter (invalid or empty list)");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Look for a stored different filename
+ /* TBC : Removed
+ if (isset($p_filedescr['stored_filename'])) {
+ $v_stored_filename = $p_filedescr['stored_filename'];
+ } else {
+ $v_stored_filename = $p_filedescr['stored_filename'];
+ }
+ */
+
+ // ----- Set the file properties
+ clearstatcache();
+ $p_header['version'] = 20;
+ $p_header['version_extracted'] = 10;
+ $p_header['flag'] = 0;
+ $p_header['compression'] = 0;
+ $p_header['crc'] = 0;
+ $p_header['compressed_size'] = 0;
+ $p_header['filename_len'] = strlen($p_filename);
+ $p_header['extra_len'] = 0;
+ $p_header['disk'] = 0;
+ $p_header['internal'] = 0;
+ $p_header['offset'] = 0;
+ $p_header['filename'] = $p_filename;
+ // TBC : Removed $p_header['stored_filename'] = $v_stored_filename;
+ $p_header['stored_filename'] = $p_filedescr['stored_filename'];
+ $p_header['extra'] = '';
+ $p_header['status'] = 'ok';
+ $p_header['index'] = -1;
+
+ // ----- Look for regular file
+ if ($p_filedescr['type'] == 'file') {
+ $p_header['external'] = 0x00000000;
+ $p_header['size'] = filesize($p_filename);
+
+ // ----- Look for regular folder
+ } elseif ($p_filedescr['type'] == 'folder') {
+ $p_header['external'] = 0x00000010;
+ $p_header['mtime'] = filemtime($p_filename);
+ $p_header['size'] = filesize($p_filename);
+
+ // ----- Look for virtual file
+ } elseif ($p_filedescr['type'] == 'virtual_file') {
+ $p_header['external'] = 0x00000000;
+ $p_header['size'] = strlen($p_filedescr['content']);
+ }
+
+ // ----- Look for filetime
+ if (isset($p_filedescr['mtime'])) {
+ $p_header['mtime'] = $p_filedescr['mtime'];
+ } elseif ($p_filedescr['type'] == 'virtual_file') {
+ $p_header['mtime'] = time();
+ } else {
+ $p_header['mtime'] = filemtime($p_filename);
+ }
+
+ // ------ Look for file comment
+ if (isset($p_filedescr['comment'])) {
+ $p_header['comment_len'] = strlen($p_filedescr['comment']);
+ $p_header['comment'] = $p_filedescr['comment'];
+ } else {
+ $p_header['comment_len'] = 0;
+ $p_header['comment'] = '';
+ }
+
+ // ----- Look for pre-add callback
+ if (isset($p_options[PCLZIP_CB_PRE_ADD])) {
+
+ // ----- Generate a local information
+ $v_local_header = array();
+ $this->privConvertHeader2FileInfo($p_header, $v_local_header);
+
+ // ----- Call the callback
+ // Here I do not use call_user_func() because I need to send a reference to the
+ // header.
+ // eval('$v_result = '.$p_options[PCLZIP_CB_PRE_ADD].'(PCLZIP_CB_PRE_ADD, $v_local_header);');
+ $v_result = $p_options[PCLZIP_CB_PRE_ADD](PCLZIP_CB_PRE_ADD, $v_local_header);
+ if ($v_result == 0) {
+ // ----- Change the file status
+ $p_header['status'] = "skipped";
+ $v_result = 1;
+ }
+
+ // ----- Update the informations
+ // Only some fields can be modified
+ if ($p_header['stored_filename'] != $v_local_header['stored_filename']) {
+ $p_header['stored_filename'] = PclZipUtilPathReduction($v_local_header['stored_filename']);
+ }
+ }
+
+ // ----- Look for empty stored filename
+ if ($p_header['stored_filename'] == "") {
+ $p_header['status'] = "filtered";
+ }
+
+ // ----- Check the path length
+ if (strlen($p_header['stored_filename']) > 0xFF) {
+ $p_header['status'] = 'filename_too_long';
+ }
+
+ // ----- Look if no error, or file not skipped
+ if ($p_header['status'] == 'ok') {
+
+ // ----- Look for a file
+ if ($p_filedescr['type'] == 'file') {
+ // ----- Look for using temporary file to zip
+ if ((!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON]) || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_header['size'])))) {
+ $v_result = $this->privAddFileUsingTempFile($p_filedescr, $p_header, $p_options);
+ if ($v_result < PCLZIP_ERR_NO_ERROR) {
+ return $v_result;
+ }
+
+ // ----- Use "in memory" zip algo
+ } else {
+
+ // ----- Open the source file
+ if (($v_file = @fopen($p_filename, "rb")) == 0) {
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode");
+
+ return PclZip::errorCode();
+ }
+
+ // ----- Read the file content
+ $v_content = @fread($v_file, $p_header['size']);
+
+ // ----- Close the file
+ @fclose($v_file);
+
+ // ----- Calculate the CRC
+ $p_header['crc'] = @crc32($v_content);
+
+ // ----- Look for no compression
+ if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) {
+ // ----- Set header parameters
+ $p_header['compressed_size'] = $p_header['size'];
+ $p_header['compression'] = 0;
+
+ // ----- Look for normal compression
+ } else {
+ // ----- Compress the content
+ $v_content = @gzdeflate($v_content);
+
+ // ----- Set header parameters
+ $p_header['compressed_size'] = strlen($v_content);
+ $p_header['compression'] = 8;
+ }
+
+ // ----- Call the header generation
+ if (($v_result = $this->privWriteFileHeader($p_header)) != 1) {
+ @fclose($v_file);
+
+ return $v_result;
+ }
+
+ // ----- Write the compressed (or not) content
+ @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']);
+
+ }
+
+ // ----- Look for a virtual file (a file from string)
+ } elseif ($p_filedescr['type'] == 'virtual_file') {
+
+ $v_content = $p_filedescr['content'];
+
+ // ----- Calculate the CRC
+ $p_header['crc'] = @crc32($v_content);
+
+ // ----- Look for no compression
+ if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) {
+ // ----- Set header parameters
+ $p_header['compressed_size'] = $p_header['size'];
+ $p_header['compression'] = 0;
+
+ // ----- Look for normal compression
+ } else {
+ // ----- Compress the content
+ $v_content = @gzdeflate($v_content);
+
+ // ----- Set header parameters
+ $p_header['compressed_size'] = strlen($v_content);
+ $p_header['compression'] = 8;
+ }
+
+ // ----- Call the header generation
+ if (($v_result = $this->privWriteFileHeader($p_header)) != 1) {
+ @fclose($v_file);
+
+ return $v_result;
+ }
+
+ // ----- Write the compressed (or not) content
+ @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']);
+
+ // ----- Look for a directory
+ } elseif ($p_filedescr['type'] == 'folder') {
+ // ----- Look for directory last '/'
+ if (@substr($p_header['stored_filename'], -1) != '/') {
+ $p_header['stored_filename'] .= '/';
+ }
+
+ // ----- Set the file properties
+ $p_header['size'] = 0;
+ //$p_header['external'] = 0x41FF0010; // Value for a folder : to be checked
+ $p_header['external'] = 0x00000010; // Value for a folder : to be checked
+
+ // ----- Call the header generation
+ if (($v_result = $this->privWriteFileHeader($p_header)) != 1) {
+ return $v_result;
+ }
+ }
+ }
+
+ // ----- Look for post-add callback
+ if (isset($p_options[PCLZIP_CB_POST_ADD])) {
+
+ // ----- Generate a local information
+ $v_local_header = array();
+ $this->privConvertHeader2FileInfo($p_header, $v_local_header);
+
+ // ----- Call the callback
+ // Here I do not use call_user_func() because I need to send a reference to the
+ // header.
+ // eval('$v_result = '.$p_options[PCLZIP_CB_POST_ADD].'(PCLZIP_CB_POST_ADD, $v_local_header);');
+ $v_result = $p_options[PCLZIP_CB_POST_ADD](PCLZIP_CB_POST_ADD, $v_local_header);
+ if ($v_result == 0) {
+ // ----- Ignored
+ $v_result = 1;
+ }
+
+ // ----- Update the informations
+ // Nothing can be modified
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privAddFileUsingTempFile()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ public function privAddFileUsingTempFile($p_filedescr, &$p_header, &$p_options)
+ {
+ $v_result = PCLZIP_ERR_NO_ERROR;
+
+ // ----- Working variable
+ $p_filename = $p_filedescr['filename'];
+
+ // ----- Open the source file
+ if (($v_file = @fopen($p_filename, "rb")) == 0) {
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode");
+
+ return PclZip::errorCode();
+ }
+
+ // ----- Creates a compressed temporary file
+ $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR . $this->createUniqueName('pclzip-') . '.gz';
+ if (($v_file_compressed = @gzopen($v_gzip_temp_name, "wb")) == 0) {
+ fclose($v_file);
+ PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \'' . $v_gzip_temp_name . '\' in binary write mode');
+
+ return PclZip::errorCode();
+ }
+
+ // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
+ $v_size = filesize($p_filename);
+ while ($v_size != 0) {
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = @fread($v_file, $v_read_size);
+ //$v_binary_data = pack('a'.$v_read_size, $v_buffer);
+ @gzputs($v_file_compressed, $v_buffer, $v_read_size);
+ $v_size -= $v_read_size;
+ }
+
+ // ----- Close the file
+ @fclose($v_file);
+ @gzclose($v_file_compressed);
+
+ // ----- Check the minimum file size
+ if (filesize($v_gzip_temp_name) < 18) {
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'gzip temporary file \'' . $v_gzip_temp_name . '\' has invalid filesize - should be minimum 18 bytes');
+
+ return PclZip::errorCode();
+ }
+
+ // ----- Extract the compressed attributes
+ if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0) {
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \'' . $v_gzip_temp_name . '\' in binary read mode');
+
+ return PclZip::errorCode();
+ }
+
+ // ----- Read the gzip file header
+ $v_binary_data = @fread($v_file_compressed, 10);
+ $v_data_header = unpack('a1id1/a1id2/a1cm/a1flag/Vmtime/a1xfl/a1os', $v_binary_data);
+
+ // ----- Check some parameters
+ $v_data_header['os'] = bin2hex($v_data_header['os']);
+
+ // ----- Read the gzip file footer
+ @fseek($v_file_compressed, filesize($v_gzip_temp_name) - 8);
+ $v_binary_data = @fread($v_file_compressed, 8);
+ $v_data_footer = unpack('Vcrc/Vcompressed_size', $v_binary_data);
+
+ // ----- Set the attributes
+ $p_header['compression'] = ord($v_data_header['cm']);
+ //$p_header['mtime'] = $v_data_header['mtime'];
+ $p_header['crc'] = $v_data_footer['crc'];
+ $p_header['compressed_size'] = filesize($v_gzip_temp_name) - 18;
+
+ // ----- Close the file
+ @fclose($v_file_compressed);
+
+ // ----- Call the header generation
+ if (($v_result = $this->privWriteFileHeader($p_header)) != 1) {
+ return $v_result;
+ }
+
+ // ----- Add the compressed data
+ if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0) {
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \'' . $v_gzip_temp_name . '\' in binary read mode');
+
+ return PclZip::errorCode();
+ }
+
+ // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
+ fseek($v_file_compressed, 10);
+ $v_size = $p_header['compressed_size'];
+ while ($v_size != 0) {
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = @fread($v_file_compressed, $v_read_size);
+ //$v_binary_data = pack('a'.$v_read_size, $v_buffer);
+ @fwrite($this->zip_fd, $v_buffer, $v_read_size);
+ $v_size -= $v_read_size;
+ }
+
+ // ----- Close the file
+ @fclose($v_file_compressed);
+
+ // ----- Unlink the temporary file
+ @unlink($v_gzip_temp_name);
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privCalculateStoredFilename()
+ // Description :
+ // Based on file descriptor properties and global options, this method
+ // calculate the filename that will be stored in the archive.
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ public function privCalculateStoredFilename(&$p_filedescr, &$p_options)
+ {
+ $v_result = 1;
+
+ // ----- Working variables
+ $p_filename = $p_filedescr['filename'];
+ if (isset($p_options[PCLZIP_OPT_ADD_PATH])) {
+ $p_add_dir = $p_options[PCLZIP_OPT_ADD_PATH];
+ } else {
+ $p_add_dir = '';
+ }
+ if (isset($p_options[PCLZIP_OPT_REMOVE_PATH])) {
+ $p_remove_dir = $p_options[PCLZIP_OPT_REMOVE_PATH];
+ } else {
+ $p_remove_dir = '';
+ }
+ if (isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH])) {
+ $p_remove_all_dir = $p_options[PCLZIP_OPT_REMOVE_ALL_PATH];
+ } else {
+ $p_remove_all_dir = 0;
+ }
+
+ // ----- Look for full name change
+ if (isset($p_filedescr['new_full_name'])) {
+ // ----- Remove drive letter if any
+ $v_stored_filename = PclZipUtilTranslateWinPath($p_filedescr['new_full_name']);
+
+ // ----- Look for path and/or short name change
+ } else {
+
+ // ----- Look for short name change
+ // Its when we cahnge just the filename but not the path
+ if (isset($p_filedescr['new_short_name'])) {
+ $v_path_info = pathinfo($p_filename);
+ $v_dir = '';
+ if ($v_path_info['dirname'] != '') {
+ $v_dir = $v_path_info['dirname'] . '/';
+ }
+ $v_stored_filename = $v_dir . $p_filedescr['new_short_name'];
+ } else {
+ // ----- Calculate the stored filename
+ $v_stored_filename = $p_filename;
+ }
+
+ // ----- Look for all path to remove
+ if ($p_remove_all_dir) {
+ $v_stored_filename = basename($p_filename);
+
+ // ----- Look for partial path remove
+ } elseif ($p_remove_dir != "") {
+ if (substr($p_remove_dir, -1) != '/') {
+ $p_remove_dir .= "/";
+ }
+
+ if ((substr($p_filename, 0, 2) == "./") || (substr($p_remove_dir, 0, 2) == "./")) {
+
+ if ((substr($p_filename, 0, 2) == "./") && (substr($p_remove_dir, 0, 2) != "./")) {
+ $p_remove_dir = "./" . $p_remove_dir;
+ }
+ if ((substr($p_filename, 0, 2) != "./") && (substr($p_remove_dir, 0, 2) == "./")) {
+ $p_remove_dir = substr($p_remove_dir, 2);
+ }
+ }
+
+ $v_compare = PclZipUtilPathInclusion($p_remove_dir, $v_stored_filename);
+ if ($v_compare > 0) {
+ if ($v_compare == 2) {
+ $v_stored_filename = "";
+ } else {
+ $v_stored_filename = substr($v_stored_filename, strlen($p_remove_dir));
+ }
+ }
+ }
+
+ // ----- Remove drive letter if any
+ $v_stored_filename = PclZipUtilTranslateWinPath($v_stored_filename);
+
+ // ----- Look for path to add
+ if ($p_add_dir != "") {
+ if (substr($p_add_dir, -1) == "/") {
+ $v_stored_filename = $p_add_dir . $v_stored_filename;
+ } else {
+ $v_stored_filename = $p_add_dir . "/" . $v_stored_filename;
+ }
+ }
+ }
+
+ // ----- Filename (reduce the path of stored name)
+ $v_stored_filename = PclZipUtilPathReduction($v_stored_filename);
+ $p_filedescr['stored_filename'] = $v_stored_filename;
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privWriteFileHeader()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ public function privWriteFileHeader(&$p_header)
+ {
+ $v_result = 1;
+
+ // ----- Store the offset position of the file
+ $p_header['offset'] = ftell($this->zip_fd);
+
+ // ----- Transform UNIX mtime to DOS format mdate/mtime
+ $v_date = getdate($p_header['mtime']);
+ $v_mtime = ($v_date['hours'] << 11) + ($v_date['minutes'] << 5) + $v_date['seconds'] / 2;
+ $v_mdate = (($v_date['year'] - 1980) << 9) + ($v_date['mon'] << 5) + $v_date['mday'];
+
+ // ----- Packed data
+ $v_binary_data = pack("VvvvvvVVVvv", 0x04034b50, $p_header['version_extracted'], $p_header['flag'], $p_header['compression'], $v_mtime, $v_mdate, $p_header['crc'], $p_header['compressed_size'], $p_header['size'], strlen($p_header['stored_filename']), $p_header['extra_len']);
+
+ // ----- Write the first 148 bytes of the header in the archive
+ fputs($this->zip_fd, $v_binary_data, 30);
+
+ // ----- Write the variable fields
+ if (strlen($p_header['stored_filename']) != 0) {
+ fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename']));
+ }
+ if ($p_header['extra_len'] != 0) {
+ fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']);
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privWriteCentralFileHeader()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ public function privWriteCentralFileHeader(&$p_header)
+ {
+ $v_result = 1;
+
+ // TBC
+ //for (reset($p_header); $key = key($p_header); next($p_header)) {
+ //}
+
+ // ----- Transform UNIX mtime to DOS format mdate/mtime
+ $v_date = getdate($p_header['mtime']);
+ $v_mtime = ($v_date['hours'] << 11) + ($v_date['minutes'] << 5) + $v_date['seconds'] / 2;
+ $v_mdate = (($v_date['year'] - 1980) << 9) + ($v_date['mon'] << 5) + $v_date['mday'];
+
+ // ----- Packed data
+ $v_binary_data = pack("VvvvvvvVVVvvvvvVV", 0x02014b50, $p_header['version'], $p_header['version_extracted'], $p_header['flag'], $p_header['compression'], $v_mtime, $v_mdate, $p_header['crc'], $p_header['compressed_size'], $p_header['size'], strlen($p_header['stored_filename']), $p_header['extra_len'], $p_header['comment_len'], $p_header['disk'], $p_header['internal'], $p_header['external'], $p_header['offset']);
+
+ // ----- Write the 42 bytes of the header in the zip file
+ fputs($this->zip_fd, $v_binary_data, 46);
+
+ // ----- Write the variable fields
+ if (strlen($p_header['stored_filename']) != 0) {
+ fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename']));
+ }
+ if ($p_header['extra_len'] != 0) {
+ fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']);
+ }
+ if ($p_header['comment_len'] != 0) {
+ fputs($this->zip_fd, $p_header['comment'], $p_header['comment_len']);
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privWriteCentralHeader()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ public function privWriteCentralHeader($p_nb_entries, $p_size, $p_offset, $p_comment)
+ {
+ $v_result = 1;
+
+ // ----- Packed data
+ $v_binary_data = pack("VvvvvVVv", 0x06054b50, 0, 0, $p_nb_entries, $p_nb_entries, $p_size, $p_offset, strlen($p_comment));
+
+ // ----- Write the 22 bytes of the header in the zip file
+ fputs($this->zip_fd, $v_binary_data, 22);
+
+ // ----- Write the variable fields
+ if (strlen($p_comment) != 0) {
+ fputs($this->zip_fd, $p_comment, strlen($p_comment));
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privList()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ public function privList(&$p_list)
+ {
+ $v_result = 1;
+
+ // ----- Magic quotes trick
+ $this->privDisableMagicQuotes();
+
+ // ----- Open the zip file
+ if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0) {
+ // ----- Magic quotes trick
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \'' . $this->zipname . '\' in binary read mode');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Read the central directory informations
+ $v_central_dir = array();
+ if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) {
+ $this->privSwapBackMagicQuotes();
+
+ return $v_result;
+ }
+
+ // ----- Go to beginning of Central Dir
+ @rewind($this->zip_fd);
+ if (@fseek($this->zip_fd, $v_central_dir['offset'])) {
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Read each entry
+ for ($i = 0; $i < $v_central_dir['entries']; $i++) {
+ // ----- Read the file header
+ if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1) {
+ $this->privSwapBackMagicQuotes();
+
+ return $v_result;
+ }
+ $v_header['index'] = $i;
+
+ // ----- Get the only interesting attributes
+ $this->privConvertHeader2FileInfo($v_header, $p_list[$i]);
+ unset($v_header);
+ }
+
+ // ----- Close the zip file
+ $this->privCloseFd();
+
+ // ----- Magic quotes trick
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privConvertHeader2FileInfo()
+ // Description :
+ // This function takes the file informations from the central directory
+ // entries and extract the interesting parameters that will be given back.
+ // The resulting file infos are set in the array $p_info
+ // $p_info['filename'] : Filename with full path. Given by user (add),
+ // extracted in the filesystem (extract).
+ // $p_info['stored_filename'] : Stored filename in the archive.
+ // $p_info['size'] = Size of the file.
+ // $p_info['compressed_size'] = Compressed size of the file.
+ // $p_info['mtime'] = Last modification date of the file.
+ // $p_info['comment'] = Comment associated with the file.
+ // $p_info['folder'] = true/false : indicates if the entry is a folder or not.
+ // $p_info['status'] = status of the action on the file.
+ // $p_info['crc'] = CRC of the file content.
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ public function privConvertHeader2FileInfo($p_header, &$p_info)
+ {
+ $v_result = 1;
+
+ // ----- Get the interesting attributes
+ $v_temp_path = PclZipUtilPathReduction($p_header['filename']);
+ $p_info['filename'] = $v_temp_path;
+ $v_temp_path = PclZipUtilPathReduction($p_header['stored_filename']);
+ $p_info['stored_filename'] = $v_temp_path;
+ $p_info['size'] = $p_header['size'];
+ $p_info['compressed_size'] = $p_header['compressed_size'];
+ $p_info['mtime'] = $p_header['mtime'];
+ $p_info['comment'] = $p_header['comment'];
+ $p_info['folder'] = (($p_header['external'] & 0x00000010) == 0x00000010);
+ $p_info['index'] = $p_header['index'];
+ $p_info['status'] = $p_header['status'];
+ $p_info['crc'] = $p_header['crc'];
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privExtractByRule()
+ // Description :
+ // Extract a file or directory depending of rules (by index, by name, ...)
+ // Parameters :
+ // $p_file_list : An array where will be placed the properties of each
+ // extracted file
+ // $p_path : Path to add while writing the extracted files
+ // $p_remove_path : Path to remove (from the file memorized path) while writing the
+ // extracted files. If the path does not match the file path,
+ // the file is extracted with its memorized path.
+ // $p_remove_path does not apply to 'list' mode.
+ // $p_path and $p_remove_path are commulative.
+ // Return Values :
+ // 1 on success,0 or less on error (see error code list)
+ // --------------------------------------------------------------------------------
+ public function privExtractByRule(&$p_file_list, $p_path, $p_remove_path, $p_remove_all_path, &$p_options)
+ {
+ $v_result = 1;
+
+ // ----- Magic quotes trick
+ $this->privDisableMagicQuotes();
+
+ // ----- Check the path
+ if (($p_path == "") || ((substr($p_path, 0, 1) != "/") && (substr($p_path, 0, 3) != "../") && (substr($p_path, 1, 2) != ":/"))) {
+ $p_path = "./" . $p_path;
+ }
+
+ // ----- Reduce the path last (and duplicated) '/'
+ if (($p_path != "./") && ($p_path != "/")) {
+ // ----- Look for the path end '/'
+ while (substr($p_path, -1) == "/") {
+ $p_path = substr($p_path, 0, strlen($p_path) - 1);
+ }
+ }
+
+ // ----- Look for path to remove format (should end by /)
+ if (($p_remove_path != "") && (substr($p_remove_path, -1) != '/')) {
+ $p_remove_path .= '/';
+ }
+ $p_remove_path_size = strlen($p_remove_path);
+
+ // ----- Open the zip file
+ if (($v_result = $this->privOpenFd('rb')) != 1) {
+ $this->privSwapBackMagicQuotes();
+
+ return $v_result;
+ }
+
+ // ----- Read the central directory informations
+ $v_central_dir = array();
+ if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) {
+ // ----- Close the zip file
+ $this->privCloseFd();
+ $this->privSwapBackMagicQuotes();
+
+ return $v_result;
+ }
+
+ // ----- Start at beginning of Central Dir
+ $v_pos_entry = $v_central_dir['offset'];
+
+ // ----- Read each entry
+ $j_start = 0;
+ for ($i = 0, $v_nb_extracted = 0; $i < $v_central_dir['entries']; $i++) {
+
+ // ----- Read next Central dir entry
+ @rewind($this->zip_fd);
+ if (@fseek($this->zip_fd, $v_pos_entry)) {
+ // ----- Close the zip file
+ $this->privCloseFd();
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Read the file header
+ $v_header = array();
+ if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1) {
+ // ----- Close the zip file
+ $this->privCloseFd();
+ $this->privSwapBackMagicQuotes();
+
+ return $v_result;
+ }
+
+ // ----- Store the index
+ $v_header['index'] = $i;
+
+ // ----- Store the file position
+ $v_pos_entry = ftell($this->zip_fd);
+
+ // ----- Look for the specific extract rules
+ $v_extract = false;
+
+ // ----- Look for extract by name rule
+ if ((isset($p_options[PCLZIP_OPT_BY_NAME])) && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) {
+
+ // ----- Look if the filename is in the list
+ for ($j = 0; ($j < sizeof($p_options[PCLZIP_OPT_BY_NAME])) && (!$v_extract); $j++) {
+
+ // ----- Look for a directory
+ if (substr($p_options[PCLZIP_OPT_BY_NAME][$j], -1) == "/") {
+
+ // ----- Look if the directory is in the filename path
+ if ((strlen($v_header['stored_filename']) > strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) && (substr($v_header['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) {
+ $v_extract = true;
+ }
+
+ // ----- Look for a filename
+ } elseif ($v_header['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) {
+ $v_extract = true;
+ }
+ }
+ // ----- Look for extract by ereg rule
+ // ereg() is deprecated with PHP 5.3
+ /*
+ elseif ( (isset($p_options[PCLZIP_OPT_BY_EREG]))
+ && ($p_options[PCLZIP_OPT_BY_EREG] != "")) {
+
+ if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header['stored_filename'])) {
+ $v_extract = true;
+ }
+ }
+ */
+
+ // ----- Look for extract by preg rule
+ } elseif ((isset($p_options[PCLZIP_OPT_BY_PREG])) && ($p_options[PCLZIP_OPT_BY_PREG] != "")) {
+
+ if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header['stored_filename'])) {
+ $v_extract = true;
+ }
+
+ // ----- Look for extract by index rule
+ } elseif ((isset($p_options[PCLZIP_OPT_BY_INDEX])) && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) {
+
+ // ----- Look if the index is in the list
+ for ($j = $j_start; ($j < sizeof($p_options[PCLZIP_OPT_BY_INDEX])) && (!$v_extract); $j++) {
+
+ if (($i >= $p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i <= $p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) {
+ $v_extract = true;
+ }
+ if ($i >= $p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) {
+ $j_start = $j + 1;
+ }
+
+ if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start'] > $i) {
+ break;
+ }
+ }
+
+ // ----- Look for no rule, which means extract all the archive
+ } else {
+ $v_extract = true;
+ }
+
+ // ----- Check compression method
+ if (($v_extract) && (($v_header['compression'] != 8) && ($v_header['compression'] != 0))) {
+ $v_header['status'] = 'unsupported_compression';
+
+ // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
+ if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)) {
+
+ $this->privSwapBackMagicQuotes();
+
+ PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_COMPRESSION, "Filename '" . $v_header['stored_filename'] . "' is " . "compressed by an unsupported compression " . "method (" . $v_header['compression'] . ") ");
+
+ return PclZip::errorCode();
+ }
+ }
+
+ // ----- Check encrypted files
+ if (($v_extract) && (($v_header['flag'] & 1) == 1)) {
+ $v_header['status'] = 'unsupported_encryption';
+
+ // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
+ if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)) {
+
+ $this->privSwapBackMagicQuotes();
+
+ PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, "Unsupported encryption for " . " filename '" . $v_header['stored_filename'] . "'");
+
+ return PclZip::errorCode();
+ }
+ }
+
+ // ----- Look for real extraction
+ if (($v_extract) && ($v_header['status'] != 'ok')) {
+ $v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++]);
+ if ($v_result != 1) {
+ $this->privCloseFd();
+ $this->privSwapBackMagicQuotes();
+
+ return $v_result;
+ }
+
+ $v_extract = false;
+ }
+
+ // ----- Look for real extraction
+ if ($v_extract) {
+
+ // ----- Go to the file position
+ @rewind($this->zip_fd);
+ if (@fseek($this->zip_fd, $v_header['offset'])) {
+ // ----- Close the zip file
+ $this->privCloseFd();
+
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Look for extraction as string
+ if ($p_options[PCLZIP_OPT_EXTRACT_AS_STRING]) {
+
+ $v_string = '';
+
+ // ----- Extracting the file
+ $v_result1 = $this->privExtractFileAsString($v_header, $v_string, $p_options);
+ if ($v_result1 < 1) {
+ $this->privCloseFd();
+ $this->privSwapBackMagicQuotes();
+
+ return $v_result1;
+ }
+
+ // ----- Get the only interesting attributes
+ if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted])) != 1) {
+ // ----- Close the zip file
+ $this->privCloseFd();
+ $this->privSwapBackMagicQuotes();
+
+ return $v_result;
+ }
+
+ // ----- Set the file content
+ $p_file_list[$v_nb_extracted]['content'] = $v_string;
+
+ // ----- Next extracted file
+ $v_nb_extracted++;
+
+ // ----- Look for user callback abort
+ if ($v_result1 == 2) {
+ break;
+ }
+
+ // ----- Look for extraction in standard output
+ } elseif ((isset($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])) && ($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])) {
+ // ----- Extracting the file in standard output
+ $v_result1 = $this->privExtractFileInOutput($v_header, $p_options);
+ if ($v_result1 < 1) {
+ $this->privCloseFd();
+ $this->privSwapBackMagicQuotes();
+
+ return $v_result1;
+ }
+
+ // ----- Get the only interesting attributes
+ if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) {
+ $this->privCloseFd();
+ $this->privSwapBackMagicQuotes();
+
+ return $v_result;
+ }
+
+ // ----- Look for user callback abort
+ if ($v_result1 == 2) {
+ break;
+ }
+
+ // ----- Look for normal extraction
+ } else {
+ // ----- Extracting the file
+ $v_result1 = $this->privExtractFile($v_header, $p_path, $p_remove_path, $p_remove_all_path, $p_options);
+ if ($v_result1 < 1) {
+ $this->privCloseFd();
+ $this->privSwapBackMagicQuotes();
+
+ return $v_result1;
+ }
+
+ // ----- Get the only interesting attributes
+ if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) {
+ // ----- Close the zip file
+ $this->privCloseFd();
+ $this->privSwapBackMagicQuotes();
+
+ return $v_result;
+ }
+
+ // ----- Look for user callback abort
+ if ($v_result1 == 2) {
+ break;
+ }
+ }
+ }
+ }
+
+ // ----- Close the zip file
+ $this->privCloseFd();
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privExtractFile()
+ // Description :
+ // Parameters :
+ // Return Values :
+ //
+ // 1 : ... ?
+ // PCLZIP_ERR_USER_ABORTED(2) : User ask for extraction stop in callback
+ // --------------------------------------------------------------------------------
+ public function privExtractFile(&$p_entry, $p_path, $p_remove_path, $p_remove_all_path, &$p_options)
+ {
+ $v_result = 1;
+
+ // ----- Read the file header
+ if (($v_result = $this->privReadFileHeader($v_header)) != 1) {
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Check that the file header is coherent with $p_entry info
+ if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) {
+ // TBC
+ }
+
+ // ----- Look for all path to remove
+ if ($p_remove_all_path == true) {
+ // ----- Look for folder entry that not need to be extracted
+ if (($p_entry['external'] & 0x00000010) == 0x00000010) {
+
+ $p_entry['status'] = "filtered";
+
+ return $v_result;
+ }
+
+ // ----- Get the basename of the path
+ $p_entry['filename'] = basename($p_entry['filename']);
+
+ // ----- Look for path to remove
+ } elseif ($p_remove_path != "") {
+ if (PclZipUtilPathInclusion($p_remove_path, $p_entry['filename']) == 2) {
+
+ // ----- Change the file status
+ $p_entry['status'] = "filtered";
+
+ // ----- Return
+ return $v_result;
+ }
+
+ $p_remove_path_size = strlen($p_remove_path);
+ if (substr($p_entry['filename'], 0, $p_remove_path_size) == $p_remove_path) {
+
+ // ----- Remove the path
+ $p_entry['filename'] = substr($p_entry['filename'], $p_remove_path_size);
+
+ }
+ }
+
+ // Patch for Zip Traversal vulnerability
+ if (strpos($p_entry['stored_filename'], '../') !== false || strpos($p_entry['stored_filename'], '..\\') !== false) {
+ $p_entry['stored_filename'] = basename($p_entry['stored_filename']);
+ $p_entry['filename'] = basename($p_entry['stored_filename']);
+ }
+
+ // ----- Add the path
+ if ($p_path != '') {
+ $p_entry['filename'] = $p_path . "/" . $p_entry['filename'];
+ }
+
+ // ----- Check a base_dir_restriction
+ if (isset($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION])) {
+ $v_inclusion = PclZipUtilPathInclusion($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION], $p_entry['filename']);
+ if ($v_inclusion == 0) {
+
+ PclZip::privErrorLog(PCLZIP_ERR_DIRECTORY_RESTRICTION, "Filename '" . $p_entry['filename'] . "' is " . "outside PCLZIP_OPT_EXTRACT_DIR_RESTRICTION");
+
+ return PclZip::errorCode();
+ }
+ }
+
+ // ----- Look for pre-extract callback
+ if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) {
+
+ // ----- Generate a local information
+ $v_local_header = array();
+ $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
+
+ // ----- Call the callback
+ // Here I do not use call_user_func() because I need to send a reference to the
+ // header.
+ // eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);');
+ $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header);
+ if ($v_result == 0) {
+ // ----- Change the file status
+ $p_entry['status'] = "skipped";
+ $v_result = 1;
+ }
+
+ // ----- Look for abort result
+ if ($v_result == 2) {
+ // ----- This status is internal and will be changed in 'skipped'
+ $p_entry['status'] = "aborted";
+ $v_result = PCLZIP_ERR_USER_ABORTED;
+ }
+
+ // ----- Update the informations
+ // Only some fields can be modified
+ $p_entry['filename'] = $v_local_header['filename'];
+ }
+
+ // ----- Look if extraction should be done
+ if ($p_entry['status'] == 'ok') {
+
+ // ----- Look for specific actions while the file exist
+ if (file_exists($p_entry['filename'])) {
+
+ // ----- Look if file is a directory
+ if (is_dir($p_entry['filename'])) {
+
+ // ----- Change the file status
+ $p_entry['status'] = "already_a_directory";
+
+ // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
+ // For historical reason first PclZip implementation does not stop
+ // when this kind of error occurs.
+ if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)) {
+
+ PclZip::privErrorLog(PCLZIP_ERR_ALREADY_A_DIRECTORY, "Filename '" . $p_entry['filename'] . "' is " . "already used by an existing directory");
+
+ return PclZip::errorCode();
+ }
+
+ // ----- Look if file is write protected
+ } elseif (!is_writeable($p_entry['filename'])) {
+
+ // ----- Change the file status
+ $p_entry['status'] = "write_protected";
+
+ // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
+ // For historical reason first PclZip implementation does not stop
+ // when this kind of error occurs.
+ if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)) {
+
+ PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, "Filename '" . $p_entry['filename'] . "' exists " . "and is write protected");
+
+ return PclZip::errorCode();
+ }
+
+ // ----- Look if the extracted file is older
+ } elseif (filemtime($p_entry['filename']) > $p_entry['mtime']) {
+ // ----- Change the file status
+ if ((isset($p_options[PCLZIP_OPT_REPLACE_NEWER])) && ($p_options[PCLZIP_OPT_REPLACE_NEWER] === true)) {
+ } else {
+ $p_entry['status'] = "newer_exist";
+
+ // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
+ // For historical reason first PclZip implementation does not stop
+ // when this kind of error occurs.
+ if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)) {
+
+ PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, "Newer version of '" . $p_entry['filename'] . "' exists " . "and option PCLZIP_OPT_REPLACE_NEWER is not selected");
+
+ return PclZip::errorCode();
+ }
+ }
+ } else {
+ }
+
+ // ----- Check the directory availability and create it if necessary
+ } else {
+ if ((($p_entry['external'] & 0x00000010) == 0x00000010) || (substr($p_entry['filename'], -1) == '/')) {
+ $v_dir_to_check = $p_entry['filename'];
+ } elseif (!strstr($p_entry['filename'], "/")) {
+ $v_dir_to_check = "";
+ } else {
+ $v_dir_to_check = dirname($p_entry['filename']);
+ }
+
+ if (($v_result = $this->privDirCheck($v_dir_to_check, (($p_entry['external'] & 0x00000010) == 0x00000010))) != 1) {
+
+ // ----- Change the file status
+ $p_entry['status'] = "path_creation_fail";
+
+ // ----- Return
+ //return $v_result;
+ $v_result = 1;
+ }
+ }
+ }
+
+ // ----- Look if extraction should be done
+ if ($p_entry['status'] == 'ok') {
+
+ // ----- Do the extraction (if not a folder)
+ if (!(($p_entry['external'] & 0x00000010) == 0x00000010)) {
+ // ----- Look for not compressed file
+ if ($p_entry['compression'] == 0) {
+
+ // ----- Opening destination file
+ if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) {
+
+ // ----- Change the file status
+ $p_entry['status'] = "write_error";
+
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
+ $v_size = $p_entry['compressed_size'];
+ while ($v_size != 0) {
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = @fread($this->zip_fd, $v_read_size);
+ /* Try to speed up the code
+ $v_binary_data = pack('a'.$v_read_size, $v_buffer);
+ @fwrite($v_dest_file, $v_binary_data, $v_read_size);
+ */
+ @fwrite($v_dest_file, $v_buffer, $v_read_size);
+ $v_size -= $v_read_size;
+ }
+
+ // ----- Closing the destination file
+ fclose($v_dest_file);
+
+ // ----- Change the file mtime
+ touch($p_entry['filename'], $p_entry['mtime']);
+
+ } else {
+ // ----- TBC
+ // Need to be finished
+ if (($p_entry['flag'] & 1) == 1) {
+ PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, 'File \'' . $p_entry['filename'] . '\' is encrypted. Encrypted files are not supported.');
+
+ return PclZip::errorCode();
+ }
+
+ // ----- Look for using temporary file to unzip
+ if ((!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON]) || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_entry['size'])))) {
+ $v_result = $this->privExtractFileUsingTempFile($p_entry, $p_options);
+ if ($v_result < PCLZIP_ERR_NO_ERROR) {
+ return $v_result;
+ }
+
+ // ----- Look for extract in memory
+ } else {
+
+ // ----- Read the compressed file in a buffer (one shot)
+ $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']);
+
+ // ----- Decompress the file
+ $v_file_content = @gzinflate($v_buffer);
+ unset($v_buffer);
+ if ($v_file_content === false) {
+
+ // ----- Change the file status
+ // TBC
+ $p_entry['status'] = "error";
+
+ return $v_result;
+ }
+
+ // ----- Opening destination file
+ if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) {
+
+ // ----- Change the file status
+ $p_entry['status'] = "write_error";
+
+ return $v_result;
+ }
+
+ // ----- Write the uncompressed data
+ @fwrite($v_dest_file, $v_file_content, $p_entry['size']);
+ unset($v_file_content);
+
+ // ----- Closing the destination file
+ @fclose($v_dest_file);
+
+ }
+
+ // ----- Change the file mtime
+ @touch($p_entry['filename'], $p_entry['mtime']);
+ }
+
+ // ----- Look for chmod option
+ if (isset($p_options[PCLZIP_OPT_SET_CHMOD])) {
+
+ // ----- Change the mode of the file
+ @chmod($p_entry['filename'], $p_options[PCLZIP_OPT_SET_CHMOD]);
+ }
+
+ }
+ }
+
+ // ----- Change abort status
+ if ($p_entry['status'] == "aborted") {
+ $p_entry['status'] = "skipped";
+
+ // ----- Look for post-extract callback
+ } elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) {
+
+ // ----- Generate a local information
+ $v_local_header = array();
+ $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
+
+ // ----- Call the callback
+ // Here I do not use call_user_func() because I need to send a reference to the
+ // header.
+ // eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);');
+ $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header);
+
+ // ----- Look for abort result
+ if ($v_result == 2) {
+ $v_result = PCLZIP_ERR_USER_ABORTED;
+ }
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privExtractFileUsingTempFile()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ public function privExtractFileUsingTempFile(&$p_entry, &$p_options)
+ {
+ $v_result = 1;
+
+ // ----- Creates a temporary file
+ $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR . $this->createUniqueName('pclzip-') . '.gz';
+ if (($v_dest_file = @fopen($v_gzip_temp_name, "wb")) == 0) {
+ fclose($v_file);
+ PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \'' . $v_gzip_temp_name . '\' in binary write mode');
+
+ return PclZip::errorCode();
+ }
+
+ // ----- Write gz file format header
+ $v_binary_data = pack('va1a1Va1a1', 0x8b1f, Chr($p_entry['compression']), Chr(0x00), time(), Chr(0x00), Chr(3));
+ @fwrite($v_dest_file, $v_binary_data, 10);
+
+ // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
+ $v_size = $p_entry['compressed_size'];
+ while ($v_size != 0) {
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = @fread($this->zip_fd, $v_read_size);
+ //$v_binary_data = pack('a'.$v_read_size, $v_buffer);
+ @fwrite($v_dest_file, $v_buffer, $v_read_size);
+ $v_size -= $v_read_size;
+ }
+
+ // ----- Write gz file format footer
+ $v_binary_data = pack('VV', $p_entry['crc'], $p_entry['size']);
+ @fwrite($v_dest_file, $v_binary_data, 8);
+
+ // ----- Close the temporary file
+ @fclose($v_dest_file);
+
+ // ----- Opening destination file
+ if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) {
+ $p_entry['status'] = "write_error";
+
+ return $v_result;
+ }
+
+ // ----- Open the temporary gz file
+ if (($v_src_file = @gzopen($v_gzip_temp_name, 'rb')) == 0) {
+ @fclose($v_dest_file);
+ $p_entry['status'] = "read_error";
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \'' . $v_gzip_temp_name . '\' in binary read mode');
+
+ return PclZip::errorCode();
+ }
+
+ // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
+ $v_size = $p_entry['size'];
+ while ($v_size != 0) {
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = @gzread($v_src_file, $v_read_size);
+ //$v_binary_data = pack('a'.$v_read_size, $v_buffer);
+ @fwrite($v_dest_file, $v_buffer, $v_read_size);
+ $v_size -= $v_read_size;
+ }
+ @fclose($v_dest_file);
+ @gzclose($v_src_file);
+
+ // ----- Delete the temporary file
+ @unlink($v_gzip_temp_name);
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privExtractFileInOutput()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ public function privExtractFileInOutput(&$p_entry, &$p_options)
+ {
+ $v_result = 1;
+
+ // ----- Read the file header
+ if (($v_result = $this->privReadFileHeader($v_header)) != 1) {
+ return $v_result;
+ }
+
+ // ----- Check that the file header is coherent with $p_entry info
+ if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) {
+ // TBC
+ }
+
+ // ----- Look for pre-extract callback
+ if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) {
+
+ // ----- Generate a local information
+ $v_local_header = array();
+ $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
+
+ // ----- Call the callback
+ // Here I do not use call_user_func() because I need to send a reference to the
+ // header.
+ // eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);');
+ $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header);
+ if ($v_result == 0) {
+ // ----- Change the file status
+ $p_entry['status'] = "skipped";
+ $v_result = 1;
+ }
+
+ // ----- Look for abort result
+ if ($v_result == 2) {
+ // ----- This status is internal and will be changed in 'skipped'
+ $p_entry['status'] = "aborted";
+ $v_result = PCLZIP_ERR_USER_ABORTED;
+ }
+
+ // ----- Update the informations
+ // Only some fields can be modified
+ $p_entry['filename'] = $v_local_header['filename'];
+ }
+
+ // ----- Trace
+
+ // ----- Look if extraction should be done
+ if ($p_entry['status'] == 'ok') {
+
+ // ----- Do the extraction (if not a folder)
+ if (!(($p_entry['external'] & 0x00000010) == 0x00000010)) {
+ // ----- Look for not compressed file
+ if ($p_entry['compressed_size'] == $p_entry['size']) {
+
+ // ----- Read the file in a buffer (one shot)
+ $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']);
+
+ // ----- Send the file to the output
+ echo $v_buffer;
+ unset($v_buffer);
+ } else {
+
+ // ----- Read the compressed file in a buffer (one shot)
+ $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']);
+
+ // ----- Decompress the file
+ $v_file_content = gzinflate($v_buffer);
+ unset($v_buffer);
+
+ // ----- Send the file to the output
+ echo $v_file_content;
+ unset($v_file_content);
+ }
+ }
+ }
+
+ // ----- Change abort status
+ if ($p_entry['status'] == "aborted") {
+ $p_entry['status'] = "skipped";
+
+ // ----- Look for post-extract callback
+ } elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) {
+
+ // ----- Generate a local information
+ $v_local_header = array();
+ $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
+
+ // ----- Call the callback
+ // Here I do not use call_user_func() because I need to send a reference to the
+ // header.
+ // eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);');
+ $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header);
+
+ // ----- Look for abort result
+ if ($v_result == 2) {
+ $v_result = PCLZIP_ERR_USER_ABORTED;
+ }
+ }
+
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privExtractFileAsString()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ public function privExtractFileAsString(&$p_entry, &$p_string, &$p_options)
+ {
+ $v_result = 1;
+
+ // ----- Read the file header
+ $v_header = array();
+ if (($v_result = $this->privReadFileHeader($v_header)) != 1) {
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Check that the file header is coherent with $p_entry info
+ if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) {
+ // TBC
+ }
+
+ // ----- Look for pre-extract callback
+ if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) {
+
+ // ----- Generate a local information
+ $v_local_header = array();
+ $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
+
+ // ----- Call the callback
+ // Here I do not use call_user_func() because I need to send a reference to the
+ // header.
+ // eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);');
+ $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header);
+ if ($v_result == 0) {
+ // ----- Change the file status
+ $p_entry['status'] = "skipped";
+ $v_result = 1;
+ }
+
+ // ----- Look for abort result
+ if ($v_result == 2) {
+ // ----- This status is internal and will be changed in 'skipped'
+ $p_entry['status'] = "aborted";
+ $v_result = PCLZIP_ERR_USER_ABORTED;
+ }
+
+ // ----- Update the informations
+ // Only some fields can be modified
+ $p_entry['filename'] = $v_local_header['filename'];
+ }
+
+ // ----- Look if extraction should be done
+ if ($p_entry['status'] == 'ok') {
+
+ // ----- Do the extraction (if not a folder)
+ if (!(($p_entry['external'] & 0x00000010) == 0x00000010)) {
+ // ----- Look for not compressed file
+ // if ($p_entry['compressed_size'] == $p_entry['size'])
+ if ($p_entry['compression'] == 0) {
+
+ // ----- Reading the file
+ $p_string = @fread($this->zip_fd, $p_entry['compressed_size']);
+ } else {
+
+ // ----- Reading the file
+ $v_data = @fread($this->zip_fd, $p_entry['compressed_size']);
+
+ // ----- Decompress the file
+ if (($p_string = @gzinflate($v_data)) === false) {
+ // TBC
+ }
+ }
+
+ // ----- Trace
+ } else {
+ // TBC : error : can not extract a folder in a string
+ }
+
+ }
+
+ // ----- Change abort status
+ if ($p_entry['status'] == "aborted") {
+ $p_entry['status'] = "skipped";
+
+ // ----- Look for post-extract callback
+ } elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) {
+
+ // ----- Generate a local information
+ $v_local_header = array();
+ $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
+
+ // ----- Swap the content to header
+ $v_local_header['content'] = $p_string;
+ $p_string = '';
+
+ // ----- Call the callback
+ // Here I do not use call_user_func() because I need to send a reference to the
+ // header.
+ // eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);');
+ $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header);
+
+ // ----- Swap back the content to header
+ $p_string = $v_local_header['content'];
+ unset($v_local_header['content']);
+
+ // ----- Look for abort result
+ if ($v_result == 2) {
+ $v_result = PCLZIP_ERR_USER_ABORTED;
+ }
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privReadFileHeader()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ public function privReadFileHeader(&$p_header)
+ {
+ $v_result = 1;
+
+ // ----- Read the 4 bytes signature
+ $v_binary_data = @fread($this->zip_fd, 4);
+ $v_data = unpack('Vid', $v_binary_data);
+
+ // ----- Check signature
+ if ($v_data['id'] != 0x04034b50) {
+
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Read the first 42 bytes of the header
+ $v_binary_data = fread($this->zip_fd, 26);
+
+ // ----- Look for invalid block size
+ if (strlen($v_binary_data) != 26) {
+ $p_header['filename'] = "";
+ $p_header['status'] = "invalid_header";
+
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : " . strlen($v_binary_data));
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Extract the values
+ $v_data = unpack('vversion/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len', $v_binary_data);
+
+ // ----- Get filename
+ $p_header['filename'] = fread($this->zip_fd, $v_data['filename_len']);
+
+ // ----- Get extra_fields
+ if ($v_data['extra_len'] != 0) {
+ $p_header['extra'] = fread($this->zip_fd, $v_data['extra_len']);
+ } else {
+ $p_header['extra'] = '';
+ }
+
+ // ----- Extract properties
+ $p_header['version_extracted'] = $v_data['version'];
+ $p_header['compression'] = $v_data['compression'];
+ $p_header['size'] = $v_data['size'];
+ $p_header['compressed_size'] = $v_data['compressed_size'];
+ $p_header['crc'] = $v_data['crc'];
+ $p_header['flag'] = $v_data['flag'];
+ $p_header['filename_len'] = $v_data['filename_len'];
+
+ // ----- Recuperate date in UNIX format
+ $p_header['mdate'] = $v_data['mdate'];
+ $p_header['mtime'] = $v_data['mtime'];
+ if ($p_header['mdate'] && $p_header['mtime']) {
+ // ----- Extract time
+ $v_hour = ($p_header['mtime'] & 0xF800) >> 11;
+ $v_minute = ($p_header['mtime'] & 0x07E0) >> 5;
+ $v_seconde = ($p_header['mtime'] & 0x001F) * 2;
+
+ // ----- Extract date
+ $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980;
+ $v_month = ($p_header['mdate'] & 0x01E0) >> 5;
+ $v_day = $p_header['mdate'] & 0x001F;
+
+ // ----- Get UNIX date format
+ $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year);
+
+ } else {
+ $p_header['mtime'] = time();
+ }
+
+ // TBC
+ //for (reset($v_data); $key = key($v_data); next($v_data)) {
+ //}
+
+ // ----- Set the stored filename
+ $p_header['stored_filename'] = $p_header['filename'];
+
+ // ----- Set the status field
+ $p_header['status'] = "ok";
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privReadCentralFileHeader()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ public function privReadCentralFileHeader(&$p_header)
+ {
+ $v_result = 1;
+
+ // ----- Read the 4 bytes signature
+ $v_binary_data = @fread($this->zip_fd, 4);
+ $v_data = unpack('Vid', $v_binary_data);
+
+ // ----- Check signature
+ if ($v_data['id'] != 0x02014b50) {
+
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Read the first 42 bytes of the header
+ $v_binary_data = fread($this->zip_fd, 42);
+
+ // ----- Look for invalid block size
+ if (strlen($v_binary_data) != 42) {
+ $p_header['filename'] = "";
+ $p_header['status'] = "invalid_header";
+
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : " . strlen($v_binary_data));
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Extract the values
+ $p_header = unpack('vversion/vversion_extracted/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len/vcomment_len/vdisk/vinternal/Vexternal/Voffset', $v_binary_data);
+
+ // ----- Get filename
+ if ($p_header['filename_len'] != 0) {
+ $p_header['filename'] = fread($this->zip_fd, $p_header['filename_len']);
+ } else {
+ $p_header['filename'] = '';
+ }
+
+ // ----- Get extra
+ if ($p_header['extra_len'] != 0) {
+ $p_header['extra'] = fread($this->zip_fd, $p_header['extra_len']);
+ } else {
+ $p_header['extra'] = '';
+ }
+
+ // ----- Get comment
+ if ($p_header['comment_len'] != 0) {
+ $p_header['comment'] = fread($this->zip_fd, $p_header['comment_len']);
+ } else {
+ $p_header['comment'] = '';
+ }
+
+ // ----- Extract properties
+
+ // ----- Recuperate date in UNIX format
+ //if ($p_header['mdate'] && $p_header['mtime'])
+ // TBC : bug : this was ignoring time with 0/0/0
+ if (1) {
+ // ----- Extract time
+ $v_hour = ($p_header['mtime'] & 0xF800) >> 11;
+ $v_minute = ($p_header['mtime'] & 0x07E0) >> 5;
+ $v_seconde = ($p_header['mtime'] & 0x001F) * 2;
+
+ // ----- Extract date
+ $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980;
+ $v_month = ($p_header['mdate'] & 0x01E0) >> 5;
+ $v_day = $p_header['mdate'] & 0x001F;
+
+ // ----- Get UNIX date format
+ $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year);
+
+ } else {
+ $p_header['mtime'] = time();
+ }
+
+ // ----- Set the stored filename
+ $p_header['stored_filename'] = $p_header['filename'];
+
+ // ----- Set default status to ok
+ $p_header['status'] = 'ok';
+
+ // ----- Look if it is a directory
+ if (substr($p_header['filename'], -1) == '/') {
+ //$p_header['external'] = 0x41FF0010;
+ $p_header['external'] = 0x00000010;
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privCheckFileHeaders()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // 1 on success,
+ // 0 on error;
+ // --------------------------------------------------------------------------------
+ public function privCheckFileHeaders(&$p_local_header, &$p_central_header)
+ {
+ $v_result = 1;
+
+ // ----- Check the static values
+ // TBC
+ if ($p_local_header['filename'] != $p_central_header['filename']) {
+ }
+ if ($p_local_header['version_extracted'] != $p_central_header['version_extracted']) {
+ }
+ if ($p_local_header['flag'] != $p_central_header['flag']) {
+ }
+ if ($p_local_header['compression'] != $p_central_header['compression']) {
+ }
+ if ($p_local_header['mtime'] != $p_central_header['mtime']) {
+ }
+ if ($p_local_header['filename_len'] != $p_central_header['filename_len']) {
+ }
+
+ // ----- Look for flag bit 3
+ if (($p_local_header['flag'] & 8) == 8) {
+ $p_local_header['size'] = $p_central_header['size'];
+ $p_local_header['compressed_size'] = $p_central_header['compressed_size'];
+ $p_local_header['crc'] = $p_central_header['crc'];
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privReadEndCentralDir()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ public function privReadEndCentralDir(&$p_central_dir)
+ {
+ $v_result = 1;
+
+ // ----- Go to the end of the zip file
+ $v_size = filesize($this->zipname);
+ @fseek($this->zip_fd, $v_size);
+ if (@ftell($this->zip_fd) != $v_size) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to go to the end of the archive \'' . $this->zipname . '\'');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- First try : look if this is an archive with no commentaries (most of the time)
+ // in this case the end of central dir is at 22 bytes of the file end
+ $v_found = 0;
+ if ($v_size > 26) {
+ @fseek($this->zip_fd, $v_size - 22);
+ if (($v_pos = @ftell($this->zip_fd)) != ($v_size - 22)) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \'' . $this->zipname . '\'');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Read for bytes
+ $v_binary_data = @fread($this->zip_fd, 4);
+ $v_data = @unpack('Vid', $v_binary_data);
+
+ // ----- Check signature
+ if ($v_data['id'] == 0x06054b50) {
+ $v_found = 1;
+ }
+
+ $v_pos = ftell($this->zip_fd);
+ }
+
+ // ----- Go back to the maximum possible size of the Central Dir End Record
+ if (!$v_found) {
+ $v_maximum_size = 65557; // 0xFFFF + 22;
+ if ($v_maximum_size > $v_size) {
+ $v_maximum_size = $v_size;
+ }
+ @fseek($this->zip_fd, $v_size - $v_maximum_size);
+ if (@ftell($this->zip_fd) != ($v_size - $v_maximum_size)) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \'' . $this->zipname . '\'');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Read byte per byte in order to find the signature
+ $v_pos = ftell($this->zip_fd);
+ $v_bytes = 0x00000000;
+ while ($v_pos < $v_size) {
+ // ----- Read a byte
+ $v_byte = @fread($this->zip_fd, 1);
+
+ // ----- Add the byte
+ //$v_bytes = ($v_bytes << 8) | Ord($v_byte);
+ // Note we mask the old value down such that once shifted we can never end up with more than a 32bit number
+ // Otherwise on systems where we have 64bit integers the check below for the magic number will fail.
+ $v_bytes = (($v_bytes & 0xFFFFFF) << 8) | Ord($v_byte);
+
+ // ----- Compare the bytes
+ if ($v_bytes == 0x504b0506) {
+ $v_pos++;
+ break;
+ }
+
+ $v_pos++;
+ }
+
+ // ----- Look if not found end of central dir
+ if ($v_pos == $v_size) {
+
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Unable to find End of Central Dir Record signature");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+ }
+
+ // ----- Read the first 18 bytes of the header
+ $v_binary_data = fread($this->zip_fd, 18);
+
+ // ----- Look for invalid block size
+ if (strlen($v_binary_data) != 18) {
+
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid End of Central Dir Record size : " . strlen($v_binary_data));
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Extract the values
+ $v_data = unpack('vdisk/vdisk_start/vdisk_entries/ventries/Vsize/Voffset/vcomment_size', $v_binary_data);
+
+ // ----- Check the global size
+ if (($v_pos + $v_data['comment_size'] + 18) != $v_size) {
+
+ // ----- Removed in release 2.2 see readme file
+ // The check of the file size is a little too strict.
+ // Some bugs where found when a zip is encrypted/decrypted with 'crypt'.
+ // While decrypted, zip has training 0 bytes
+ if (0) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'The central dir is not at the end of the archive.' . ' Some trailing bytes exists after the archive.');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+ }
+
+ // ----- Get comment
+ if ($v_data['comment_size'] != 0) {
+ $p_central_dir['comment'] = fread($this->zip_fd, $v_data['comment_size']);
+ } else {
+ $p_central_dir['comment'] = '';
+ }
+
+ $p_central_dir['entries'] = $v_data['entries'];
+ $p_central_dir['disk_entries'] = $v_data['disk_entries'];
+ $p_central_dir['offset'] = $v_data['offset'];
+ $p_central_dir['size'] = $v_data['size'];
+ $p_central_dir['disk'] = $v_data['disk'];
+ $p_central_dir['disk_start'] = $v_data['disk_start'];
+
+ // TBC
+ //for (reset($p_central_dir); $key = key($p_central_dir); next($p_central_dir)) {
+ //}
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privDeleteByRule()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ public function privDeleteByRule(&$p_result_list, &$p_options)
+ {
+ $v_result = 1;
+ $v_list_detail = array();
+
+ // ----- Open the zip file
+ if (($v_result = $this->privOpenFd('rb')) != 1) {
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Read the central directory informations
+ $v_central_dir = array();
+ if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) {
+ $this->privCloseFd();
+
+ return $v_result;
+ }
+
+ // ----- Go to beginning of File
+ @rewind($this->zip_fd);
+
+ // ----- Scan all the files
+ // ----- Start at beginning of Central Dir
+ $v_pos_entry = $v_central_dir['offset'];
+ @rewind($this->zip_fd);
+ if (@fseek($this->zip_fd, $v_pos_entry)) {
+ // ----- Close the zip file
+ $this->privCloseFd();
+
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Read each entry
+ $v_header_list = array();
+ $j_start = 0;
+ for ($i = 0, $v_nb_extracted = 0; $i < $v_central_dir['entries']; $i++) {
+
+ // ----- Read the file header
+ $v_header_list[$v_nb_extracted] = array();
+ if (($v_result = $this->privReadCentralFileHeader($v_header_list[$v_nb_extracted])) != 1) {
+ // ----- Close the zip file
+ $this->privCloseFd();
+
+ return $v_result;
+ }
+
+ // ----- Store the index
+ $v_header_list[$v_nb_extracted]['index'] = $i;
+
+ // ----- Look for the specific extract rules
+ $v_found = false;
+
+ // ----- Look for extract by name rule
+ if ((isset($p_options[PCLZIP_OPT_BY_NAME])) && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) {
+
+ // ----- Look if the filename is in the list
+ for ($j = 0; ($j < sizeof($p_options[PCLZIP_OPT_BY_NAME])) && (!$v_found); $j++) {
+
+ // ----- Look for a directory
+ if (substr($p_options[PCLZIP_OPT_BY_NAME][$j], -1) == "/") {
+
+ // ----- Look if the directory is in the filename path
+ if ((strlen($v_header_list[$v_nb_extracted]['stored_filename']) > strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) && (substr($v_header_list[$v_nb_extracted]['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) {
+ $v_found = true;
+ } elseif ((($v_header_list[$v_nb_extracted]['external'] & 0x00000010) == 0x00000010) /* Indicates a folder */ && ($v_header_list[$v_nb_extracted]['stored_filename'] . '/' == $p_options[PCLZIP_OPT_BY_NAME][$j])) {
+ $v_found = true;
+ }
+
+ // ----- Look for a filename
+ } elseif ($v_header_list[$v_nb_extracted]['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) {
+ $v_found = true;
+ }
+ }
+
+ // ----- Look for extract by ereg rule
+ // ereg() is deprecated with PHP 5.3
+ /*
+ elseif ( (isset($p_options[PCLZIP_OPT_BY_EREG]))
+ && ($p_options[PCLZIP_OPT_BY_EREG] != "")) {
+
+ if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header_list[$v_nb_extracted]['stored_filename'])) {
+ $v_found = true;
+ }
+ }
+ */
+
+ // ----- Look for extract by preg rule
+ } elseif ((isset($p_options[PCLZIP_OPT_BY_PREG])) && ($p_options[PCLZIP_OPT_BY_PREG] != "")) {
+
+ if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header_list[$v_nb_extracted]['stored_filename'])) {
+ $v_found = true;
+ }
+
+ // ----- Look for extract by index rule
+ } elseif ((isset($p_options[PCLZIP_OPT_BY_INDEX])) && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) {
+
+ // ----- Look if the index is in the list
+ for ($j = $j_start; ($j < sizeof($p_options[PCLZIP_OPT_BY_INDEX])) && (!$v_found); $j++) {
+
+ if (($i >= $p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i <= $p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) {
+ $v_found = true;
+ }
+ if ($i >= $p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) {
+ $j_start = $j + 1;
+ }
+
+ if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start'] > $i) {
+ break;
+ }
+ }
+ } else {
+ $v_found = true;
+ }
+
+ // ----- Look for deletion
+ if ($v_found) {
+ unset($v_header_list[$v_nb_extracted]);
+ } else {
+ $v_nb_extracted++;
+ }
+ }
+
+ // ----- Look if something need to be deleted
+ if ($v_nb_extracted > 0) {
+
+ // ----- Creates a temporary file
+ $v_zip_temp_name = PCLZIP_TEMPORARY_DIR . $this->createUniqueName('pclzip-') . '.tmp';
+
+ // ----- Creates a temporary zip archive
+ $v_temp_zip = new PclZip($v_zip_temp_name);
+
+ // ----- Open the temporary zip file in write mode
+ if (($v_result = $v_temp_zip->privOpenFd('wb')) != 1) {
+ $this->privCloseFd();
+
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Look which file need to be kept
+ for ($i = 0; $i < sizeof($v_header_list); $i++) {
+
+ // ----- Calculate the position of the header
+ @rewind($this->zip_fd);
+ if (@fseek($this->zip_fd, $v_header_list[$i]['offset'])) {
+ // ----- Close the zip file
+ $this->privCloseFd();
+ $v_temp_zip->privCloseFd();
+ @unlink($v_zip_temp_name);
+
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Read the file header
+ $v_local_header = array();
+ if (($v_result = $this->privReadFileHeader($v_local_header)) != 1) {
+ // ----- Close the zip file
+ $this->privCloseFd();
+ $v_temp_zip->privCloseFd();
+ @unlink($v_zip_temp_name);
+
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Check that local file header is same as central file header
+ if ($this->privCheckFileHeaders($v_local_header, $v_header_list[$i]) != 1) {
+ // TBC
+ }
+ unset($v_local_header);
+
+ // ----- Write the file header
+ if (($v_result = $v_temp_zip->privWriteFileHeader($v_header_list[$i])) != 1) {
+ // ----- Close the zip file
+ $this->privCloseFd();
+ $v_temp_zip->privCloseFd();
+ @unlink($v_zip_temp_name);
+
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Read/write the data block
+ if (($v_result = PclZipUtilCopyBlock($this->zip_fd, $v_temp_zip->zip_fd, $v_header_list[$i]['compressed_size'])) != 1) {
+ // ----- Close the zip file
+ $this->privCloseFd();
+ $v_temp_zip->privCloseFd();
+ @unlink($v_zip_temp_name);
+
+ // ----- Return
+ return $v_result;
+ }
+ }
+
+ // ----- Store the offset of the central dir
+ $v_offset = @ftell($v_temp_zip->zip_fd);
+
+ // ----- Re-Create the Central Dir files header
+ for ($i = 0; $i < sizeof($v_header_list); $i++) {
+ // ----- Create the file header
+ if (($v_result = $v_temp_zip->privWriteCentralFileHeader($v_header_list[$i])) != 1) {
+ $v_temp_zip->privCloseFd();
+ $this->privCloseFd();
+ @unlink($v_zip_temp_name);
+
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Transform the header to a 'usable' info
+ $v_temp_zip->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]);
+ }
+
+ // ----- Zip file comment
+ $v_comment = '';
+ if (isset($p_options[PCLZIP_OPT_COMMENT])) {
+ $v_comment = $p_options[PCLZIP_OPT_COMMENT];
+ }
+
+ // ----- Calculate the size of the central header
+ $v_size = @ftell($v_temp_zip->zip_fd) - $v_offset;
+
+ // ----- Create the central dir footer
+ if (($v_result = $v_temp_zip->privWriteCentralHeader(sizeof($v_header_list), $v_size, $v_offset, $v_comment)) != 1) {
+ // ----- Reset the file list
+ unset($v_header_list);
+ $v_temp_zip->privCloseFd();
+ $this->privCloseFd();
+ @unlink($v_zip_temp_name);
+
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Close
+ $v_temp_zip->privCloseFd();
+ $this->privCloseFd();
+
+ // ----- Delete the zip file
+ // TBC : I should test the result ...
+ @unlink($this->zipname);
+
+ // ----- Rename the temporary file
+ // TBC : I should test the result ...
+ //@rename($v_zip_temp_name, $this->zipname);
+ PclZipUtilRename($v_zip_temp_name, $this->zipname);
+
+ // ----- Destroy the temporary archive
+ unset($v_temp_zip);
+
+ // ----- Remove every files : reset the file
+ } elseif ($v_central_dir['entries'] != 0) {
+ $this->privCloseFd();
+
+ if (($v_result = $this->privOpenFd('wb')) != 1) {
+ return $v_result;
+ }
+
+ if (($v_result = $this->privWriteCentralHeader(0, 0, 0, '')) != 1) {
+ return $v_result;
+ }
+
+ $this->privCloseFd();
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privDirCheck()
+ // Description :
+ // Check if a directory exists, if not it creates it and all the parents directory
+ // which may be useful.
+ // Parameters :
+ // $p_dir : Directory path to check.
+ // Return Values :
+ // 1 : OK
+ // -1 : Unable to create directory
+ // --------------------------------------------------------------------------------
+ public function privDirCheck($p_dir, $p_is_dir = false)
+ {
+ $v_result = 1;
+
+ // ----- Remove the final '/'
+ if (($p_is_dir) && (substr($p_dir, -1) == '/')) {
+ $p_dir = substr($p_dir, 0, strlen($p_dir) - 1);
+ }
+
+ // ----- Check the directory availability
+ if ((is_dir($p_dir)) || ($p_dir == "")) {
+ return 1;
+ }
+
+ // ----- Extract parent directory
+ $p_parent_dir = dirname($p_dir);
+
+ // ----- Just a check
+ if ($p_parent_dir != $p_dir) {
+ // ----- Look for parent directory
+ if ($p_parent_dir != "") {
+ if (($v_result = $this->privDirCheck($p_parent_dir)) != 1) {
+ return $v_result;
+ }
+ }
+ }
+
+ // ----- Create the directory
+ if (!@mkdir($p_dir, 0777)) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_DIR_CREATE_FAIL, "Unable to create directory '$p_dir'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privMerge()
+ // Description :
+ // If $p_archive_to_add does not exist, the function exit with a success result.
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ public function privMerge(&$p_archive_to_add)
+ {
+ $v_result = 1;
+
+ // ----- Look if the archive_to_add exists
+ if (!is_file($p_archive_to_add->zipname)) {
+
+ // ----- Nothing to merge, so merge is a success
+ $v_result = 1;
+
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Look if the archive exists
+ if (!is_file($this->zipname)) {
+
+ // ----- Do a duplicate
+ $v_result = $this->privDuplicate($p_archive_to_add->zipname);
+
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Open the zip file
+ if (($v_result = $this->privOpenFd('rb')) != 1) {
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Read the central directory informations
+ $v_central_dir = array();
+ if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) {
+ $this->privCloseFd();
+
+ return $v_result;
+ }
+
+ // ----- Go to beginning of File
+ @rewind($this->zip_fd);
+
+ // ----- Open the archive_to_add file
+ if (($v_result = $p_archive_to_add->privOpenFd('rb')) != 1) {
+ $this->privCloseFd();
+
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Read the central directory informations
+ $v_central_dir_to_add = array();
+ if (($v_result = $p_archive_to_add->privReadEndCentralDir($v_central_dir_to_add)) != 1) {
+ $this->privCloseFd();
+ $p_archive_to_add->privCloseFd();
+
+ return $v_result;
+ }
+
+ // ----- Go to beginning of File
+ @rewind($p_archive_to_add->zip_fd);
+
+ // ----- Creates a temporary file
+ $v_zip_temp_name = PCLZIP_TEMPORARY_DIR . $this->createUniqueName('pclzip-') . '.tmp';
+
+ // ----- Open the temporary file in write mode
+ if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) {
+ $this->privCloseFd();
+ $p_archive_to_add->privCloseFd();
+
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \'' . $v_zip_temp_name . '\' in binary write mode');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Copy the files from the archive to the temporary file
+ // TBC : Here I should better append the file and go back to erase the central dir
+ $v_size = $v_central_dir['offset'];
+ while ($v_size != 0) {
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = fread($this->zip_fd, $v_read_size);
+ @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
+ $v_size -= $v_read_size;
+ }
+
+ // ----- Copy the files from the archive_to_add into the temporary file
+ $v_size = $v_central_dir_to_add['offset'];
+ while ($v_size != 0) {
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = fread($p_archive_to_add->zip_fd, $v_read_size);
+ @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
+ $v_size -= $v_read_size;
+ }
+
+ // ----- Store the offset of the central dir
+ $v_offset = @ftell($v_zip_temp_fd);
+
+ // ----- Copy the block of file headers from the old archive
+ $v_size = $v_central_dir['size'];
+ while ($v_size != 0) {
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = @fread($this->zip_fd, $v_read_size);
+ @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
+ $v_size -= $v_read_size;
+ }
+
+ // ----- Copy the block of file headers from the archive_to_add
+ $v_size = $v_central_dir_to_add['size'];
+ while ($v_size != 0) {
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = @fread($p_archive_to_add->zip_fd, $v_read_size);
+ @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
+ $v_size -= $v_read_size;
+ }
+
+ // ----- Merge the file comments
+ $v_comment = $v_central_dir['comment'] . ' ' . $v_central_dir_to_add['comment'];
+
+ // ----- Calculate the size of the (new) central header
+ $v_size = @ftell($v_zip_temp_fd) - $v_offset;
+
+ // ----- Swap the file descriptor
+ // Here is a trick : I swap the temporary fd with the zip fd, in order to use
+ // the following methods on the temporary fil and not the real archive fd
+ $v_swap = $this->zip_fd;
+ $this->zip_fd = $v_zip_temp_fd;
+ $v_zip_temp_fd = $v_swap;
+
+ // ----- Create the central dir footer
+ if (($v_result = $this->privWriteCentralHeader($v_central_dir['entries'] + $v_central_dir_to_add['entries'], $v_size, $v_offset, $v_comment)) != 1) {
+ $this->privCloseFd();
+ $p_archive_to_add->privCloseFd();
+ @fclose($v_zip_temp_fd);
+ $this->zip_fd = null;
+
+ // ----- Reset the file list
+ unset($v_header_list);
+
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Swap back the file descriptor
+ $v_swap = $this->zip_fd;
+ $this->zip_fd = $v_zip_temp_fd;
+ $v_zip_temp_fd = $v_swap;
+
+ // ----- Close
+ $this->privCloseFd();
+ $p_archive_to_add->privCloseFd();
+
+ // ----- Close the temporary file
+ @fclose($v_zip_temp_fd);
+
+ // ----- Delete the zip file
+ // TBC : I should test the result ...
+ @unlink($this->zipname);
+
+ // ----- Rename the temporary file
+ // TBC : I should test the result ...
+ //@rename($v_zip_temp_name, $this->zipname);
+ PclZipUtilRename($v_zip_temp_name, $this->zipname);
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privDuplicate()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ public function privDuplicate($p_archive_filename)
+ {
+ $v_result = 1;
+
+ // ----- Look if the $p_archive_filename exists
+ if (!is_file($p_archive_filename)) {
+
+ // ----- Nothing to duplicate, so duplicate is a success.
+ $v_result = 1;
+
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Open the zip file
+ if (($v_result = $this->privOpenFd('wb')) != 1) {
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Open the temporary file in write mode
+ if (($v_zip_temp_fd = @fopen($p_archive_filename, 'rb')) == 0) {
+ $this->privCloseFd();
+
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive file \'' . $p_archive_filename . '\' in binary write mode');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Copy the files from the archive to the temporary file
+ // TBC : Here I should better append the file and go back to erase the central dir
+ $v_size = filesize($p_archive_filename);
+ while ($v_size != 0) {
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = fread($v_zip_temp_fd, $v_read_size);
+ @fwrite($this->zip_fd, $v_buffer, $v_read_size);
+ $v_size -= $v_read_size;
+ }
+
+ // ----- Close
+ $this->privCloseFd();
+
+ // ----- Close the temporary file
+ @fclose($v_zip_temp_fd);
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privErrorLog()
+ // Description :
+ // Parameters :
+ // --------------------------------------------------------------------------------
+ public function privErrorLog($p_error_code = 0, $p_error_string = '')
+ {
+ if (PCLZIP_ERROR_EXTERNAL == 1) {
+ PclError($p_error_code, $p_error_string);
+ } else {
+ $this->error_code = $p_error_code;
+ $this->error_string = $p_error_string;
+ }
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privErrorReset()
+ // Description :
+ // Parameters :
+ // --------------------------------------------------------------------------------
+ public function privErrorReset()
+ {
+ if (PCLZIP_ERROR_EXTERNAL == 1) {
+ PclErrorReset();
+ } else {
+ $this->error_code = 0;
+ $this->error_string = '';
+ }
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privDisableMagicQuotes()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ public function privDisableMagicQuotes()
+ {
+ $v_result = 1;
+
+ // ----- Look if function exists
+ if ((!function_exists("get_magic_quotes_runtime")) || (!function_exists("set_magic_quotes_runtime"))) {
+ return $v_result;
+ }
+
+ // ----- Look if already done
+ if ($this->magic_quotes_status != -1) {
+ return $v_result;
+ }
+
+ // ----- Get and memorize the magic_quote value
+ $this->magic_quotes_status = @get_magic_quotes_runtime();
+
+ // ----- Disable magic_quotes
+ if ($this->magic_quotes_status == 1) {
+ @set_magic_quotes_runtime(0);
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privSwapBackMagicQuotes()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ public function privSwapBackMagicQuotes()
+ {
+ $v_result = 1;
+
+ // ----- Look if function exists
+ if ((!function_exists("get_magic_quotes_runtime")) || (!function_exists("set_magic_quotes_runtime"))) {
+ return $v_result;
+ }
+
+ // ----- Look if something to do
+ if ($this->magic_quotes_status != -1) {
+ return $v_result;
+ }
+
+ // ----- Swap back magic_quotes
+ if ($this->magic_quotes_status == 1) {
+ @set_magic_quotes_runtime($this->magic_quotes_status);
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : createUniqueName()
+ // Description : Create a unique(sh) name.
+ // Parameters : $prefix: prefix to use.
+ // Return Values : A unique name starting with $prefix.
+ // --------------------------------------------------------------------------------
+ private function createUniqueName($prefix)
+ {
+ $pseudo_pid = NULL;
+
+ // ----- Try to get our own pid, else a random number
+ if (!function_exists("getmypid")) {
+ $pseudo_pid = mt_rand(1, 99999);
+ }
+ else {
+ $pseudo_pid = getmypid();
+ if (!$pseudo_pid) {
+ $pseudo_pid = mt_rand(1, 99999);
+ }
+ }
+
+ // The reasoning behind this: uniqid() does not return a unique id, even
+ // with 'more_entropy' set to true, uniqid() actually returns a hex version
+ // of the current system time. Adding process id and a couple of random
+ // numbers makes the chance of collisions much smaller when running in
+ // parallel: 4 random numbers 'feels' enough. This does not yet guarantee
+ // 100% uniqueness, but the probability of getting a unique id is much
+ // higher than only using uniqid().
+ //
+ // Downside: the resulting names will be longer.
+
+ // ----- Slap on some random numbers and the pseudo pid
+ $v_result = uniqid($prefix, TRUE) .
+ sprintf('%04X%04X%04X%04X%d',
+ mt_rand(0, 65535), mt_rand(0, 65535),
+ mt_rand(0, 65535), mt_rand(0, 65535), $pseudo_pid);
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+}
+
+// End of class
+// --------------------------------------------------------------------------------
+
+// --------------------------------------------------------------------------------
+// Function : PclZipUtilPathReduction()
+// Description :
+// Parameters :
+// Return Values :
+// --------------------------------------------------------------------------------
+function PclZipUtilPathReduction($p_dir)
+{
+ $v_result = "";
+
+ // ----- Look for not empty path
+ if ($p_dir != "") {
+ // ----- Explode path by directory names
+ $v_list = explode("/", $p_dir);
+
+ // ----- Study directories from last to first
+ $v_skip = 0;
+ for ($i = sizeof($v_list) - 1; $i >= 0; $i--) {
+ // ----- Look for current path
+ if ($v_list[$i] == ".") {
+ // ----- Ignore this directory
+ // Should be the first $i=0, but no check is done
+ } elseif ($v_list[$i] == "..") {
+ $v_skip++;
+ } elseif ($v_list[$i] == "") {
+ // ----- First '/' i.e. root slash
+ if ($i == 0) {
+ $v_result = "/" . $v_result;
+ if ($v_skip > 0) {
+ // ----- It is an invalid path, so the path is not modified
+ // TBC
+ $v_result = $p_dir;
+ $v_skip = 0;
+ }
+
+ // ----- Last '/' i.e. indicates a directory
+ } elseif ($i == (sizeof($v_list) - 1)) {
+ $v_result = $v_list[$i];
+
+ // ----- Double '/' inside the path
+ } else {
+ // ----- Ignore only the double '//' in path,
+ // but not the first and last '/'
+ }
+ } else {
+ // ----- Look for item to skip
+ if ($v_skip > 0) {
+ $v_skip--;
+ } else {
+ $v_result = $v_list[$i] . ($i != (sizeof($v_list) - 1) ? "/" . $v_result : "");
+ }
+ }
+ }
+
+ // ----- Look for skip
+ if ($v_skip > 0) {
+ while ($v_skip > 0) {
+ $v_result = '../' . $v_result;
+ $v_skip--;
+ }
+ }
+ }
+
+ // ----- Return
+ return $v_result;
+}
+// --------------------------------------------------------------------------------
+
+// --------------------------------------------------------------------------------
+// Function : PclZipUtilPathInclusion()
+// Description :
+// This function indicates if the path $p_path is under the $p_dir tree. Or,
+// said in an other way, if the file or sub-dir $p_path is inside the dir
+// $p_dir.
+// The function indicates also if the path is exactly the same as the dir.
+// This function supports path with duplicated '/' like '//', but does not
+// support '.' or '..' statements.
+// Parameters :
+// Return Values :
+// 0 if $p_path is not inside directory $p_dir
+// 1 if $p_path is inside directory $p_dir
+// 2 if $p_path is exactly the same as $p_dir
+// --------------------------------------------------------------------------------
+function PclZipUtilPathInclusion($p_dir, $p_path)
+{
+ $v_result = 1;
+
+ // ----- Look for path beginning by ./
+ if (($p_dir == '.') || ((strlen($p_dir) >= 2) && (substr($p_dir, 0, 2) == './'))) {
+ $p_dir = PclZipUtilTranslateWinPath(getcwd(), false) . '/' . substr($p_dir, 1);
+ }
+ if (($p_path == '.') || ((strlen($p_path) >= 2) && (substr($p_path, 0, 2) == './'))) {
+ $p_path = PclZipUtilTranslateWinPath(getcwd(), false) . '/' . substr($p_path, 1);
+ }
+
+ // ----- Explode dir and path by directory separator
+ $v_list_dir = explode("/", $p_dir);
+ $v_list_dir_size = sizeof($v_list_dir);
+ $v_list_path = explode("/", $p_path);
+ $v_list_path_size = sizeof($v_list_path);
+
+ // ----- Study directories paths
+ $i = 0;
+ $j = 0;
+ while (($i < $v_list_dir_size) && ($j < $v_list_path_size) && ($v_result)) {
+
+ // ----- Look for empty dir (path reduction)
+ if ($v_list_dir[$i] == '') {
+ $i++;
+ continue;
+ }
+ if ($v_list_path[$j] == '') {
+ $j++;
+ continue;
+ }
+
+ // ----- Compare the items
+ if (($v_list_dir[$i] != $v_list_path[$j]) && ($v_list_dir[$i] != '') && ($v_list_path[$j] != '')) {
+ $v_result = 0;
+ }
+
+ // ----- Next items
+ $i++;
+ $j++;
+ }
+
+ // ----- Look if everything seems to be the same
+ if ($v_result) {
+ // ----- Skip all the empty items
+ while (($j < $v_list_path_size) && ($v_list_path[$j] == '')) {
+ $j++;
+ }
+ while (($i < $v_list_dir_size) && ($v_list_dir[$i] == '')) {
+ $i++;
+ }
+
+ if (($i >= $v_list_dir_size) && ($j >= $v_list_path_size)) {
+ // ----- There are exactly the same
+ $v_result = 2;
+ } elseif ($i < $v_list_dir_size) {
+ // ----- The path is shorter than the dir
+ $v_result = 0;
+ }
+ }
+
+ // ----- Return
+ return $v_result;
+}
+// --------------------------------------------------------------------------------
+
+// --------------------------------------------------------------------------------
+// Function : PclZipUtilCopyBlock()
+// Description :
+// Parameters :
+// $p_mode : read/write compression mode
+// 0 : src & dest normal
+// 1 : src gzip, dest normal
+// 2 : src normal, dest gzip
+// 3 : src & dest gzip
+// Return Values :
+// --------------------------------------------------------------------------------
+function PclZipUtilCopyBlock($p_src, $p_dest, $p_size, $p_mode = 0)
+{
+ $v_result = 1;
+
+ if ($p_mode == 0) {
+ while ($p_size != 0) {
+ $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = @fread($p_src, $v_read_size);
+ @fwrite($p_dest, $v_buffer, $v_read_size);
+ $p_size -= $v_read_size;
+ }
+ } elseif ($p_mode == 1) {
+ while ($p_size != 0) {
+ $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = @gzread($p_src, $v_read_size);
+ @fwrite($p_dest, $v_buffer, $v_read_size);
+ $p_size -= $v_read_size;
+ }
+ } elseif ($p_mode == 2) {
+ while ($p_size != 0) {
+ $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = @fread($p_src, $v_read_size);
+ @gzwrite($p_dest, $v_buffer, $v_read_size);
+ $p_size -= $v_read_size;
+ }
+ } elseif ($p_mode == 3) {
+ while ($p_size != 0) {
+ $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = @gzread($p_src, $v_read_size);
+ @gzwrite($p_dest, $v_buffer, $v_read_size);
+ $p_size -= $v_read_size;
+ }
+ }
+
+ // ----- Return
+ return $v_result;
+}
+// --------------------------------------------------------------------------------
+
+// --------------------------------------------------------------------------------
+// Function : PclZipUtilRename()
+// Description :
+// This function tries to do a simple rename() function. If it fails, it
+// tries to copy the $p_src file in a new $p_dest file and then unlink the
+// first one.
+// Parameters :
+// $p_src : Old filename
+// $p_dest : New filename
+// Return Values :
+// 1 on success, 0 on failure.
+// --------------------------------------------------------------------------------
+function PclZipUtilRename($p_src, $p_dest)
+{
+ $v_result = 1;
+
+ // ----- Try to rename the files
+ if (!@rename($p_src, $p_dest)) {
+
+ // ----- Try to copy & unlink the src
+ if (!@copy($p_src, $p_dest)) {
+ $v_result = 0;
+ } elseif (!@unlink($p_src)) {
+ $v_result = 0;
+ }
+ }
+
+ // ----- Return
+ return $v_result;
+}
+// --------------------------------------------------------------------------------
+
+// --------------------------------------------------------------------------------
+// Function : PclZipUtilOptionText()
+// Description :
+// Translate option value in text. Mainly for debug purpose.
+// Parameters :
+// $p_option : the option value.
+// Return Values :
+// The option text value.
+// --------------------------------------------------------------------------------
+function PclZipUtilOptionText($p_option)
+{
+
+ $v_list = get_defined_constants();
+ for (reset($v_list); $v_key = key($v_list); next($v_list)) {
+ $v_prefix = substr($v_key, 0, 10);
+ if ((($v_prefix == 'PCLZIP_OPT') || ($v_prefix == 'PCLZIP_CB_') || ($v_prefix == 'PCLZIP_ATT')) && ($v_list[$v_key] == $p_option)) {
+ return $v_key;
+ }
+ }
+
+ $v_result = 'Unknown';
+
+ return $v_result;
+}
+// --------------------------------------------------------------------------------
+
+// --------------------------------------------------------------------------------
+// Function : PclZipUtilTranslateWinPath()
+// Description :
+// Translate windows path by replacing '\' by '/' and optionally removing
+// drive letter.
+// Parameters :
+// $p_path : path to translate.
+// $p_remove_disk_letter : true | false
+// Return Values :
+// The path translated.
+// --------------------------------------------------------------------------------
+function PclZipUtilTranslateWinPath($p_path, $p_remove_disk_letter = true)
+{
+ if (stristr(php_uname(), 'windows')) {
+ // ----- Look for potential disk letter
+ if (($p_remove_disk_letter) && (($v_position = strpos($p_path, ':')) != false)) {
+ $p_path = substr($p_path, $v_position + 1);
+ }
+ // ----- Change potential windows directory separator
+ if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0, 1) == '\\')) {
+ $p_path = strtr($p_path, '\\', '/');
+ }
+ }
+
+ return $p_path;
+}
+// --------------------------------------------------------------------------------
diff --git a/phpunit-runner.php b/phpunit-runner.php
new file mode 100755
index 0000000..6242d8d
--- /dev/null
+++ b/phpunit-runner.php
@@ -0,0 +1,36 @@
+load($arguments);
+$testRunner = new TestRunner();
+$result = $testRunner->run($configuration);
+
+exit($result->wasSuccessful() ? 0 : 1);
diff --git a/phpunit.xml b/phpunit.xml
new file mode 100755
index 0000000..ddab5b0
--- /dev/null
+++ b/phpunit.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+ tests/src
+
+
+
+
+ src
+
+
+ vendor
+
+
+
+
+
+
diff --git a/run-tests.bat b/run-tests.bat
new file mode 100755
index 0000000..883007f
--- /dev/null
+++ b/run-tests.bat
@@ -0,0 +1,8 @@
+@echo off
+
+rem Assuming you're on Windows.
+rem Assuming you have php.exe in your path
+rem
+rem Add option "--debug" to get more output.
+
+php.exe phpunit-runner.php --configuration=phpunit.xml
diff --git a/run-tests.sh b/run-tests.sh
new file mode 100755
index 0000000..53deed6
--- /dev/null
+++ b/run-tests.sh
@@ -0,0 +1,7 @@
+#/bin/bash
+
+#
+# Add option "--debug" to get more output.
+#
+
+vendor/bin/phpunit --configuration=phpunit.xml
diff --git a/src/Attributes/AllowDynamicProperties.php b/src/Attributes/AllowDynamicProperties.php
new file mode 100755
index 0000000..d494290
--- /dev/null
+++ b/src/Attributes/AllowDynamicProperties.php
@@ -0,0 +1,18 @@
+ 'Odtphp\\Zip\\PclZipProxy',
+#[AllowDynamicProperties]
+class Odf {
+ /**
+ * Zip file handler.
+ *
+ * @var \Odtphp\Zip\ZipInterface
+ */
+ protected ZipInterface $file;
+
+ /**
+ * Conversion ratio from pixels to centimeters.
+ */
+ protected const PIXEL_TO_CM = 0.026458333;
+
+ /**
+ * Default configuration values.
+ *
+ * @var array
+ */
+ protected array $config = [
+ 'ZIP_PROXY' => PhpZipProxy::class,
'DELIMITER_LEFT' => '{',
'DELIMITER_RIGHT' => '}',
- 'PATH_TO_TMP' => null
- );
- protected $file;
- protected $contentXml; // To store content of content.xml file
- protected $manifestXml; // To store content of manifest.xml file
- protected $stylesXml; // To store content of styles.xml file
- protected $tmpfile;
- protected $images = array();
- protected $vars = array();
- protected $manif_vars = array(); // array to store image names
- protected $segments = array();
- const PIXEL_TO_CM = 0.026458333;
-
- /**
- * Class constructor
- *
- * @param string $filename the name of the odt file
- * @throws OdfException
- */
- public function __construct($filename, $config = array())
- {
- if (!is_array($config)) {
- throw new OdfException('Configuration data must be provided as array');
- }
- foreach ($config as $configKey => $configValue) {
- if (array_key_exists($configKey, $this->config)) {
- $this->config[$configKey] = $configValue;
- }
- }
- if (!class_exists($this->config['ZIP_PROXY'])) {
- throw new OdfException($this->config['ZIP_PROXY'] . ' class not found - check your php settings');
- }
- $zipHandler = $this->config['ZIP_PROXY'];
- $this->file = new $zipHandler();
- if ($this->file->open($filename) !== true) {
- throw new OdfException("Error while Opening the file '$filename' - Check your odt file");
- }
- if (($this->contentXml = $this->file->getFromName('content.xml')) === false) {
- throw new OdfException("Nothing to parse - check that the content.xml file is correctly formed");
- }
- if (($this->stylesXml = $this->file->getFromName('styles.xml')) === false) {
- throw new OdfException("Nothing to parse - Check that the styles.xml file is correctly formed in source file '$filename'");
- }
- if (($this->manifestXml = $this->file->getFromName('META-INF/manifest.xml')) === false) {
- throw new OdfException("Something is wrong with META-INF/manifest.xm in source file '$filename'");
- }
-
- $this->file->close();
-
- $tmp = tempnam($this->config['PATH_TO_TMP'], md5(uniqid()));
- copy($filename, $tmp);
- $this->tmpfile = $tmp;
- $this->_moveRowSegments();
- }
-
- /**
- * Delete the temporary file when the object is destroyed
- */
- public function __destruct()
- {
- if (file_exists($this->tmpfile)) {
- unlink($this->tmpfile);
- }
- }
-
- /**
- * Assing a template variable
- *
- * @param string $key name of the variable within the template
- * @param string $value replacement value
- * @param bool $encode if true, special XML characters are encoded
- * @throws OdfException
- * @return odf
- */
- public function setVars($key, $value, $encode = true, $charset = 'ISO-8859')
- {
- $tag= $this->config['DELIMITER_LEFT'] . $key . $this->config['DELIMITER_RIGHT'];
- if (strpos($this->contentXml, $tag) === false && strpos($this->stylesXml, $tag) === false) {
- throw new OdfException("var $key not found in the document");
- }
- $value = $encode ? $this->recursiveHtmlspecialchars($value) : $value;
- $value = ($charset == 'ISO-8859') ? utf8_encode($value) : $value;
- $this->vars[$tag] = str_replace("\n", " ", $value);
- return $this;
- }
-
- /**
- * Assign a template variable as a picture
- *
- * @param string $key name of the variable within the template
- * @param string $value path to the picture
- * @param integer $page anchor to page number (or -1 if anchor-type is as-char)
- * @param integer $width width of picture (keep original if null)
- * @param integer $height height of picture (keep original if null)
- * @param integer $offsetX offset by horizontal (not used if $page = -1)
- * @param integer $offsetY offset by vertical (not used if $page = -1)
- * @throws OdfException
- * @return odf
- */
- public function setImage($key, $value, $page = -1, $width = null, $height = null, $offsetX = null, $offsetY = null)
- {
- $filename = strtok(strrchr($value, '/'), '/.');
- $file = substr(strrchr($value, '/'), 1);
- $size = @getimagesize($value);
- if ($size === false) {
- throw new OdfException("Invalid image");
- }
- if (!$width && !$height) {
- list ($width, $height) = $size;
- $width *= Odf::PIXEL_TO_CM;
- $height *= Odf::PIXEL_TO_CM;
- }
- $anchor = $page == -1 ? 'text:anchor-type="as-char"' : "text:anchor-type=\"page\" text:anchor-page-number=\"{$page}\" svg:x=\"{$offsetX}cm\" svg:y=\"{$offsetY}cm\"";
- $xml = << NULL
+ ];
+
+ /**
+ * Content of the content.xml file.
+ */
+ protected string $contentXml = '';
+
+ /**
+ * Content of the manifest.xml file.
+ */
+ protected string $manifestXml = '';
+
+ /**
+ * Content of the styles.xml file.
+ */
+ protected string $stylesXml = '';
+
+ /**
+ * Temporary file path.
+ */
+ protected string $tmpfile = '';
+
+ /**
+ * Array of images used in the document.
+ *
+ * @var array
+ */
+ protected array $images = [];
+
+ /**
+ * Template variables.
+ *
+ * @var array
+ */
+ protected array $vars = [];
+
+ /**
+ * Manifest variables for image tracking.
+ *
+ * @var array
+ */
+ protected array $manifestVars = [];
+
+ /**
+ * Document segments.
+ *
+ * @var array
+ */
+ protected array $segments = [];
+
+ /**
+ * Initialize ODT document handling.
+ *
+ * @param string $filename
+ * Path to the ODT template file to process.
+ * @param array $config
+ * Configuration options for document processing.
+ *
+ * @throws \Odtphp\Exceptions\OdfException
+ * When the ODT file cannot be initialized or processed.
+ */
+ public function __construct(
+ protected readonly string $filename,
+ array $config = [],
+ ) {
+ // Merge and validate configuration.
+ $this->config = $this->mergeAndValidateConfig($config);
+
+ // Set default temporary directory if not provided.
+ if ($this->config['PATH_TO_TMP'] === NULL) {
+ $this->config['PATH_TO_TMP'] = sys_get_temp_dir();
+ }
+
+ // Validate configuration components.
+ $this->validateTemporaryDirectory();
+ $this->validateZipProxy();
+
+ // Initialize properties and process file.
+ $this->initializeProperties();
+ $this->processZipFile();
+ }
+
+ /**
+ * Merge and validate configuration options.
+ *
+ * @param array $config
+ * User-provided configuration.
+ *
+ * @return array
+ * Validated configuration array with default values merged.
+ *
+ * @throws \Odtphp\Exceptions\OdfException
+ * If configuration is invalid or cannot be processed.
+ */
+ private function mergeAndValidateConfig(array $config): array {
+ // Start with default configuration.
+ $mergedConfig = $this->config;
+
+ // Merge user configuration.
+ foreach ($config as $key => $value) {
+ $mergedConfig[$key] = $value;
+ }
+
+ return $mergedConfig;
+ }
+
+ /**
+ * Validate temporary directory configuration.
+ *
+ * @throws \Odtphp\Exceptions\OdfException
+ * If the temporary directory is invalid or inaccessible.
+ */
+ private function validateTemporaryDirectory(): void {
+ $path = $this->config['PATH_TO_TMP'];
+
+ if (!is_string($path)) {
+ throw new OdfException('Temporary directory path must be a string');
+ }
+
+ $path = rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
+
+ if (!is_dir($path)) {
+ throw new OdfException('Temporary directory does not exist');
+ }
+
+ if (!is_writable($path)) {
+ throw new OdfException('Temporary directory is not writable');
+ }
+
+ $this->config['PATH_TO_TMP'] = $path;
+ }
+
+ /**
+ * Validate ZIP proxy configuration.
+ *
+ * @throws \Odtphp\Exceptions\OdfException
+ * If the ZIP proxy class is invalid or does not implement the required interface.
+ *
+ * @return void
+ * Validates the ZIP proxy class configuration.
+ */
+ private function validateZipProxy(): void {
+ $zipProxyClass = $this->config['ZIP_PROXY'];
+
+ if (!class_exists($zipProxyClass)) {
+ throw new OdfException("ZIP proxy class does not exist: $zipProxyClass");
+ }
+
+ if (!is_subclass_of($zipProxyClass, ZipInterface::class)) {
+ throw new OdfException("$zipProxyClass must implement ZipInterface");
+ }
+ }
+
+ /**
+ * Initialize object properties with default values.
+ *
+ * @return void
+ * Initializes all internal object properties to their default values.
+ */
+ private function initializeProperties(): void {
+ $this->contentXml = '';
+ $this->manifestXml = '';
+ $this->stylesXml = '';
+ $this->tmpfile = '';
+ $this->images = [];
+ $this->vars = [];
+ $this->manifestVars = [];
+ $this->segments = [];
+ }
+
+ /**
+ * Process the ZIP file and extract necessary XML contents.
+ *
+ * @throws \Odtphp\Exceptions\OdfException
+ * If the file cannot be processed or XML contents cannot be extracted.
+ *
+ * @return void
+ * Processes the ZIP file and extracts required XML contents.
+ */
+ private function processZipFile(): void {
+ // Validate file existence.
+ if (!file_exists($this->filename)) {
+ throw new OdfException("File '{$this->filename}' does not exist");
+ }
+
+ // Create ZIP handler.
+ $zipHandlerClass = $this->config['ZIP_PROXY'];
+ $this->file = new $zipHandlerClass($this->config['PATH_TO_TMP']);
+
+ // Open ZIP file.
+ if ($this->file->open($this->filename) !== TRUE) {
+ throw new OdfException("Error opening file '{$this->filename}'");
+ }
+
+ // Extract XML contents.
+ $this->extractXmlContents();
+
+ // Close the ZIP file.
+ $this->file->close();
+
+ // Create a temporary copy of the file.
+ $this->createTemporaryFileCopy();
+
+ // Process row segments.
+ $this->moveRowSegments();
+ }
+
+ /**
+ * Extract XML contents from the ZIP file.
+ *
+ * @throws \Odtphp\Exceptions\OdfException
+ * If XML content extraction fails or required files are missing.
+ *
+ * @return void
+ * Extracts and stores XML content from the ODT file.
+ */
+ private function extractXmlContents(): void {
+ // Extract content.xml.
+ $this->contentXml = $this->file->getFromName('content.xml');
+ if ($this->contentXml === FALSE) {
+ throw new OdfException("Error during content.xml extraction");
+ }
+
+ // Extract manifest.xml.
+ $this->manifestXml = $this->file->getFromName('META-INF/manifest.xml');
+ if ($this->manifestXml === FALSE) {
+ throw new OdfException("Error during manifest.xml extraction");
+ }
+
+ // Extract styles.xml.
+ $this->stylesXml = $this->file->getFromName('styles.xml');
+ if ($this->stylesXml === FALSE) {
+ throw new OdfException("Error during styles.xml extraction");
+ }
+ }
+
+ /**
+ * Create a temporary copy of the file for processing.
+ *
+ * @throws \Odtphp\Exceptions\OdfException
+ * If the temporary file cannot be created or copied.
+ *
+ * @return void
+ * Creates a temporary copy of the ODT file.
+ */
+ private function createTemporaryFileCopy(): void {
+ $this->tmpfile = tempnam($this->config['PATH_TO_TMP'], 'odtphp_');
+ if ($this->tmpfile === FALSE) {
+ throw new OdfException('Error creating temporary file');
+ }
+ copy($this->filename, $this->tmpfile);
+ }
+
+ /**
+ * Delete the temporary file when the object is destroyed.
+ *
+ * @return void
+ * Cleans up temporary files used during processing.
+ */
+ public function __destruct() {
+ if (file_exists($this->tmpfile)) {
+ unlink($this->tmpfile);
+ }
+ }
+
+ /**
+ * Assign a template variable.
+ *
+ * @param string $key
+ * Name of the variable within the template.
+ * @param string $value
+ * Replacement value for the variable.
+ * @param bool $encode
+ * Whether to encode special XML characters for safe XML output.
+ * @param string $charset
+ * Character set encoding of the input value (defaults to UTF-8).
+ *
+ * @throws \Odtphp\Exceptions\OdfException
+ * When the variable is not found in the document.
+ *
+ * @return $this
+ * The current ODT object for method chaining.
+ */
+ public function setVars($key, $value, $encode = TRUE, $charset = 'UTF-8'): self {
+ $tag = $this->config['DELIMITER_LEFT'] . $key . $this->config['DELIMITER_RIGHT'];
+ if (strpos($this->contentXml, $tag) === FALSE && strpos($this->stylesXml, $tag) === FALSE) {
+ throw new OdfException("var $key not found in the document");
+ }
+
+ // Handle encoding.
+ $value = $encode ? $this->recursiveHtmlspecialchars($value) : $value;
+
+ // Convert to UTF-8 if not already.
+ if ($charset !== 'UTF-8') {
+ $value = mb_convert_encoding($value, 'UTF-8', $charset);
+ }
+
+ $this->vars[$tag] = str_replace("\n", " ", $value);
+ return $this;
+ }
+
+ /**
+ * Set the value of a variable in a template.
+ *
+ * @param string $key
+ * Name of the variable within the template.
+ * @param string $value
+ * Replacement value for the variable.
+ * @param bool $encode
+ * Whether to encode special XML characters for safe XML output.
+ *
+ * @throws \Odtphp\Exceptions\OdfException
+ * When the variable is not found in the document.
+ *
+ * @return $this
+ * The current ODT object for method chaining.
+ */
+ public function setVariable($key, $value, $encode = TRUE): self {
+ return $this->setVars($key, $value, $encode);
+ }
+
+ /**
+ * Check if a variable exists in the template.
+ *
+ * @param string $key
+ * Name of the variable to check for in the template.
+ *
+ * @throws \Odtphp\Exceptions\OdfException
+ * When the variable check operation fails.
+ *
+ * @return bool
+ * TRUE if the variable exists in the document, FALSE otherwise.
+ */
+ public function variableExists($key): bool {
+ return strpos($this->contentXml, $this->config['DELIMITER_LEFT'] . $key . $this->config['DELIMITER_RIGHT']) !== FALSE;
+ }
+
+ /**
+ * Assign a template variable as a picture.
+ *
+ * @param string $key
+ * Name of the variable within the template.
+ * @param string $value
+ * Absolute or relative path to the picture file.
+ * @param int $page
+ * Page number to anchor the image to (-1 for as-char anchoring).
+ * @param int|null $width
+ * Width of the picture in pixels (null to keep original).
+ * @param int|null $height
+ * Height of the picture in pixels (null to keep original).
+ * @param int|null $offsetX
+ * Horizontal offset in pixels (ignored if $page is -1).
+ * @param int|null $offsetY
+ * Vertical offset in pixels (ignored if $page is -1).
+ *
+ * @throws \Odtphp\Exceptions\OdfException
+ * When the image cannot be added or processed.
+ *
+ * @return $this
+ * The current ODT object for method chaining.
+ */
+ public function setImage($key, $value, $page = -1, $width = NULL, $height = NULL, $offsetX = NULL, $offsetY = NULL): self {
+ $filename = strtok(strrchr($value, '/'), '/.');
+ $file = substr(strrchr($value, '/'), 1);
+ $size = @getimagesize($value);
+ if ($size === FALSE) {
+ throw new OdfException("Invalid image");
+ }
+ if (!$width && !$height) {
+ [$width, $height] = $size;
+ $width *= $this->getPixelToCm();
+ $height *= $this->getPixelToCm();
+ }
+ $anchor = $page == -1 ? 'text:anchor-type="as-char"' : "text:anchor-type=\"page\" text:anchor-page-number=\"{$page}\" svg:x=\"{$offsetX}cm\" svg:y=\"{$offsetY}cm\"";
+ $xml = <<
IMG;
-
- $this->images[$value] = $file;
- $this->manif_vars[] = $file; //save image name as array element
- $this->setVars($key, $xml, false);
- return $this;
- }
-
- /**
- * Move segment tags for lines of tables
- * Called automatically within the constructor
- *
- * @return void
- */
- private function _moveRowSegments()
- {
- // Search all possible rows in the document
- $reg1 = "#]*>(.*) #smU";
- preg_match_all($reg1, $this->contentXml, $matches);
- for ($i = 0, $size = count($matches[0]); $i < $size; $i++) {
- // Check if the current row contains a segment row.*
- $reg2 = '#\[!--\sBEGIN\s(row.[\S]*)\s--\](.*)\[!--\sEND\s\\1\s--\]#smU';
- if (preg_match($reg2, $matches[0][$i], $matches2)) {
- $balise = str_replace('row.', '', $matches2[1]);
- // Move segment tags around the row
- $replace = array(
- '[!-- BEGIN ' . $matches2[1] . ' --]' => '',
- '[!-- END ' . $matches2[1] . ' --]' => '',
- ' '[!-- BEGIN ' . $balise . ' --]' => ' [!-- END ' . $balise . ' --]'
- );
- $replacedXML = str_replace(array_keys($replace), array_values($replace), $matches[0][$i]);
- $this->contentXml = str_replace($matches[0][$i], $replacedXML, $this->contentXml);
- }
- }
- }
-
- /**
- * Merge template variables
- * Called automatically for a save
- *
- * @return void
- */
- private function _parse()
- {
- $this->contentXml = str_replace(array_keys($this->vars), array_values($this->vars), $this->contentXml);
- $this->stylesXml = str_replace(array_keys($this->vars), array_values($this->vars), $this->stylesXml);
- }
- /**
- * Add the merged segment to the document
- *
- * @param Segment $segment
- * @throws OdfException
- * @return odf
- */
- public function mergeSegment(Segment $segment)
- {
- if (! array_key_exists($segment->getName(), $this->segments)) {
- throw new OdfException($segment->getName() . 'cannot be parsed, has it been set yet ?');
- }
- $string = $segment->getName();
- // $reg = '@]*>\[!--\sBEGIN\s' . $string . '\s--\](.*)\[!--.+END\s' . $string . '\s--\]<\/text:p>@smU';
- $reg = '@\[!--\sBEGIN\s' . $string . '\s--\](.*)\[!--.+END\s' . $string . '\s--\]@smU';
- $this->contentXml = preg_replace($reg, $segment->getXmlParsed(), $this->contentXml);
- foreach ($segment->manif_vars as $val) {
- $this->manif_vars[] = $val; //copy all segment image names into current array
- }
- return $this;
- }
-
- /**
- * Display all the current template variables
- *
- * @return string
- */
- public function printVars()
- {
- return print_r('' . print_r($this->vars, true) . ' ', true);
- }
-
- /**
- * Display the XML content of the file from odt document
- * as it is at the moment
- *
- * @return string
- */
- public function __toString()
- {
- return $this->contentXml;
- }
-
- /**
- * Display loop segments declared with setSegment()
- *
- * @return string
- */
- public function printDeclaredSegments()
- {
- return '' . print_r(implode(' ', array_keys($this->segments)), true) . ' ';
- }
-
- /**
- * Declare a segment in order to use it in a loop
- *
- * @param string $segment
- * @throws OdfException
- * @return Segment
- */
- public function setSegment($segment)
- {
- if (array_key_exists($segment, $this->segments)) {
- return $this->segments[$segment];
- }
- // $reg = "#\[!--\sBEGIN\s$segment\s--\]<\/text:p>(.*?)\[!--\sEND\s$segment\s--\]#sm";
- $reg = "#\[!--\sBEGIN\s$segment\s--\](.*?)\[!--\sEND\s$segment\s--\]#smU";
- if (preg_match($reg, html_entity_decode($this->contentXml), $m) == 0) {
- throw new OdfException("'$segment' segment not found in the document");
- }
- $this->segments[$segment] = new Segment($segment, $m[1], $this);
- return $this->segments[$segment];
- }
-
- /**
- * Save the odt file on the disk
- *
- * @param string $file name of the desired file
- * @throws OdfException
- * @return void
- */
- public function saveToDisk($file = null)
- {
- if ($file !== null && is_string($file)) {
- if (file_exists($file) && !(is_file($file) && is_writable($file))) {
- throw new OdfException('Permission denied : can\'t create ' . $file);
- }
- $this->_save();
- copy($this->tmpfile, $file);
- } else {
- $this->_save();
- }
- }
-
- /**
- * Internal save
- *
- * @throws OdfException
- * @return void
- */
- private function _save()
- {
- $this->file->open($this->tmpfile);
- $this->_parse();
- if (!$this->file->addFromString('content.xml', $this->contentXml) || !$this->file->addFromString('styles.xml', $this->stylesXml)) {
- throw new OdfException('Error during file export addFromString');
- }
- $lastpos=strrpos($this->manifestXml, "\n", -15); //find second last newline in the manifest.xml file
- $manifdata = "";
-
- //Enter all images description in $manifdata variable
- foreach ($this->manif_vars as $val) {
- $ext = substr(strrchr($val, '.'), 1);
- $manifdata = $manifdata.' '."\n";
- }
- //Place content of $manifdata variable in manifest.xml file at appropriate place
- $this->manifestXml = substr_replace($this->manifestXml, "\n".$manifdata, $lastpos+1, 0);
- //$this->manifestXml = $this->manifestXml ."\n".$manifdata;
-
- if (! $this->file->addFromString('META-INF/manifest.xml', $this->manifestXml)) {
- throw new OdfException('Error during manifest file export');
- }
- foreach ($this->images as $imageKey => $imageValue) {
- $this->file->addFile($imageKey, 'Pictures/' . $imageValue);
- }
- $this->file->close(); // seems to bug on windows CLI sometimes
- }
-
- /**
- * Export the file as attached file by HTTP
- *
- * @param string $name (optionnal)
- * @throws OdfException
- * @return void
- */
- public function exportAsAttachedFile($name = "")
- {
- $this->_save();
- if (headers_sent($filename, $linenum)) {
- throw new OdfException("headers already sent ($filename at $linenum)");
- }
-
- if ($name == "") {
- $name = md5(uniqid()) . ".odt";
- }
-
- header('Content-type: application/vnd.oasis.opendocument.text');
- header('Content-Disposition: attachment; filename="'.$name.'"');
- readfile($this->tmpfile);
- }
-
- /**
- * Returns a variable of configuration
- *
- * @return string The requested variable of configuration
- */
- public function getConfig($configKey)
- {
- if (array_key_exists($configKey, $this->config)) {
- return $this->config[$configKey];
- }
- return false;
- }
-
- /**
- * Returns the temporary working file
- *
- * @return string le chemin vers le fichier temporaire de travail
- */
- public function getTmpfile()
- {
- return $this->tmpfile;
- }
-
-
- /**
- * Recursive htmlspecialchars
- */
- protected function recursiveHtmlspecialchars($value)
- {
- if (is_array($value)) {
- return array_map(array($this, 'recursiveHtmlspecialchars'), $value);
- } else {
- return htmlspecialchars($value);
- }
+
+ $this->images[$value] = $file;
+ $this->manifestVars[] = $file;
+ $this->setVars($key, $xml, FALSE);
+ return $this;
+ }
+
+ /**
+ * Move segment tags for lines of tables.
+ *
+ * Called automatically within the constructor.
+ *
+ * @return void
+ * Modifies the internal XML content by moving segment tags.
+ */
+ private function moveRowSegments(): void {
+ // Search all possible rows in the document.
+ $reg1 = "#]*>(.*) #smU";
+ preg_match_all($reg1, $this->contentXml, $matches);
+ for ($i = 0, $size = count($matches[0]); $i < $size; $i++) {
+ // Check if the current row contains a segment row.*.
+ $reg2 = '#\[!--\sBEGIN\s(row.[\S]*)\s--\](.*)\[!--\sEND\s\\1\s--\]#smU';
+ if (preg_match($reg2, $matches[0][$i], $matches2)) {
+ $balise = str_replace('row.', '', $matches2[1]);
+ // Move segment tags around the row.
+ $replace = [
+ '[!-- BEGIN ' . $matches2[1] . ' --]' => '',
+ '[!-- END ' . $matches2[1] . ' --]' => '',
+ ' '[!-- BEGIN ' . $balise . ' --]' => ' [!-- END ' . $balise . ' --]'
+ ];
+ $replacedXML = str_replace(array_keys($replace), array_values($replace), $matches[0][$i]);
+ $this->contentXml = str_replace($matches[0][$i], $replacedXML, $this->contentXml);
+ }
}
+ }
+
+ /**
+ * Merge template variables.
+ *
+ * Called automatically for a save operation.
+ *
+ * @return void
+ * Processes and updates the internal XML content with merged variables.
+ */
+ private function parse(): void {
+ $this->contentXml = str_replace(array_keys($this->vars), array_values($this->vars), $this->contentXml);
+ $this->stylesXml = str_replace(array_keys($this->vars), array_values($this->vars), $this->stylesXml);
+ }
+
+ /**
+ * Add the merged segment to the document.
+ *
+ * @param \Odtphp\Segment $segment
+ * The segment to merge.
+ *
+ * @throws \Odtphp\Exceptions\OdfException
+ * When the segment cannot be merged or has not been set.
+ *
+ * @return $this
+ * The current ODT object instance.
+ */
+ public function mergeSegment(Segment $segment): self {
+ if (!array_key_exists($segment->getName(), $this->segments)) {
+ throw new OdfException($segment->getName() . ' cannot be parsed, has it been set yet?');
+ }
+ $string = $segment->getName();
+ $reg = '@\[!--\sBEGIN\s' . $string . '\s--\](.*)\[!--.+END\s' . $string . '\s--\]@smU';
+ $this->contentXml = preg_replace($reg, $segment->getXmlParsed(), $this->contentXml);
+ foreach ($segment->manifestVars as $val) {
+ // Copy all segment image names into current array.
+ $this->manifestVars[] = $val;
+ }
+ return $this;
+ }
+
+ /**
+ * Display all the current template variables.
+ *
+ * @return string
+ * The formatted string containing all template variables.
+ */
+ public function printVars(): string {
+ return print_r('' . print_r($this->vars, TRUE) . ' ', TRUE);
+ }
+
+ /**
+ * Display the XML content of the file from ODT document as it is at the moment.
+ *
+ * @return string
+ * The XML content of the ODT document.
+ */
+ public function __toString(): string {
+ return $this->contentXml;
+ }
+
+ /**
+ * Display loop segments declared with setSegment().
+ *
+ * @return string
+ * Space-separated list of declared segments.
+ */
+ public function printDeclaredSegments(): string {
+ return '' . print_r(implode(' ', array_keys($this->segments)), TRUE) . ' ';
+ }
+
+ /**
+ * Check if the specified segment exists in the document.
+ *
+ * @param string $segment
+ * The name of the segment to check.
+ *
+ * @return bool
+ * TRUE when segment exists, FALSE otherwise.
+ */
+ public function segmentExists($segment): bool {
+ $reg = "#\[!--\sBEGIN\s$segment\s--](.*?)\[!--\sEND\s$segment\s--]#smU";
+ return preg_match($reg, html_entity_decode($this->contentXml), $m) != 0;
+ }
+
+ /**
+ * Declare a segment in order to use it in a loop.
+ *
+ * @param string $segment
+ * The name of the segment to declare.
+ *
+ * @throws \Odtphp\Exceptions\OdfException
+ * When the segment cannot be found in the document.
+ *
+ * @return \Odtphp\Segment
+ * The requested segment object for use in a loop.
+ */
+ public function setSegment($segment): Segment {
+ if (array_key_exists($segment, $this->segments)) {
+ return $this->segments[$segment];
+ }
+ $reg = "#\[!--\sBEGIN\s$segment\s--\](.*?)\[!--\sEND\s$segment\s--\]#smU";
+ if (preg_match($reg, html_entity_decode($this->contentXml), $m) == 0) {
+ throw new OdfException("'$segment' segment not found in the document");
+ }
+ $this->segments[$segment] = new Segment($segment, $m[1], $this);
+ return $this->segments[$segment];
+ }
+
+ /**
+ * Save the ODT file to disk.
+ *
+ * @param string|null $file
+ * Name of the desired file. If null, uses the original filename.
+ *
+ * @throws \Odtphp\Exceptions\OdfException
+ * When the file cannot be saved to disk.
+ *
+ * @return void
+ * Saves the ODT file to the specified location.
+ */
+ public function saveToDisk($file = NULL): void {
+ $this->saveInternal();
+ if ($file === NULL) {
+ $file = $this->filename;
+ }
+ copy($this->tmpfile, $file);
+ }
+
+ /**
+ * Export the file as an attached file via HTTP.
+ *
+ * @param string $name
+ * Optional name for the downloaded file.
+ *
+ * @throws \Odtphp\Exceptions\OdfException
+ * When the file cannot be exported or sent via HTTP.
+ *
+ * @return void
+ * Sends the ODT file as an HTTP attachment.
+ */
+ public function exportAsAttachedFile($name = ""): void {
+ $this->saveInternal();
+ if (empty($name)) {
+ $name = basename($this->filename);
+ }
+ header('Content-type: application/vnd.oasis.opendocument.text');
+ header('Content-Disposition: attachment; filename="' . $name . '"');
+ readfile($this->tmpfile);
+ }
+
+ /**
+ * Save internal ODT file state.
+ *
+ * @throws \Odtphp\Exceptions\OdfException
+ * When the internal file state cannot be saved.
+ *
+ * @return void
+ * Updates the internal ODT file state with current changes.
+ */
+ private function saveInternal(): void {
+ $this->file->open($this->tmpfile);
+ $this->parse();
+ if (!$this->file->addFromString('content.xml', $this->contentXml) || !$this->file->addFromString('styles.xml', $this->stylesXml)) {
+ throw new OdfException('Error during file export addFromString');
+ }
+ // Find second last newline in the manifest.xml file.
+ $lastpos = strrpos($this->manifestXml, "\n", -15);
+ $manifdata = "";
+
+ // Enter all images description in $manifdata variable.
+ foreach ($this->manifestVars as $val) {
+ $ext = substr(strrchr($val, '.'), 1);
+ $manifdata = $manifdata . ' ' . "\n";
+ }
+
+ // Place content of $manifdata variable in manifest.xml file at appropriate place.
+ $replace = ' ';
+ if ((strlen($manifdata) > 0) && (strpos($this->manifestXml, $replace) !== FALSE)) {
+ $this->manifestXml = str_replace($replace,
+ $replace . "\n" . $manifdata, $this->manifestXml);
+ }
+ else {
+ // This branch is a fail-safe but normally should not be used.
+ $this->manifestXml = substr_replace($this->manifestXml, "\n" . $manifdata, $lastpos + 1, 0);
+ }
+ if (!$this->file->addFromString('META-INF/manifest.xml', $this->manifestXml)) {
+ throw new OdfException('Error during manifest file export');
+ }
+ foreach ($this->images as $imageKey => $imageValue) {
+ $this->file->addFile($imageKey, 'Pictures/' . $imageValue);
+ }
+ // Seems to bug on windows CLI sometimes.
+ $this->file->close();
+ }
+
+ /**
+ * Returns a variable of configuration.
+ *
+ * @param string $configKey
+ * The name of the configuration variable to retrieve.
+ *
+ * @return string
+ * The requested configuration value.
+ */
+ public function getConfig($configKey): string {
+ if (array_key_exists($configKey, $this->config)) {
+ return $this->config[$configKey];
+ }
+ return FALSE;
+ }
+
+ /**
+ * Get the current configuration.
+ *
+ * @return array
+ * The complete configuration array.
+ */
+ public function getAllConfig(): array {
+ return $this->config;
+ }
+
+ /**
+ * Returns the temporary working file.
+ *
+ * @return string
+ * The path to the temporary working file.
+ */
+ public function getTmpfile(): string {
+ return $this->tmpfile;
+ }
+
+ /**
+ * Get the pixel to centimeter conversion ratio.
+ *
+ * @return float
+ * The pixel to centimeter conversion ratio.
+ */
+ public function getPixelToCm(): float {
+ return self::PIXEL_TO_CM;
+ }
+
+ /**
+ * Recursive htmlspecialchars.
+ *
+ * @param mixed $value
+ * The value to convert.
+ *
+ * @return mixed
+ * The converted value.
+ */
+ protected function recursiveHtmlspecialchars($value): mixed {
+ if (is_array($value)) {
+ return array_map([$this, 'recursiveHtmlspecialchars'], $value);
+ }
+ else {
+ return htmlspecialchars($value);
+ }
+ }
+
}
diff --git a/src/Segment.php b/src/Segment.php
old mode 100644
new mode 100755
index c68fe31..7f2f60e
--- a/src/Segment.php
+++ b/src/Segment.php
@@ -3,240 +3,379 @@
namespace Odtphp;
use Odtphp\SegmentIterator;
+use Odtphp\Exceptions\SegmentException;
+use Odtphp\Exceptions\OdfException;
/**
- * Class for handling templating segments with odt files
- * You need PHP 5.2 at least
- * You need Zip Extension or PclZip library
- * Encoding : ISO-8859-1
- * Author: neveldo $
- * Modified by: Vikas Mahajan http://vikasmahajan.wordpress.com
- * Date - $Date: 2010-12-09 11:11:57
- * SVN Revision - $Rev: 44 $
- * Id : $Id: Segment.php 44 2009-06-17 10:12:59Z neveldo $
+ * Class for handling templating segments with ODT files.
*
- * @copyright GPL License 2008 - Julien Pauli - Cyril PIERRE de GEYER - Anaska (http://www.anaska.com)
- * @license http://www.gnu.org/copyleft/gpl.html GPL License
+ * You need PHP 8.1 at least.
+ * You need Zip Extension or PclZip library.
+ * Encoding: ISO-8859-1.
+ *
+ * @copyright GPL License 2008 - Julien Pauli - Cyril PIERRE de GEYER - Anaska (http://www.anaska.com)
+ * @license http://www.gnu.org/copyleft/gpl.html GPL License
* @version 1.3
*/
-class Segment implements \IteratorAggregate, \Countable
-{
- protected $xml;
- protected $xmlParsed = '';
- protected $name;
- protected $children = array();
- protected $vars = array();
- public $manif_vars = array();
- protected $images = array();
- protected $odf;
- protected $file;
-
- /**
- * Constructor
- *
- * @param string $name name of the segment to construct
- * @param string $xml XML tree of the segment
- */
- public function __construct($name, $xml, $odf)
- {
- $this->name = (string) $name;
- $this->xml = (string) $xml;
- $this->odf = $odf;
- $zipHandler = $this->odf->getConfig('ZIP_PROXY');
- $this->file = new $zipHandler();
- $this->_analyseChildren($this->xml);
- }
+class Segment implements \IteratorAggregate, \Countable {
+ /**
+ * XML content of the segment.
+ *
+ * @var string
+ */
+ protected $xml;
- /**
- * Returns the name of the segment
- *
- * @return string
- */
- public function getName()
- {
- return $this->name;
- }
+ /**
+ * Parsed XML content of the segment.
+ *
+ * @var string
+ */
+ protected $xmlParsed = '';
- /**
- * Does the segment have children ?
- *
- * @return bool
- */
- public function hasChildren()
- {
- return $this->getIterator()->hasChildren();
- }
+ /**
+ * Name of the segment.
+ *
+ * @var string
+ */
+ protected $name;
- /**
- * Countable interface
- *
- * @return int
- */
- public function count()
- {
- return count($this->children);
- }
+ /**
+ * Child segments of this segment.
+ *
+ * @var Segment[]
+ */
+ protected $children = [];
- /**
- * IteratorAggregate interface
- *
- * @return Iterator
- */
- public function getIterator()
- {
- return new \RecursiveIteratorIterator(new SegmentIterator($this->children), 1);
- }
+ /**
+ * Variables to be replaced in the segment.
+ *
+ * @var array
+ */
+ protected $vars = [];
- /**
- * Replace variables of the template in the XML code
- * All the children are also called
- *
- * @return string
- */
- public function merge()
- {
- $this->xmlParsed .= str_replace(array_keys($this->vars), array_values($this->vars), $this->xml);
- if ($this->hasChildren()) {
- foreach ($this->children as $child) {
- $this->xmlParsed = str_replace($child->xml, ($child->xmlParsed=="")?$child->merge():$child->xmlParsed, $this->xmlParsed);
- $child->xmlParsed = '';
- //Store all image names used in child segments in current segment array
- foreach ($child->manif_vars as $file) {
- $this->manif_vars[] = $file;
- }
-
- $child->manif_vars = array();
- }
- }
- $reg = "/\[!--\sBEGIN\s$this->name\s--\](.*)\[!--\sEND\s$this->name\s--\]/smU";
- $this->xmlParsed = preg_replace($reg, '$1', $this->xmlParsed);
- $this->file->open($this->odf->getTmpfile());
- foreach ($this->images as $imageKey => $imageValue) {
- if ($this->file->getFromName('Pictures/' . $imageValue) === false) {
- $this->file->addFile($imageKey, 'Pictures/' . $imageValue);
- }
+ /**
+ * Manifest variables for the segment.
+ *
+ * @var array
+ */
+ public $manifestVars = [];
+
+ /**
+ * Images used in the segment.
+ *
+ * @var array
+ */
+ protected $images = [];
+
+ /**
+ * ODT file object.
+ *
+ * @var object
+ */
+ protected $odf;
+
+ /**
+ * Zip file handler.
+ *
+ * @var object
+ */
+ protected $file;
+
+ /**
+ * Constructor.
+ *
+ * @param string $name
+ * Name of the segment to construct.
+ * @param string $xml
+ * XML tree of the segment.
+ * @param object $odf
+ * ODT file object.
+ */
+ public function __construct($name, $xml, $odf) {
+ $this->name = (string) $name;
+ $this->xml = (string) $xml;
+ $this->odf = $odf;
+ $zipHandler = $this->odf->getConfig('ZIP_PROXY');
+ $this->file = new $zipHandler();
+ $this->analyseChildren($this->xml);
+ }
+
+ /**
+ * Returns the name of the segment.
+ *
+ * @return string
+ * The name of the segment.
+ */
+ public function getName(): string {
+ return $this->name;
+ }
+
+ /**
+ * Checks if the segment has children.
+ *
+ * @return bool
+ * TRUE if the segment has children, FALSE otherwise.
+ */
+ public function hasChildren(): bool {
+ return !empty($this->children);
+ }
+
+ /**
+ * Implements the Countable interface.
+ *
+ * @return int
+ * Number of children in the segment.
+ */
+ #[\ReturnTypeWillChange]
+ public function count(): int {
+ return count($this->children);
+ }
+
+ /**
+ * Implements the IteratorAggregate interface.
+ *
+ * @return \RecursiveIteratorIterator
+ * Iterator for the segment's children.
+ */
+ #[\ReturnTypeWillChange]
+ public function getIterator(): \RecursiveIteratorIterator {
+ return new \RecursiveIteratorIterator(new SegmentIterator($this->children), 1);
+ }
+
+ /**
+ * Replace variables of the template in the XML code.
+ *
+ * All the children are also processed.
+ *
+ * @return string
+ * The merged XML content with variables replaced.
+ */
+ public function merge(): string {
+ $this->xmlParsed .= str_replace(array_keys($this->vars), array_values($this->vars), $this->xml);
+ if ($this->hasChildren()) {
+ foreach ($this->children as $child) {
+ $this->xmlParsed = str_replace($child->xml, ($child->xmlParsed == "") ? $child->merge() : $child->xmlParsed, $this->xmlParsed);
+ $child->xmlParsed = '';
+ // Store all image names used in child segments in current segment array.
+ foreach ($child->manifestVars as $file) {
+ $this->manifestVars[] = $file;
}
- $this->file->close();
- return $this->xmlParsed;
+ $child->manifestVars = [];
+ }
+ }
+ $reg = "/\[!--\sBEGIN\s$this->name\s--\](.*)\[!--\sEND\s$this->name\s--\]/smU";
+ $this->xmlParsed = preg_replace($reg, '$1', $this->xmlParsed);
+ $this->file->open($this->odf->getTmpfile());
+ foreach ($this->images as $imageKey => $imageValue) {
+ if ($this->file->getFromName('Pictures/' . $imageValue) === FALSE) {
+ $this->file->addFile($imageKey, 'Pictures/' . $imageValue);
+ }
}
- /**
- * Analyse the XML code in order to find children
- *
- * @param string $xml
- * @return Segment
- */
- protected function _analyseChildren($xml)
- {
- // $reg2 = "#\[!--\sBEGIN\s([\S]*)\s--\](?:<\/text:p>)?(.*)(?:)?\[!--\sEND\s(\\1)\s--\]#sm";
- $reg2 = "#\[!--\sBEGIN\s([\S]*)\s--\](.*)\[!--\sEND\s(\\1)\s--\]#smU";
- preg_match_all($reg2, $xml, $matches);
- for ($i = 0, $size = count($matches[0]); $i < $size; $i++) {
- if ($matches[1][$i] != $this->name) {
- $this->children[$matches[1][$i]] = new self($matches[1][$i], $matches[0][$i], $this->odf);
- } else {
- $this->_analyseChildren($matches[2][$i]);
- }
- }
- return $this;
+ $this->file->close();
+ return $this->xmlParsed;
+ }
+
+ /**
+ * Analyse the XML code to find children segments.
+ *
+ * @param string $xml
+ * XML content to analyse.
+ *
+ * @return $this
+ * The current segment instance.
+ */
+ protected function analyseChildren($xml): self {
+ $reg2 = "#\[!--\sBEGIN\s([\S]*)\s--\](.*)\[!--\sEND\s(\\1)\s--\]#smU";
+ preg_match_all($reg2, $xml, $matches);
+ for ($i = 0, $size = count($matches[0]); $i < $size; $i++) {
+ if ($matches[1][$i] != $this->name) {
+ $this->children[$matches[1][$i]] = new self($matches[1][$i], $matches[0][$i], $this->odf);
+ }
+ else {
+ $this->analyseChildren($matches[2][$i]);
+ }
}
+ return $this;
+ }
- /**
- * Assign a template variable to replace
- *
- * @param string $key
- * @param string $value
- * @throws SegmentException
- * @return Segment
- */
- public function setVars($key, $value, $encode = true, $charset = 'ISO-8859')
- {
- if (strpos($this->xml, $this->odf->getConfig('DELIMITER_LEFT') . $key . $this->odf->getConfig('DELIMITER_RIGHT')) === false) {
- throw new SegmentException("var $key not found in {$this->getName()}");
- }
- $value = $encode ? htmlspecialchars($value) : $value;
- $value = ($charset == 'ISO-8859') ? utf8_encode($value) : $value;
- $this->vars[$this->odf->getConfig('DELIMITER_LEFT') . $key . $this->odf->getConfig('DELIMITER_RIGHT')] = str_replace("\n", " ", $value);
- return $this;
+ /**
+ * Assign a template variable to replace.
+ *
+ * @param string $key
+ * The variable key to replace.
+ * @param string $value
+ * The value to replace the variable with.
+ * @param bool $encode
+ * Whether to HTML encode the value.
+ * @param string $charset
+ * Character set for encoding.
+ *
+ * @throws \Odtphp\Exceptions\SegmentException
+ * If the variable is not found in the segment.
+ *
+ * @return $this
+ * The current segment instance.
+ */
+ public function setVars($key, $value, $encode = TRUE, $charset = 'UTF-8'): self {
+ if (strpos($this->xml, $this->odf->getConfig('DELIMITER_LEFT') . $key . $this->odf->getConfig('DELIMITER_RIGHT')) === FALSE) {
+ throw new SegmentException("var $key not found in {$this->getName()}");
}
+ $value = $encode ? htmlspecialchars($value) : $value;
+ $value = ($charset != 'UTF-8') ? mb_convert_encoding($value, 'UTF-8', $charset) : $value;
+ $this->vars[$this->odf->getConfig('DELIMITER_LEFT') . $key . $this->odf->getConfig('DELIMITER_RIGHT')] = str_replace("\n", " ", $value);
+ return $this;
+ }
- /**
- * Assign a template variable as a picture
- *
- * @param string $key name of the variable within the template
- * @param string $value path to the picture
- * @param string $page anchor to page number (or -1 if anchor-type is aschar)
- * @param string $width width of picture (keep original if null)
- * @param string $height height of picture (keep original if null)
- * @param string $offsetX offset by horizontal (not used if $page = -1)
- * @param string $offsetY offset by vertical (not used if $page = -1)
- * @throws OdfException
- * @return Segment
- */
- public function setImage($key, $value, $page = null, $width = null, $height = null, $offsetX = null, $offsetY = null)
- {
- $filename = strtok(strrchr($value, '/'), '/.');
- $file = substr(strrchr($value, '/'), 1);
- $size = @getimagesize($value);
- if ($size === false) {
- throw new OdfException("Invalid image");
- }
- if (!$width && !$height) {
- list ($width, $height) = $size;
- $width *= Odf::PIXEL_TO_CM;
- $height *= Odf::PIXEL_TO_CM;
- }
- $anchor = $page == -1 ? 'text:anchor-type="aschar"' : "text:anchor-type=\"page\" text:anchor-page-number=\"{$page}\" svg:x=\"{$offsetX}cm\" svg:y=\"{$offsetY}cm\"";
- $xml = << odf->getPixelToCm();
+ $height *= $this->odf->getPixelToCm();
+ }
+ $anchor = $page == -1 ? 'text:anchor-type="as-char"' : "text:anchor-type=\"page\" text:anchor-page-number=\"{$page}\" svg:x=\"{$offsetX}cm\" svg:y=\"{$offsetY}cm\"";
+ $xml = <<
IMG;
- $this->images[$value] = $file;
- $this->manif_vars[] = $file; //save image name as array element
- $this->setVars($key, $xml, false);
- return $this;
- }
+ $this->images[$value] = $file;
+ $this->manifestVars[] = $file;
+ $this->setVars($key, $xml, FALSE);
+ return $this;
+ }
- /**
- * Shortcut to retrieve a child
- *
- * @param string $prop
- * @return Segment
- * @throws SegmentException
- */
- public function __get($prop)
- {
- if (array_key_exists($prop, $this->children)) {
- return $this->children[$prop];
- } else {
- throw new SegmentException('child ' . $prop . ' does not exist');
- }
+ /**
+ * Shortcut to retrieve a child.
+ *
+ * @param string $prop
+ * The name of the child segment to retrieve.
+ *
+ * @return Segment
+ * The child segment instance if it exists.
+ *
+ * @throws \Odtphp\Exceptions\SegmentException
+ * If the child segment does not exist.
+ */
+ public function __get($prop): Segment {
+ if (array_key_exists($prop, $this->children)) {
+ return $this->children[$prop];
+ }
+ else {
+ throw new SegmentException('child ' . $prop . ' does not exist');
}
+ }
- /**
- * Proxy for setVars
- *
- * @param string $meth
- * @param array $args
- * @return Segment
- */
- public function __call($meth, $args)
- {
- try {
- array_unshift($args, $meth);
- return call_user_func_array(array($this, 'setVars'), $args);
- } catch (SegmentException $e) {
- throw new SegmentException("method $meth nor var $meth exist");
- }
+ /**
+ * Proxy for setVars.
+ *
+ * @param string $meth
+ * The method name being called.
+ * @param array $args
+ * The arguments passed to the method.
+ *
+ * @return Segment
+ * The current segment instance after setting variables.
+ *
+ * @throws \Odtphp\Exceptions\SegmentException
+ * If the method or variable does not exist.
+ */
+ public function __call($meth, $args): Segment {
+ try {
+ array_unshift($args, $meth);
+ return call_user_func_array([$this, 'setVars'], $args);
+ }
+ catch (SegmentException $e) {
+ throw new SegmentException("method $meth nor var $meth exist");
}
-
- /**
- * Returns the parsed XML
- *
- * @return string
- */
- public function getXmlParsed()
- {
- return $this->xmlParsed;
+ }
+
+ /**
+ * Retrieve the parsed XML content.
+ *
+ * @return string
+ * The parsed XML content of the segment.
+ */
+ public function getXmlParsed(): string {
+ return $this->xmlParsed;
+ }
+
+ /**
+ * Create a new child segment.
+ *
+ * @param string $name
+ * Name of the child segment.
+ *
+ * @return Segment
+ * The child segment with the specified name.
+ *
+ * @throws \Odtphp\Exceptions\SegmentException
+ * If the segment does not exist.
+ */
+ public function setSegment($name): Segment {
+ if (!isset($this->children[$name])) {
+ throw new SegmentException("Segment '$name' does not exist");
}
+ return $this->children[$name];
+ }
+
+ /**
+ * Retrieve the XML content of the segment.
+ *
+ * @return string
+ * The original XML content of the segment.
+ */
+ public function getXml(): string {
+ return $this->xml;
+ }
+
+ /**
+ * Retrieve the segment's children.
+ *
+ * @return Segment[]
+ * An array of child segments.
+ */
+ public function getChildren(): array {
+ return $this->children;
+ }
+
+ /**
+ * Retrieve the segment's variables.
+ *
+ * @return array
+ * An array of variables in the segment.
+ */
+ public function getVars(): array {
+ return $this->vars;
+ }
+
}
diff --git a/src/SegmentIterator.php b/src/SegmentIterator.php
old mode 100644
new mode 100755
index dbde5ed..2fec05c
--- a/src/SegmentIterator.php
+++ b/src/SegmentIterator.php
@@ -1,65 +1,73 @@
*/
-class SegmentIterator implements \RecursiveIterator
-{
- private $ref;
- private $key;
+class SegmentIterator implements \Iterator, \Countable {
+ /**
+ * Current position in the iterator.
+ */
+ private int $position = 0;
- public function __construct(array $ref)
- {
- $this->ref = $ref;
- $this->key = 0;
- $this->keys = array_keys($this->ref);
- }
+ /**
+ * Initialize segment iterator.
+ *
+ * @param array $segments
+ * Array of segments to iterate over.
+ */
+ public function __construct(
+ private readonly array $segments,
+ ) {}
- public function hasChildren()
- {
- return $this->valid() && $this->current() instanceof Segment;
- }
+ /**
+ * Reset iterator position.
+ */
+ public function rewind(): void {
+ $this->position = 0;
+ }
- public function current()
- {
- return $this->ref[$this->keys[$this->key]];
- }
+ /**
+ * Get current segment.
+ */
+ public function current(): Segment {
+ return $this->segments[$this->position];
+ }
- public function getChildren()
- {
- return new self($this->current()->children);
- }
+ /**
+ * Get current position.
+ */
+ public function key(): int {
+ return $this->position;
+ }
- public function key()
- {
- return $this->key;
- }
+ /**
+ * Move to next segment.
+ */
+ public function next(): void {
+ ++$this->position;
+ }
- public function valid()
- {
- return array_key_exists($this->key, $this->keys);
- }
+ /**
+ * Check if current position is valid.
+ */
+ public function valid(): bool {
+ return isset($this->segments[$this->position]);
+ }
- public function rewind()
- {
- $this->key = 0;
- }
+ /**
+ * Get total number of segments.
+ */
+ public function count(): int {
+ return count($this->segments);
+ }
- public function next()
- {
- $this->key ++;
- }
}
diff --git a/src/Zip/PclZipProxy.php b/src/Zip/PclZipProxy.php
old mode 100644
new mode 100755
index b65786a..eadc7dc
--- a/src/Zip/PclZipProxy.php
+++ b/src/Zip/PclZipProxy.php
@@ -6,176 +6,244 @@
use Odtphp\Exceptions\PclZipProxyException;
/**
- * Proxy class for the PclZip library
- * You need PHP 5.2 at least
- * You need Zip Extension or PclZip library
- * Encoding : ISO-8859-1
- * Last commit by $Author: neveldo $
- * Date - $Date: 2009-05-29 10:05:11 +0200 (ven., 29 mai 2009) $
- * SVN Revision - $Rev: 28 $
- * Id : $Id: odf.php 28 2009-05-29 08:05:11Z neveldo $
+ * Proxy class for the PclZip library.
*
- * @copyright GPL License 2008 - Julien Pauli - Cyril PIERRE de GEYER - Anaska (http://www.anaska.com)
- * @license http://www.gnu.org/copyleft/gpl.html GPL License
+ * You need PHP 8.1 at least.
+ * You need Zip Extension or PclZip library.
+ * Encoding: ISO-8859-1.
+ *
+ * @copyright GPL License 2008 - Julien Pauli - Cyril PIERRE de GEYER - Anaska (http://www.anaska.com)
+ * @license http://www.gnu.org/copyleft/gpl.html GPL License
* @version 1.3
*/
-class PclZipProxy implements ZipInterface
-{
- const TMP_DIR = './tmp';
- protected $openned = false;
- protected $filename;
- protected $pclzip;
- /**
- * Class constructor
- *
- * @throws PclZipProxyException
- */
- public function __construct()
- {
- if (!class_exists('PclZip')) {
- throw new PclZipProxyException('PclZip class not loaded - PclZip library is required for using PclZipProxy');
- }
+class PclZipProxy implements ZipInterface {
+
+ /**
+ * Temporary directory path for processing zip files.
+ *
+ * @var string
+ */
+ protected $tmpDir;
+
+ /**
+ * Flag indicating if the zip file is opened.
+ *
+ * @var bool
+ */
+ protected $opened = FALSE;
+
+ /**
+ * Path to the current zip file.
+ *
+ * @var string
+ */
+ protected $filename;
+
+ /**
+ * PclZip instance for handling zip operations.
+ *
+ * @var \PclZip
+ */
+ protected $pclzip;
+
+ /**
+ * Class constructor.
+ *
+ * @throws \Odtphp\Exceptions\PclZipProxyException
+ * When PclZip library is not loaded.
+ */
+ public function __construct() {
+ if (!class_exists('PclZip')) {
+ throw new PclZipProxyException('PclZip class not loaded - PclZip library is required for using PclZipProxy');
}
- /**
- * Open a Zip archive
- *
- * @param string $filename the name of the archive to open
- * @return true if openning has succeeded
- */
- public function open($filename)
- {
- if (true === $this->openned) {
- $this->close();
- }
- if (!file_exists(self::TMP_DIR)) {
- mkdir(self::TMP_DIR);
- }
- $this->filename = $filename;
- $this->pclzip = new \PclZip($this->filename);
- $this->openned = true;
- return true;
- }
-
- /**
- * Retrieve the content of a file within the archive from its name
- *
- * @param string $name the name of the file to extract
- * @return the content of the file in a string
- */
- public function getFromName($name)
- {
- if (false === $this->openned) {
- return false;
- }
- $name = preg_replace("/(?:\.|\/)*(.*)/", "\\1", $name);
- $extraction = $this->pclzip->extract(PCLZIP_OPT_BY_NAME, $name, PCLZIP_OPT_EXTRACT_AS_STRING);
- if (!empty($extraction)) {
- return $extraction[0]['content'];
- }
- return false;
- }
-
- /**
- * Add a file within the archive from a string
- *
- * @param string $localname the local path to the file in the archive
- * @param string $contents the content of the file
- * @return true if the file has been successful added
- */
- public function addFromString($localname, $contents)
- {
- if (false === $this->openned) {
- return false;
- }
- if (file_exists($this->filename) && !is_writable($this->filename)) {
- return false;
- }
- $localname = preg_replace("/(?:\.|\/)*(.*)/", "\\1", $localname);
- $localpath = dirname($localname);
- $tmpfilename = self::TMP_DIR . '/' . basename($localname);
- if (false !== file_put_contents($tmpfilename, $contents)) {
- $this->pclzip->delete(PCLZIP_OPT_BY_NAME, $localname);
- $add = $this->pclzip->add($tmpfilename, PCLZIP_OPT_REMOVE_PATH, self::TMP_DIR, PCLZIP_OPT_ADD_PATH, $localpath);
- unlink($tmpfilename);
- if (!empty($add)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Add a file within the archive from a file
- *
- * @param string $filename the path to the file we want to add
- * @param string $localname the local path to the file in the archive
- * @return true if the file has been successful added
- */
- public function addFile($filename, $localname = null)
- {
- if (false === $this->openned) {
- return false;
- }
- if ((file_exists($this->filename) && !is_writable($this->filename))
- || !file_exists($filename)) {
- return false;
- }
- if (isset($localname)) {
- $localname = preg_replace("/(?:\.|\/)*(.*)/", "\\1", $localname);
- $localpath = dirname($localname);
- $tmpfilename = self::TMP_DIR . '/' . basename($localname);
- } else {
- $localname = basename($filename);
- $tmpfilename = self::TMP_DIR . '/' . $localname;
- $localpath = '';
- }
- if (file_exists($filename)) {
- copy($filename, $tmpfilename);
- $this->pclzip->delete(PCLZIP_OPT_BY_NAME, $localname);
- $this->pclzip->add($tmpfilename, PCLZIP_OPT_REMOVE_PATH, self::TMP_DIR, PCLZIP_OPT_ADD_PATH, $localpath);
- unlink($tmpfilename);
- return true;
- }
- return false;
+
+ if (!function_exists("getmypid")) {
+ $pseudo_pid = mt_rand(1, 99999);
+ }
+ else {
+ $pseudo_pid = getmypid();
+ if (!$pseudo_pid) {
+ $pseudo_pid = mt_rand(1, 99999);
+ }
}
- /**
- * Close the Zip archive
- * @return true
- */
- public function close()
- {
- if (false === $this->openned) {
- return false;
- }
- $this->pclzip = $this->filename = null;
- $this->openned = false;
- if (file_exists(self::TMP_DIR)) {
- $this->_rrmdir(self::TMP_DIR);
- rmdir(self::TMP_DIR);
- }
- return true;
- }
-
- /**
- * Empty the temporary working directory recursively
- * @param $dir the temporary working directory
- * @return void
- */
- private function _rrmdir($dir)
- {
- if ($handle = opendir($dir)) {
- while (false !== ($file = readdir($handle))) {
- if ($file != '.' && $file != '..') {
- if (is_dir($dir . '/' . $file)) {
- $this->_rrmdir($dir . '/' . $file);
- rmdir($dir . '/' . $file);
- } else {
- unlink($dir . '/' . $file);
- }
- }
- }
- closedir($handle);
+ // Make a name that is unique enough for parallel processing: uniqid() by itself
+ // is not unique enough, it's just a hex representation of the system time.
+ $this->tmpDir = sys_get_temp_dir() . '/tmpdir_odtphp_' . uniqid(sprintf('%04X%04X%04X%04X%d',
+ mt_rand(0, 65535), mt_rand(0, 65535),
+ mt_rand(0, 65535), mt_rand(0, 65535), $pseudo_pid),
+ TRUE);
+ }
+
+ /**
+ * Open a Zip archive.
+ *
+ * @param string $filename
+ * The name of the archive to open.
+ *
+ * @return bool
+ * TRUE if opening has succeeded.
+ */
+ public function open($filename) {
+ if (TRUE === $this->opened) {
+ $this->close();
+ }
+ $this->filename = $filename;
+ $this->pclzip = new \PclZip($this->filename);
+ if (!file_exists($this->tmpDir)) {
+ if (mkdir($this->tmpDir)) {
+ // Created a new directory.
+ $this->opened = TRUE;
+ return TRUE;
+ }
+ else {
+ // Failed to create a directory.
+ $this->opened = FALSE;
+ return FALSE;
+ }
+ }
+ else {
+ // Directory already existed.
+ $this->opened = FALSE;
+ return FALSE;
+ }
+ }
+
+ /**
+ * Retrieve the content of a file within the archive from its name.
+ *
+ * @param string $name
+ * The name of the file to extract.
+ *
+ * @return string|bool
+ * The content of the file as a string, or FALSE if retrieval fails.
+ */
+ public function getFromName($name) {
+ if (FALSE === $this->opened) {
+ return FALSE;
+ }
+ $name = preg_replace("/(?:\.|\/)*(.*)/", "\\1", $name);
+ $extraction = $this->pclzip->extract(PCLZIP_OPT_BY_NAME, $name, PCLZIP_OPT_EXTRACT_AS_STRING);
+ if (!empty($extraction)) {
+ return $extraction[0]['content'];
+ }
+ return FALSE;
+ }
+
+ /**
+ * Add a file within the archive from a string.
+ *
+ * @param string $localname
+ * The local path to the file in the archive.
+ * @param string $contents
+ * The content of the file.
+ *
+ * @return bool
+ * TRUE if the file has been successfully added.
+ */
+ public function addFromString($localname, $contents) {
+ if (FALSE === $this->opened) {
+ return FALSE;
+ }
+ if (file_exists($this->filename) && !is_writable($this->filename)) {
+ return FALSE;
+ }
+ $localname = preg_replace("/(?:\.|\/)*(.*)/", "\\1", $localname);
+ $localpath = dirname($localname);
+ $tmpfilename = $this->tmpDir . '/' . basename($localname);
+ if (FALSE !== file_put_contents($tmpfilename, $contents)) {
+ $this->pclzip->delete(PCLZIP_OPT_BY_NAME, $localname);
+ $add = $this->pclzip->add($tmpfilename, PCLZIP_OPT_REMOVE_PATH, $this->tmpDir, PCLZIP_OPT_ADD_PATH, $localpath);
+ unlink($tmpfilename);
+ if (!empty($add)) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+
+ /**
+ * Add a file within the archive from a file.
+ *
+ * @param string $filename
+ * The path to the file we want to add.
+ * @param string|null $localname
+ * The local path to the file in the archive.
+ *
+ * @return bool
+ * TRUE if the file has been successfully added.
+ */
+ public function addFile($filename, $localname = NULL) {
+ if (FALSE === $this->opened) {
+ return FALSE;
+ }
+ if ((file_exists($this->filename) && !is_writable($this->filename))
+ || !file_exists($filename)) {
+ return FALSE;
+ }
+ if (isset($localname)) {
+ $localname = preg_replace("/(?:\.|\/)*(.*)/", "\\1", $localname);
+ $localpath = dirname($localname);
+ $tmpfilename = $this->tmpDir . '/' . basename($localname);
+ }
+ else {
+ $localname = basename($filename);
+ $tmpfilename = $this->tmpDir . '/' . $localname;
+ $localpath = '';
+ }
+ if (file_exists($filename)) {
+ copy($filename, $tmpfilename);
+ $this->pclzip->delete(PCLZIP_OPT_BY_NAME, $localname);
+ $this->pclzip->add($tmpfilename, PCLZIP_OPT_REMOVE_PATH, $this->tmpDir, PCLZIP_OPT_ADD_PATH, $localpath);
+ unlink($tmpfilename);
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+ /**
+ * Close the Zip archive.
+ *
+ * @return bool
+ * TRUE if the archive was closed successfully.
+ */
+ public function close() {
+ if (FALSE === $this->opened) {
+ return FALSE;
+ }
+ $this->pclzip = $this->filename = NULL;
+ $this->opened = FALSE;
+ if (file_exists($this->tmpDir)) {
+ $this->removeDir($this->tmpDir);
+ }
+ return TRUE;
+ }
+
+ /**
+ * Remove directory recursively.
+ *
+ * @param string $dir
+ * The directory to remove.
+ *
+ * @return bool
+ * TRUE if the directory was successfully removed.
+ */
+ private function removeDir($dir): bool {
+ if ($handle = opendir($dir)) {
+ while (FALSE !== ($file = readdir($handle))) {
+ if ($file != '.' && $file != '..') {
+ if (is_dir($dir . '/' . $file)) {
+ $this->removeDir($dir . '/' . $file);
+ rmdir($dir . '/' . $file);
+ }
+ else {
+ unlink($dir . '/' . $file);
+ }
}
+ }
+ closedir($handle);
}
+ return rmdir($dir);
+ }
+
}
diff --git a/src/Zip/PhpZipProxy.php b/src/Zip/PhpZipProxy.php
old mode 100644
new mode 100755
index 9275bcb..a80496c
--- a/src/Zip/PhpZipProxy.php
+++ b/src/Zip/PhpZipProxy.php
@@ -6,98 +6,117 @@
use Odtphp\Exceptions\PhpZipProxyException;
/**
- * Proxy class for the PHP Zip Extension
- * You need PHP 5.2 at least
- * You need Zip Extension or PclZip library
- * Encoding : ISO-8859-1
- * Last commit by $Author: neveldo $
- * Date - $Date: 2009-05-29 10:05:11 +0200 (ven., 29 mai 2009) $
- * SVN Revision - $Rev: 28 $
- * Id : $Id: odf.php 28 2009-05-29 08:05:11Z neveldo $
+ * Proxy class for the PHP Zip Extension.
*
- * @copyright GPL License 2008 - Julien Pauli - Cyril PIERRE de GEYER - Anaska (http://www.anaska.com)
- * @license http://www.gnu.org/copyleft/gpl.html GPL License
+ * You need PHP 8.1 at least.
+ * You need Zip Extension or PclZip library.
+ * Encoding: ISO-8859-1.
+ *
+ * @copyright GPL License 2008 - Julien Pauli - Cyril PIERRE de GEYER - Anaska (http://www.anaska.com)
+ * @license http://www.gnu.org/copyleft/gpl.html GPL License
* @version 1.3
*/
+class PhpZipProxy implements ZipInterface {
-class PhpZipProxy implements ZipInterface
-{
- protected $zipArchive;
- protected $filename;
+ /**
+ * ZipArchive instance for handling zip operations.
+ *
+ * @var \ZipArchive
+ */
+ protected $zipArchive;
- /**
- * Class constructor
- *
- * @throws PhpZipProxyException
- */
- public function __construct()
- {
- if (! class_exists('ZipArchive')) {
- throw new PhpZipProxyException('Zip extension not loaded - check your php settings, PHP5.2 minimum with zip extension is required for using PhpZipProxy');
- }
- $this->zipArchive = new ZipArchive();
- }
+ /**
+ * Path to the current zip file.
+ *
+ * @var string
+ */
+ protected $filename;
- /**
- * Open a Zip archive
- *
- * @param string $filename the name of the archive to open
- * @return true if openning has succeeded
- */
- public function open($filename)
- {
- $this->filename = $filename;
- return $this->zipArchive->open($filename, ZIPARCHIVE::CREATE);
+ /**
+ * Class constructor.
+ *
+ * @throws \Odtphp\Exceptions\PhpZipProxyException
+ * When Zip extension is not loaded.
+ */
+ public function __construct() {
+ if (!class_exists('ZipArchive')) {
+ throw new PhpZipProxyException('Zip extension not loaded - check your php settings, PHP5.2 minimum with zip extension is required for using PhpZipProxy');
}
+ $this->zipArchive = new \ZipArchive();
+ }
- /**
- * Retrieve the content of a file within the archive from its name
- *
- * @param string $name the name of the file to extract
- * @return the content of the file in a string
- */
- public function getFromName($name)
- {
- return $this->zipArchive->getFromName($name);
- }
+ /**
+ * Open a Zip archive.
+ *
+ * @param string $filename
+ * The name of the archive to open.
+ *
+ * @return bool
+ * TRUE if opening has succeeded.
+ */
+ public function open($filename) {
+ $this->filename = $filename;
+ return $this->zipArchive->open($filename, \ZIPARCHIVE::CREATE);
+ }
- /**
- * Add a file within the archive from a string
- *
- * @param string $localname the local path to the file in the archive
- * @param string $contents the content of the file
- * @return true if the file has been successful added
- */
- public function addFromString($localname, $contents)
- {
- if (file_exists($this->filename) && !is_writable($this->filename)) {
- return false;
- }
- return $this->zipArchive->addFromString($localname, $contents);
- }
+ /**
+ * Retrieve the content of a file within the archive from its name.
+ *
+ * @param string $name
+ * The name of the file to extract.
+ *
+ * @return string|bool
+ * The content of the file as a string, or FALSE if retrieval fails.
+ */
+ public function getFromName($name) {
+ return $this->zipArchive->getFromName($name);
+ }
- /**
- * Add a file within the archive from a file
- *
- * @param string $filename the path to the file we want to add
- * @param string $localname the local path to the file in the archive
- * @return true if the file has been successful added
- */
- public function addFile($filename, $localname = null)
- {
- if ((file_exists($this->filename) && !is_writable($this->filename))
- || !file_exists($filename)) {
- return false;
- }
- return $this->zipArchive->addFile($filename, $localname);
+ /**
+ * Add a file within the archive from a string.
+ *
+ * @param string $localname
+ * The local path to the file in the archive.
+ * @param string $contents
+ * The content of the file.
+ *
+ * @return bool
+ * TRUE if the file has been successfully added.
+ */
+ public function addFromString($localname, $contents) {
+ if (file_exists($this->filename) && !is_writable($this->filename)) {
+ return FALSE;
}
+ return $this->zipArchive->addFromString($localname, $contents);
+ }
- /**
- * Close the Zip archive
- * @return true
- */
- public function close()
- {
- return $this->zipArchive->close();
+ /**
+ * Add a file within the archive from a file.
+ *
+ * @param string $filename
+ * The path to the file we want to add.
+ * @param string|null $localname
+ * The local path to the file in the archive.
+ *
+ * @return bool
+ * TRUE if the file has been successfully added.
+ */
+ public function addFile($filename, $localname = NULL) {
+ if ((file_exists($this->filename) && !is_writable($this->filename))
+ || !file_exists($filename)) {
+ return FALSE;
}
+ return $this->zipArchive->addFile($filename, $localname);
+ }
+
+ /**
+ * Close the Zip archive.
+ *
+ * @return bool
+ * TRUE if the archive was closed successfully.
+ */
+ public function close() {
+ return $this->zipArchive->close();
+ }
+
}
diff --git a/src/Zip/ZipInterface.php b/src/Zip/ZipInterface.php
old mode 100644
new mode 100755
index 5da90f7..7d831de
--- a/src/Zip/ZipInterface.php
+++ b/src/Zip/ZipInterface.php
@@ -3,58 +3,72 @@
namespace Odtphp\Zip;
/**
- * Interface for Zip libraries used in odtPHP
- * You need PHP 5.2 at least
- * You need Zip Extension or PclZip library
- * Encoding : ISO-8859-1
- * Last commit by $Author: neveldo $
- * Date - $Date: 2009-05-29 10:05:11 +0200 (ven., 29 mai 2009) $
- * SVN Revision - $Rev: 28 $
- * Id : $Id: odf.php 28 2009-05-29 08:05:11Z neveldo $
+ * Interface for Zip libraries used in ODT PHP.
*
- * @copyright GPL License 2008 - Julien Pauli - Cyril PIERRE de GEYER - Anaska (http://www.anaska.com)
- * @license http://www.gnu.org/copyleft/gpl.html GPL License
+ * You need PHP 8.1 at least.
+ * You need Zip Extension or PclZip library.
+ * Encoding: ISO-8859-1.
+ *
+ * @copyright GPL License 2008 - Julien Pauli - Cyril PIERRE de GEYER - Anaska (http://www.anaska.com)
+ * @license http://www.gnu.org/copyleft/gpl.html GPL License
* @version 1.3
*/
-interface ZipInterface
-{
- /**
- * Open a Zip archive
- *
- * @param string $filename the name of the archive to open
- * @return true if openning has succeeded
- */
- public function open($filename);
-
- /**
- * Retrieve the content of a file within the archive from its name
- *
- * @param string $name the name of the file to extract
- * @return the content of the file in a string
- */
- public function getFromName($name);
-
- /**
- * Add a file within the archive from a string
- *
- * @param string $localname the local path to the file in the archive
- * @param string $contents the content of the file
- * @return true if the file has been successful added
- */
- public function addFromString($localname, $contents);
-
- /**
- * Add a file within the archive from a file
- *
- * @param string $filename the path to the file we want to add
- * @param string $localname the local path to the file in the archive
- * @return true if the file has been successful added
- */
- public function addFile($filename, $localname = null);
-
- /**
- * Close the Zip archive
- * @return true
- */
- public function close();
+interface ZipInterface {
+
+ /**
+ * Open a Zip archive.
+ *
+ * @param string $filename
+ * The name of the archive to open.
+ *
+ * @return bool
+ * TRUE if opening has succeeded.
+ */
+ public function open($filename);
+
+ /**
+ * Retrieve the content of a file within the archive from its name.
+ *
+ * @param string $name
+ * The name of the file to extract.
+ *
+ * @return string|bool
+ * The content of the file as a string, or FALSE if retrieval fails.
+ */
+ public function getFromName($name);
+
+ /**
+ * Add a file within the archive from a string.
+ *
+ * @param string $localname
+ * The local path to the file in the archive.
+ * @param string $contents
+ * The content of the file.
+ *
+ * @return bool
+ * TRUE if the file has been successfully added.
+ */
+ public function addFromString($localname, $contents);
+
+ /**
+ * Add a file within the archive from a file.
+ *
+ * @param string $filename
+ * The path to the file we want to add.
+ * @param string|null $localname
+ * The local path to the file in the archive.
+ *
+ * @return bool
+ * TRUE if the file has been successfully added.
+ */
+ public function addFile($filename, $localname = NULL);
+
+ /**
+ * Close the Zip archive.
+ *
+ * @return bool
+ * TRUE if the archive was closed successfully.
+ */
+ public function close();
+
}
diff --git a/tests/src/Basic1Test.php b/tests/src/Basic1Test.php
new file mode 100755
index 0000000..d42095f
--- /dev/null
+++ b/tests/src/Basic1Test.php
@@ -0,0 +1,56 @@
+odfPhpZipConfig();
+ $gold_dir = 'gold_phpzip';
+ $type_name = 'PhpZip';
+ }
+ else {
+ $config = $this->odfPclZipConfig();
+ $gold_dir = 'gold_pclzip';
+ $type_name = 'PclZip';
+ }
+
+ $input_file = __DIR__ . '/files/input/BasicTest1.odt';
+ $odf = new Odf($input_file, $config);
+
+ $odf->setVars('titre',
+ 'PHP: Hypertext Preprocessor');
+
+ $message = "PHP (sigle de PHP: Hypertext Preprocessor), est un langage de scripts libre
+principalement utilisé pour produire des pages Web dynamiques via un serveur HTTP, mais
+pouvant également fonctionner comme n'importe quel langage interprété de façon locale,
+en exécutant les programmes en ligne de commande.";
+
+ $odf->setVars('message', $message, TRUE, 'UTF-8');
+
+ $output_name = __DIR__ . "/files/output/BasicTest1" . $type_name . "Output.odt";
+ // We export the file
+ $odf->saveToDisk($output_name);
+
+ // print("\nComparing files:\n $output_name\n files/$gold_dir/BasicTest1Gold.odt\n");
+ $this->assertTrue($this->odtFilesAreIdentical($output_name, __DIR__ . "/files/$gold_dir/BasicTest1Gold.odt"));
+
+ unlink($output_name);
+ }
+
+ public function testBasicPclZip1(): void {
+ $this->basic1(self::PCLZIP_TYPE);
+ }
+
+ public function testBasicPhpZip1(): void {
+ $this->basic1(self::PHPZIP_TYPE);
+ }
+
+}
diff --git a/tests/src/Basic2Test.php b/tests/src/Basic2Test.php
new file mode 100755
index 0000000..5e957da
--- /dev/null
+++ b/tests/src/Basic2Test.php
@@ -0,0 +1,54 @@
+odfPhpZipConfig();
+ $gold_dir = 'gold_phpzip';
+ $type_name = 'PhpZip';
+ }
+ else {
+ $config = $this->odfPclZipConfig();
+ $gold_dir = 'gold_pclzip';
+ $type_name = 'PclZip';
+ }
+
+ $input_file = __DIR__ . '/files/input/BasicTest2.odt';
+ $odf = new Odf($input_file, $config);
+
+ $odf->setVars('titre', 'PHP: Hypertext Preprocessor');
+
+ $message = "PHP (sigle de PHP: Hypertext Preprocessor), est un langage de scripts libre
+principalement utilisé pour produire des pages Web dynamiques via un serveur HTTP, mais
+pouvant également fonctionner comme n'importe quel langage interprété de façon locale,
+en exécutant les programmes en ligne de commande.";
+
+ $odf->setVars('message', $message, TRUE, 'UTF-8');
+
+ $odf->setImage('image', __DIR__ . '/files/images/anaska.jpg');
+
+ $output_name = __DIR__ . "/files/output/BasicTest2" . $type_name . "Output.odt";
+ $odf->saveToDisk($output_name);
+
+ $this->assertTrue($this->odtFilesAreIdentical($output_name, __DIR__ . "/files/$gold_dir/BasicTest2Gold.odt"));
+
+ unlink($output_name);
+ }
+
+ public function testBasicPclZip2(): void {
+ $this->basic2(self::PCLZIP_TYPE);
+ }
+
+ public function testBasicPhpZip2(): void {
+ $this->basic2(self::PHPZIP_TYPE);
+ }
+}
diff --git a/tests/src/BasicTest1.odt b/tests/src/BasicTest1.odt
new file mode 100755
index 0000000..05eab71
Binary files /dev/null and b/tests/src/BasicTest1.odt differ
diff --git a/tests/src/ConfigTest.php b/tests/src/ConfigTest.php
new file mode 100755
index 0000000..97a232a
--- /dev/null
+++ b/tests/src/ConfigTest.php
@@ -0,0 +1,45 @@
+expectException(\TypeError::class);
+ $this->expectExceptionMessage('Argument #2 ($config) must be of type array');
+ new Odf(__DIR__ . '/files/input/BasicTest1.odt', 'invalid');
+ }
+
+ public function testCustomDelimiters(): void {
+ $config = array_merge($this->odfPhpZipConfig(), [
+ 'DELIMITER_LEFT' => '[[',
+ 'DELIMITER_RIGHT' => ']]'
+ ]);
+
+ $odf = new Odf(__DIR__ . "/files/input/ConfigTest.odt", $config);
+ $odf->setVars('test_var', 'test value');
+
+ $output_name = __DIR__ . "/files/output/ConfigTestOutput.odt";
+ $odf->saveToDisk($output_name);
+
+ $this->assertTrue($this->odtFilesAreIdentical($output_name, __DIR__ . "/files/gold_phpzip/ConfigTestGold.odt"));
+ unlink($output_name);
+ }
+
+ public function testInvalidTempPath(): void {
+ $config = array_merge($this->odfPhpZipConfig(), [
+ 'PATH_TO_TMP' => '/nonexistent/path'
+ ]);
+
+ $this->expectException(OdfException::class);
+ new Odf(__DIR__ . "/files/input/BasicTest1.odt", $config);
+ }
+}
diff --git a/tests/src/EdgeCaseTest.php b/tests/src/EdgeCaseTest.php
new file mode 100755
index 0000000..ec09f0c
--- /dev/null
+++ b/tests/src/EdgeCaseTest.php
@@ -0,0 +1,177 @@
+odfPhpZipConfig();
+ $gold_dir = 'gold_phpzip';
+ $type_name = 'PhpZip';
+ }
+ else {
+ $config = $this->odfPclZipConfig();
+ $gold_dir = 'gold_pclzip';
+ $type_name = 'PclZip';
+ }
+
+ switch ($testName) {
+ case 'LargeVariableSubstitution':
+ $input_file = __DIR__ . '/files/input/LargeVariableTest.odt';
+ $output_name = __DIR__ . '/files/output/LargeVariableTest' . $type_name . 'Output.odt';
+ $gold_file = __DIR__ . '/files/' . $gold_dir . '/LargeVariableTestGold.odt';
+
+ $odf = new Odf($input_file, $config);
+
+ // Generate a large text block
+ $largeText = str_repeat("This is a large text block with many repetitions. ", 1000);
+
+ $odf->setVars('large_content', $largeText, true, 'UTF-8');
+
+ $odf->saveToDisk($output_name);
+
+ $this->assertTrue($this->odtFilesAreIdentical($output_name, $gold_file));
+
+ unlink($output_name);
+ break;
+
+ case 'ComplexSegmentMerging':
+ $input_file = __DIR__ . '/files/input/NestedSegmentTest.odt';
+ $output_name = __DIR__ . '/files/output/NestedSegmentTest' . $type_name . 'Output.odt';
+ $gold_file = __DIR__ . '/files/' . $gold_dir . '/NestedSegmentTestGold.odt';
+
+ $odf = new Odf($input_file, $config);
+
+ // Create a nested data structure
+ $departments = [
+ [
+ 'name' => 'Engineering',
+ 'employees' => [
+ ['name' => 'Alice', 'role' => 'Senior Developer'],
+ ['name' => 'Bob', 'role' => 'Junior Developer']
+ ]
+ ],
+ [
+ 'name' => 'Marketing',
+ 'employees' => [
+ ['name' => 'Charlie', 'role' => 'Marketing Manager'],
+ ['name' => 'David', 'role' => 'Content Strategist']
+ ]
+ ]
+ ];
+
+ $departmentSegment = $odf->setSegment('departments');
+
+ foreach ($departments as $department) {
+ $departmentSegment->setVars('department_name', $department['name']);
+
+ $employeeSegment = $departmentSegment->setSegment('employees');
+
+ foreach ($department['employees'] as $employee) {
+ $employeeSegment->setVars('employee_name', $employee['name']);
+ $employeeSegment->setVars('employee_role', $employee['role']);
+ $employeeSegment->merge();
+ }
+ $departmentSegment->merge();
+ }
+ $odf->mergeSegment($departmentSegment);
+ $odf->saveToDisk($output_name);
+
+ $this->assertTrue($this->odtFilesAreIdentical($output_name, $gold_file));
+
+ unlink($output_name);
+ break;
+
+ case 'SpecialCharacterEncoding':
+ $input_file = __DIR__ . '/files/input/EncodingTest.odt';
+ $output_name = __DIR__ . '/files/output/EncodingTest' . $type_name . 'Output.odt';
+ $gold_file = __DIR__ . '/files/' . $gold_dir . '/EncodingTestGold.odt';
+
+ $specialCharText = "Special characters: éèà €ñ¿ § ® © µ";
+
+ $odf = new Odf($input_file, $config);
+
+ $odf->setVars('special_chars', $specialCharText, true, 'UTF-8');
+
+ $odf->saveToDisk($output_name);
+
+ $this->assertTrue($this->odtFilesAreIdentical($output_name, $gold_file));
+
+ unlink($output_name);
+ break;
+
+ case 'AdvancedImageInsertion':
+ $input_file = __DIR__ . '/files/input/ImageTest.odt';
+ $output_name = __DIR__ . '/files/output/AdvancedImageTest' . $type_name . 'Output.odt';
+ $gold_file = __DIR__ . '/files/' . $gold_dir . '/AdvancedImageTestGold.odt';
+
+ $odf = new Odf($input_file, $config);
+
+ // Test different image types and sizes
+ $images = [
+ 'small_png' => __DIR__ . '/files/images/voronoi_sphere.png',
+ 'large_jpg' => __DIR__ . '/files/images/test.jpg',
+ 'transparent_gif' => __DIR__ . '/files/images/circle_transparent.gif'
+ ];
+
+ foreach ($images as $key => $imagePath) {
+ $odf->setImage($key, $imagePath);
+ }
+
+ $odf->saveToDisk($output_name);
+
+ $this->assertTrue($this->odtFilesAreIdentical($output_name, $gold_file));
+
+ unlink($output_name);
+ break;
+ }
+ }
+
+ public function testLargeVariableSubstitutionPclZip(): void {
+ $this->edgeCase(self::PCLZIP_TYPE, 'LargeVariableSubstitution');
+ }
+
+ public function testLargeVariableSubstitutionPhpZip(): void {
+ $this->edgeCase(self::PHPZIP_TYPE, 'LargeVariableSubstitution');
+ }
+
+ public function testComplexSegmentMergingPclZip(): void {
+ $this->edgeCase(self::PCLZIP_TYPE, 'ComplexSegmentMerging');
+ }
+
+ public function testComplexSegmentMergingPhpZip(): void {
+ $this->edgeCase(self::PHPZIP_TYPE, 'ComplexSegmentMerging');
+ }
+
+ public function testSpecialCharacterEncodingPclZip(): void {
+ $this->edgeCase(self::PCLZIP_TYPE, 'SpecialCharacterEncoding');
+ }
+
+ public function testSpecialCharacterEncodingPhpZip(): void {
+ $this->edgeCase(self::PHPZIP_TYPE, 'SpecialCharacterEncoding');
+ }
+
+ public function testAdvancedImageInsertionPclZip(): void {
+ $this->edgeCase(self::PCLZIP_TYPE, 'AdvancedImageInsertion');
+ }
+
+ public function testAdvancedImageInsertionPhpZip(): void {
+ $this->edgeCase(self::PHPZIP_TYPE, 'AdvancedImageInsertion');
+ }
+
+ /**
+ * Test handling of invalid template files.
+ */
+ public function testInvalidTemplateHandling(): void {
+ $this->expectException(\Odtphp\Exceptions\OdfException::class);
+ $this->expectExceptionMessage("File '" . __DIR__ . "/files/input/NonexistentTemplate.odt' does not exist");
+ new Odf(__DIR__ . '/files/input/NonexistentTemplate.odt');
+ }
+}
diff --git a/tests/src/ImageTest.php b/tests/src/ImageTest.php
new file mode 100755
index 0000000..2a761a8
--- /dev/null
+++ b/tests/src/ImageTest.php
@@ -0,0 +1,40 @@
+odfPclZipConfig();
+ $odf = new Odf(__DIR__ . "/files/input/ImageTest.odt", $config);
+ $odf->setImage('test_image', __DIR__ . "/files/images/voronoi_sphere.png");
+ $output_name = __DIR__ . "/files/output/ImageTestOutput.odt";
+ $odf->saveToDisk($output_name);
+ $this->assertFileExists($output_name);
+ $this->assertTrue($this->odtFilesAreIdentical($output_name, __DIR__ . "/files/gold_phpzip/ImageTestGold.odt"));
+ unlink($output_name);
+ }
+
+ public function testImageResizing(): void {
+ $config = $this->odfPclZipConfig();
+ $odf = new Odf(__DIR__ . "/files/input/ImageTest.odt", $config);
+ $odf->setImage('test_image', __DIR__ . "/files/images/test.jpg", -1, 100, 100);
+ $output_name = __DIR__ . "/files/output/ImageTestResizedOutput.odt";
+ $odf->saveToDisk($output_name);
+ $this->assertFileExists($output_name);
+ $this->assertTrue($this->odtFilesAreIdentical($output_name, __DIR__ . "/files/gold_phpzip/ImageTestResizedGold.odt"));
+ unlink($output_name);
+ }
+
+ public function testInvalidImagePath(): void {
+ $config = $this->odfPclZipConfig();
+ $odf = new Odf(__DIR__ . "/files/input/ImageTest.odt", $config);
+ $this->expectException(OdfException::class);
+ $odf->setImage('test_image', __DIR__ . "/files/images/nonexistent.png");
+ }
+}
diff --git a/tests/src/OdtTestCase.php b/tests/src/OdtTestCase.php
new file mode 100755
index 0000000..d6295e3
--- /dev/null
+++ b/tests/src/OdtTestCase.php
@@ -0,0 +1,100 @@
+ \Odtphp\Zip\PhpZipProxy::class,
+ 'DELIMITER_LEFT' => '{',
+ 'DELIMITER_RIGHT' => '}',
+ ];
+ }
+
+ protected function odfPclZipConfig() {
+ return [
+ 'ZIP_PROXY' => \Odtphp\Zip\PclZipProxy::class,
+ 'DELIMITER_LEFT' => '{',
+ 'DELIMITER_RIGHT' => '}',
+ ];
+ }
+
+
+ protected function extractText($filename) {
+ $file_parts = explode('.', $filename);
+ $ext = end($file_parts);
+ if ($ext == 'docx') {
+ $dataFile = "word/document.xml";
+ }
+ else {
+ $dataFile = "content.xml";
+ }
+ $zip = new \ZipArchive;
+ if (TRUE === $zip->open($filename)) {
+ if (($index = $zip->locateName($dataFile)) !== FALSE) {
+ // Index found! Now read it to a string
+ $text = $zip->getFromIndex($index);
+ // Load XML from a string
+ // Ignore errors and warnings
+ $doc = new DOMDocument();
+ $rcode = $doc->loadXML($text,
+ LIBXML_NOENT | LIBXML_XINCLUDE | LIBXML_NOERROR | LIBXML_NOWARNING);
+ // Remove XML formatting tags and return the text
+ return strip_tags($doc->saveXML());
+ }
+ // Close the archive file
+ $zip->close();
+ }
+ // In case of failure return a message
+ return "File not found";
+ }
+
+
+ function odtFilesAreIdentical($file1, $file2)
+ {
+ // Ensure both files exist
+ if (!file_exists($file1)) {
+ throw new Exception("File $file1 does not exist.");
+ }
+
+ if (!file_exists($file2)) {
+ throw new Exception("File $file2 does not exist.");
+ }
+
+ // Open the first .odt file as a ZIP archive and extract content.xml
+ $zip1 = new \ZipArchive;
+ $zip2 = new \ZipArchive;
+
+ if ($zip1->open($file1) !== true) {
+ throw new Exception("Unable to open file: " . $file1);
+ }
+
+ if ($zip2->open($file2) !== true) {
+ $zip1->close();
+ throw new Exception("Unable to open file: " . $file2);
+ }
+
+ // Read the content.xml files from both .odt files
+ $content1 = $zip1->getFromName("content.xml");
+ $content2 = $zip2->getFromName("content.xml");
+
+ // Close the archives
+ $zip1->close();
+ $zip2->close();
+
+ // Compare the contents of content.xml
+ return $content1 === $content2;
+ }
+}
diff --git a/tests/src/VariableTest.php b/tests/src/VariableTest.php
new file mode 100755
index 0000000..ffcbd99
--- /dev/null
+++ b/tests/src/VariableTest.php
@@ -0,0 +1,46 @@
+odfPhpZipConfig();
+ $odf = new Odf(__DIR__ . "/files/input/VariableTest.odt", $config);
+
+ $this->assertTrue($odf->variableExists('test_var'));
+ $this->assertFalse($odf->variableExists('nonexistent_var'));
+ }
+
+ public function testSpecialCharacterEncoding(): void {
+ $config = $this->odfPhpZipConfig();
+ $odf = new Odf(__DIR__ . "/files/input/VariableTest.odt", $config);
+
+ $specialChars = "<>&'\"";
+ $odf->setVars('test_var', $specialChars, true);
+
+ $output_name = __DIR__ . "/files/output/VariableTestOutputSpecialChars.odt";
+ $odf->saveToDisk($output_name);
+
+ $this->assertTrue($this->odtFilesAreIdentical($output_name, __DIR__ . "/files/gold_phpzip/VariableTestSpecialCharsGold.odt"));
+ unlink($output_name);
+ }
+
+ public function testMultilineText(): void {
+ $config = $this->odfPhpZipConfig();
+ $odf = new Odf(__DIR__ . "/files/input/VariableTest.odt", $config);
+
+ $multiline = "Line 1\nLine 2\nLine 3";
+ $odf->setVars('test_var', $multiline, true);
+
+ $output_name = __DIR__ . "/files/output/VariableTestOutputMultiline.odt";
+ $odf->saveToDisk($output_name);
+
+ $this->assertTrue($this->odtFilesAreIdentical($output_name, __DIR__ . "/files/gold_phpzip/VariableTestMultilineGold.odt"));
+ unlink($output_name);
+ }
+}
diff --git a/tests/src/files/gold_pclzip/AdvancedImageTestGold.odt b/tests/src/files/gold_pclzip/AdvancedImageTestGold.odt
new file mode 100755
index 0000000..b0045f6
Binary files /dev/null and b/tests/src/files/gold_pclzip/AdvancedImageTestGold.odt differ
diff --git a/tests/src/files/gold_pclzip/BasicTest1Gold.odt b/tests/src/files/gold_pclzip/BasicTest1Gold.odt
new file mode 100755
index 0000000..9cda417
Binary files /dev/null and b/tests/src/files/gold_pclzip/BasicTest1Gold.odt differ
diff --git a/tests/src/files/gold_pclzip/BasicTest2Gold.odt b/tests/src/files/gold_pclzip/BasicTest2Gold.odt
new file mode 100755
index 0000000..af50d9c
Binary files /dev/null and b/tests/src/files/gold_pclzip/BasicTest2Gold.odt differ
diff --git a/tests/src/files/gold_pclzip/ConfigTestGold.odt b/tests/src/files/gold_pclzip/ConfigTestGold.odt
new file mode 100755
index 0000000..5fac55e
Binary files /dev/null and b/tests/src/files/gold_pclzip/ConfigTestGold.odt differ
diff --git a/tests/src/files/gold_pclzip/EncodingTestGold.odt b/tests/src/files/gold_pclzip/EncodingTestGold.odt
new file mode 100755
index 0000000..7243f7a
Binary files /dev/null and b/tests/src/files/gold_pclzip/EncodingTestGold.odt differ
diff --git a/tests/src/files/gold_pclzip/ImageTestGold.odt b/tests/src/files/gold_pclzip/ImageTestGold.odt
new file mode 100755
index 0000000..ad10489
Binary files /dev/null and b/tests/src/files/gold_pclzip/ImageTestGold.odt differ
diff --git a/tests/src/files/gold_pclzip/ImageTestOutputGold.odt b/tests/src/files/gold_pclzip/ImageTestOutputGold.odt
new file mode 100755
index 0000000..ad10489
Binary files /dev/null and b/tests/src/files/gold_pclzip/ImageTestOutputGold.odt differ
diff --git a/tests/src/files/gold_pclzip/ImageTestResizedGold.odt b/tests/src/files/gold_pclzip/ImageTestResizedGold.odt
new file mode 100755
index 0000000..1e3360f
Binary files /dev/null and b/tests/src/files/gold_pclzip/ImageTestResizedGold.odt differ
diff --git a/tests/src/files/gold_pclzip/ImageTestResizedOutputGold.odt b/tests/src/files/gold_pclzip/ImageTestResizedOutputGold.odt
new file mode 100755
index 0000000..1e3360f
Binary files /dev/null and b/tests/src/files/gold_pclzip/ImageTestResizedOutputGold.odt differ
diff --git a/tests/src/files/gold_pclzip/LargeVariableTestGold.odt b/tests/src/files/gold_pclzip/LargeVariableTestGold.odt
new file mode 100755
index 0000000..86562d4
Binary files /dev/null and b/tests/src/files/gold_pclzip/LargeVariableTestGold.odt differ
diff --git a/tests/src/files/gold_pclzip/NestedSegmentTestGold.odt b/tests/src/files/gold_pclzip/NestedSegmentTestGold.odt
new file mode 100755
index 0000000..a87b007
Binary files /dev/null and b/tests/src/files/gold_pclzip/NestedSegmentTestGold.odt differ
diff --git a/tests/src/files/gold_pclzip/VariableTestGold.odt b/tests/src/files/gold_pclzip/VariableTestGold.odt
new file mode 100755
index 0000000..5100ff7
--- /dev/null
+++ b/tests/src/files/gold_pclzip/VariableTestGold.odt
@@ -0,0 +1,8 @@
+
+
+
+
+ <>&'"
+
+
+
diff --git a/tests/src/files/gold_phpzip/AdvancedImageTestGold.odt b/tests/src/files/gold_phpzip/AdvancedImageTestGold.odt
new file mode 100755
index 0000000..b0045f6
Binary files /dev/null and b/tests/src/files/gold_phpzip/AdvancedImageTestGold.odt differ
diff --git a/tests/src/files/gold_phpzip/BasicTest1Gold.odt b/tests/src/files/gold_phpzip/BasicTest1Gold.odt
new file mode 100755
index 0000000..b864541
Binary files /dev/null and b/tests/src/files/gold_phpzip/BasicTest1Gold.odt differ
diff --git a/tests/src/files/gold_phpzip/BasicTest2Gold.odt b/tests/src/files/gold_phpzip/BasicTest2Gold.odt
new file mode 100755
index 0000000..af50d9c
Binary files /dev/null and b/tests/src/files/gold_phpzip/BasicTest2Gold.odt differ
diff --git a/tests/src/files/gold_phpzip/ConfigTestGold.odt b/tests/src/files/gold_phpzip/ConfigTestGold.odt
new file mode 100755
index 0000000..5fac55e
Binary files /dev/null and b/tests/src/files/gold_phpzip/ConfigTestGold.odt differ
diff --git a/tests/src/files/gold_phpzip/EncodingTestGold.odt b/tests/src/files/gold_phpzip/EncodingTestGold.odt
new file mode 100755
index 0000000..5a7b254
Binary files /dev/null and b/tests/src/files/gold_phpzip/EncodingTestGold.odt differ
diff --git a/tests/src/files/gold_phpzip/EncodingTestPhpGold.odt b/tests/src/files/gold_phpzip/EncodingTestPhpGold.odt
new file mode 100755
index 0000000..7243f7a
Binary files /dev/null and b/tests/src/files/gold_phpzip/EncodingTestPhpGold.odt differ
diff --git a/tests/src/files/gold_phpzip/ImageTestGold.odt b/tests/src/files/gold_phpzip/ImageTestGold.odt
new file mode 100755
index 0000000..bbd94b6
Binary files /dev/null and b/tests/src/files/gold_phpzip/ImageTestGold.odt differ
diff --git a/tests/src/files/gold_phpzip/ImageTestResizedGold.odt b/tests/src/files/gold_phpzip/ImageTestResizedGold.odt
new file mode 100755
index 0000000..c91340a
Binary files /dev/null and b/tests/src/files/gold_phpzip/ImageTestResizedGold.odt differ
diff --git a/tests/src/files/gold_phpzip/LargeVariableTestGold.odt b/tests/src/files/gold_phpzip/LargeVariableTestGold.odt
new file mode 100755
index 0000000..86562d4
Binary files /dev/null and b/tests/src/files/gold_phpzip/LargeVariableTestGold.odt differ
diff --git a/tests/src/files/gold_phpzip/NestedSegmentTestGold.odt b/tests/src/files/gold_phpzip/NestedSegmentTestGold.odt
new file mode 100755
index 0000000..a87b007
Binary files /dev/null and b/tests/src/files/gold_phpzip/NestedSegmentTestGold.odt differ
diff --git a/tests/src/files/gold_phpzip/VariableTestGold.odt b/tests/src/files/gold_phpzip/VariableTestGold.odt
new file mode 100755
index 0000000..5100ff7
--- /dev/null
+++ b/tests/src/files/gold_phpzip/VariableTestGold.odt
@@ -0,0 +1,8 @@
+
+
+
+
+ <>&'"
+
+
+
diff --git a/tests/src/files/gold_phpzip/VariableTestMultilineGold.odt b/tests/src/files/gold_phpzip/VariableTestMultilineGold.odt
new file mode 100755
index 0000000..adabf5a
Binary files /dev/null and b/tests/src/files/gold_phpzip/VariableTestMultilineGold.odt differ
diff --git a/tests/src/files/gold_phpzip/VariableTestSpecialCharsGold.odt b/tests/src/files/gold_phpzip/VariableTestSpecialCharsGold.odt
new file mode 100755
index 0000000..0b65492
Binary files /dev/null and b/tests/src/files/gold_phpzip/VariableTestSpecialCharsGold.odt differ
diff --git a/tests/src/files/images/anaska.gif b/tests/src/files/images/anaska.gif
new file mode 100755
index 0000000..1ea3f0e
Binary files /dev/null and b/tests/src/files/images/anaska.gif differ
diff --git a/tests/src/files/images/anaska.jpg b/tests/src/files/images/anaska.jpg
new file mode 100755
index 0000000..b02b4c4
Binary files /dev/null and b/tests/src/files/images/anaska.jpg differ
diff --git a/tests/src/files/images/circle_transparent.gif b/tests/src/files/images/circle_transparent.gif
new file mode 100755
index 0000000..9a8eeed
Binary files /dev/null and b/tests/src/files/images/circle_transparent.gif differ
diff --git a/tests/src/files/images/mysql.gif b/tests/src/files/images/mysql.gif
new file mode 100755
index 0000000..6520883
Binary files /dev/null and b/tests/src/files/images/mysql.gif differ
diff --git a/tests/src/files/images/overschot.jpg b/tests/src/files/images/overschot.jpg
new file mode 100755
index 0000000..e5bb4ed
Binary files /dev/null and b/tests/src/files/images/overschot.jpg differ
diff --git a/tests/src/files/images/php.gif b/tests/src/files/images/php.gif
new file mode 100755
index 0000000..f352c73
Binary files /dev/null and b/tests/src/files/images/php.gif differ
diff --git a/tests/src/files/images/test.jpg b/tests/src/files/images/test.jpg
new file mode 100755
index 0000000..4e03043
Binary files /dev/null and b/tests/src/files/images/test.jpg differ
diff --git a/tests/src/files/images/voronoi_sphere.png b/tests/src/files/images/voronoi_sphere.png
new file mode 100755
index 0000000..1685f87
Binary files /dev/null and b/tests/src/files/images/voronoi_sphere.png differ
diff --git a/tests/src/files/input/BasicTest1.odt b/tests/src/files/input/BasicTest1.odt
new file mode 100755
index 0000000..f1af2af
Binary files /dev/null and b/tests/src/files/input/BasicTest1.odt differ
diff --git a/tests/src/files/input/BasicTest2.odt b/tests/src/files/input/BasicTest2.odt
new file mode 100755
index 0000000..68ae776
Binary files /dev/null and b/tests/src/files/input/BasicTest2.odt differ
diff --git a/tests/src/files/input/ConfigTest.odt b/tests/src/files/input/ConfigTest.odt
new file mode 100755
index 0000000..480ce57
Binary files /dev/null and b/tests/src/files/input/ConfigTest.odt differ
diff --git a/tests/src/files/input/EncodingTest.odt b/tests/src/files/input/EncodingTest.odt
new file mode 100755
index 0000000..985fcbc
Binary files /dev/null and b/tests/src/files/input/EncodingTest.odt differ
diff --git a/tests/src/files/input/ImageTest.odt b/tests/src/files/input/ImageTest.odt
new file mode 100755
index 0000000..376df50
Binary files /dev/null and b/tests/src/files/input/ImageTest.odt differ
diff --git a/tests/src/files/input/LargeVariableTest.odt b/tests/src/files/input/LargeVariableTest.odt
new file mode 100755
index 0000000..5196e2d
Binary files /dev/null and b/tests/src/files/input/LargeVariableTest.odt differ
diff --git a/tests/src/files/input/LargeVariableTest1.odt b/tests/src/files/input/LargeVariableTest1.odt
new file mode 100755
index 0000000..e87b3ca
--- /dev/null
+++ b/tests/src/files/input/LargeVariableTest1.odt
@@ -0,0 +1 @@
+{large_content}
diff --git a/tests/src/files/input/NestedSegmentTest.odt b/tests/src/files/input/NestedSegmentTest.odt
new file mode 100755
index 0000000..7f477e5
Binary files /dev/null and b/tests/src/files/input/NestedSegmentTest.odt differ
diff --git a/tests/src/files/input/VariableTest.odt b/tests/src/files/input/VariableTest.odt
new file mode 100755
index 0000000..d72bac6
Binary files /dev/null and b/tests/src/files/input/VariableTest.odt differ
diff --git a/tests/src/files/output/.gitkeep b/tests/src/files/output/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/tests/tutoriel1.php b/tests/tutoriel1.php
deleted file mode 100755
index a03db63..0000000
--- a/tests/tutoriel1.php
+++ /dev/null
@@ -1,35 +0,0 @@
-setVars('titre', 'PHP: Hypertext PreprocessorPHP: Hypertext Preprocessor');
-
-$message = "PHP (sigle de PHP: Hypertext Preprocessor), est un langage de scripts libre
-principalement utilisé pour produire des pages Web dynamiques via un serveur HTTP, mais
-pouvant également fonctionner comme n'importe quel langage interprété de façon locale,
-en exécutant les programmes en ligne de commande.";
-
-$odf->setVars('message', $message);
-
-// We export the file
-$odf->exportAsAttachedFile();
diff --git a/tests/tutoriel2.php b/tests/tutoriel2.php
deleted file mode 100755
index bf77aa3..0000000
--- a/tests/tutoriel2.php
+++ /dev/null
@@ -1,34 +0,0 @@
-setVars('titre','Anaska formation');
-
-$message = "Anaska, leader Français de la formation informatique sur les technologies
-Open Source, propose un catalogue de plus de 50 formations dont certaines préparent
-aux certifications Linux, MySQL, PHP et PostgreSQL.";
-
-$odf->setVars('message', $message);
-
-$odf->setImage('image', './images/anaska.jpg');
-
-// We export the file
-$odf->exportAsAttachedFile();
-
-?>
\ No newline at end of file
diff --git a/tests/tutoriel3.php b/tests/tutoriel3.php
deleted file mode 100755
index 3aaef67..0000000
--- a/tests/tutoriel3.php
+++ /dev/null
@@ -1,53 +0,0 @@
-setVars('titre', 'Quelques articles de l\'encyclopédie Wikipédia');
-
-$message = "La force de cette encyclopédie en ligne réside dans son nombre important de
- contributeurs. Ce sont en effet des millions d'articles qui sont disponibles dans la langue
- de Shakespeare et des centaines de milliers d'autres dans de nombreuses langues dont
- le français, l'espagnol, l'italien, le turc ou encore l'allemand.";
-
-$odf->setVars('message', $message);
-
-$listeArticles = array(
- array( 'titre' => 'PHP',
- 'texte' => 'PHP (sigle de PHP: Hypertext Preprocessor), est un langage de scripts (...)',
- ),
- array( 'titre' => 'MySQL',
- 'texte' => 'MySQL est un système de gestion de base de données (SGDB). Selon le (...)',
- ),
- array( 'titre' => 'Apache',
- 'texte' => 'Apache HTTP Server, souvent appelé Apache, est un logiciel de serveur (...)',
- ),
-);
-
-$article = $odf->setSegment('articles');
-foreach($listeArticles AS $element) {
- $article->titreArticle($element['titre']);
- $article->texteArticle($element['texte']);
- $article->merge();
-}
-$odf->mergeSegment($article);
-
-// We export the file
-$odf->exportAsAttachedFile();
-
-?>
\ No newline at end of file
diff --git a/tests/tutoriel5.odt b/tests/tutoriel5.odt
deleted file mode 100755
index b9079f2..0000000
Binary files a/tests/tutoriel5.odt and /dev/null differ
diff --git a/tests/tutoriel6.php b/tests/tutoriel6.php
deleted file mode 100755
index e957409..0000000
--- a/tests/tutoriel6.php
+++ /dev/null
@@ -1,53 +0,0 @@
-setVars('titre', 'Quelques articles de l\'encyclopédie Wikipédia');
-
-$message = "La force de cette encyclopédie en ligne réside dans son nombre important de
- contributeurs. Ce sont en effet des millions d'articles qui sont disponibles dans la langue
- de Shakespeare et des centaines de milliers d'autres dans de nombreuses langues dont
- le français, l'espagnol, l'italien, le turc ou encore l'allemand.";
-
-$odf->setVars('message', $message);
-
-$listeArticles = array(
- array( 'titre' => 'PHP',
- 'texte' => 'PHP (sigle de PHP: Hypertext Preprocessor), est un langage de scripts (...)',
- ),
- array( 'titre' => 'MySQL',
- 'texte' => 'MySQL est un système de gestion de base de données (SGDB). Selon le (...)',
- ),
- array( 'titre' => 'Apache',
- 'texte' => 'Apache HTTP Server, souvent appelé Apache, est un logiciel de serveur (...)',
- ),
-);
-
-$article = $odf->setSegment('articles');
-foreach($listeArticles AS $element) {
- $article->titreArticle($element['titre']);
- $article->texteArticle($element['texte']);
- $article->merge();
-}
-$odf->mergeSegment($article);
-
-// We export the file
-$odf->exportAsAttachedFile();
-
-?>
\ No newline at end of file
diff --git a/tests/tutoriel7.php b/tests/tutoriel7.php
deleted file mode 100755
index a37b2bb..0000000
--- a/tests/tutoriel7.php
+++ /dev/null
@@ -1,39 +0,0 @@
- 'PhpZipProxy', // Make sure you have Zip extension loaded
- 'DELIMITER_LEFT' => '#', // Yan can also change delimiters
- 'DELIMITER_RIGHT' => '#'
-);
-
-$odf = new Odf("tutoriel7.odt", $config);
-
-$odf->setVars('titre', 'PHP: Hypertext PreprocessorPHP: Hypertext Preprocessor');
-
-$message = "PHP (sigle de PHP: Hypertext Preprocessor), est un langage de scripts libre
-principalement utilisé pour produire des pages Web dynamiques via un serveur HTTP, mais
-pouvant également fonctionner comme n'importe quel langage interprété de façon locale,
-en exécutant les programmes en ligne de commande.";
-
-$odf->setVars('message', $message);
-
-// We export the file
-$odf->exportAsAttachedFile();
-
-?>
\ No newline at end of file