mirror of
https://github.com/nextcloud/richdocuments.git
synced 2025-12-17 13:08:43 +01:00
refactor: remove composer dir and redirect autoloader
Signed-off-by: Elizabeth Danzberger <lizzy7128@tutanota.de>
This commit is contained in:
parent
6d0d75cc2d
commit
104de52d6e
39 changed files with 160 additions and 5469 deletions
|
|
@ -9,11 +9,14 @@
|
|||
},
|
||||
"allow-plugins": {
|
||||
"bamarni/composer-bin-plugin": true
|
||||
}
|
||||
},
|
||||
"optimize-autoloader": true,
|
||||
"autoloader-suffix": "Richdocuments"
|
||||
},
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
"ext-simplexml": "*"
|
||||
"ext-simplexml": "*",
|
||||
"mikehaertl/php-pdftk": "^0.13.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"roave/security-advisories": "dev-master",
|
||||
|
|
@ -41,6 +44,11 @@
|
|||
"cs:fix": "php-cs-fixer fix",
|
||||
"test:unit": "vendor/bin/phpunit -c tests/phpunit.xml"
|
||||
},
|
||||
"autoload" : {
|
||||
"psr-4": {
|
||||
"OCA\\Richdocuments\\": "./lib/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"OCP\\": "vendor/nextcloud/ocp/OCP"
|
||||
|
|
|
|||
144
composer.lock
generated
144
composer.lock
generated
|
|
@ -4,8 +4,148 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "e2fa29217850c4397522384d4e3de2bb",
|
||||
"packages": [],
|
||||
"content-hash": "8d223939222cf02033e9f429d7a6b0dc",
|
||||
"packages": [
|
||||
{
|
||||
"name": "mikehaertl/php-pdftk",
|
||||
"version": "0.13.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mikehaertl/php-pdftk.git",
|
||||
"reference": "3851b08c1027489e48387d7c14c27bc295d98239"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/mikehaertl/php-pdftk/zipball/3851b08c1027489e48387d7c14c27bc295d98239",
|
||||
"reference": "3851b08c1027489e48387d7c14c27bc295d98239",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"mikehaertl/php-shellcommand": "^1.6.3",
|
||||
"mikehaertl/php-tmpfile": "^1.1.0",
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": ">4.0 <9.4"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"mikehaertl\\pdftk\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Michael Haertl",
|
||||
"email": "haertl.mike@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "A PDF conversion and form utility based on pdftk.",
|
||||
"keywords": [
|
||||
"pdf",
|
||||
"pdftk"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/mikehaertl/php-pdftk/issues",
|
||||
"source": "https://github.com/mikehaertl/php-pdftk/tree/0.13.1"
|
||||
},
|
||||
"time": "2023-11-03T16:06:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "mikehaertl/php-shellcommand",
|
||||
"version": "1.7.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mikehaertl/php-shellcommand.git",
|
||||
"reference": "e79ea528be155ffdec6f3bf1a4a46307bb49e545"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/mikehaertl/php-shellcommand/zipball/e79ea528be155ffdec6f3bf1a4a46307bb49e545",
|
||||
"reference": "e79ea528be155ffdec6f3bf1a4a46307bb49e545",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">= 5.3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": ">4.0 <=9.4"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"mikehaertl\\shellcommand\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Michael Härtl",
|
||||
"email": "haertl.mike@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "An object oriented interface to shell commands",
|
||||
"keywords": [
|
||||
"shell"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/mikehaertl/php-shellcommand/issues",
|
||||
"source": "https://github.com/mikehaertl/php-shellcommand/tree/1.7.0"
|
||||
},
|
||||
"time": "2023-04-19T08:25:22+00:00"
|
||||
},
|
||||
{
|
||||
"name": "mikehaertl/php-tmpfile",
|
||||
"version": "1.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mikehaertl/php-tmpfile.git",
|
||||
"reference": "a5392bed91f67e2849a7cb24075d346468e1b1a8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/mikehaertl/php-tmpfile/zipball/a5392bed91f67e2849a7cb24075d346468e1b1a8",
|
||||
"reference": "a5392bed91f67e2849a7cb24075d346468e1b1a8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require-dev": {
|
||||
"php": ">=5.3.0",
|
||||
"phpunit/phpunit": ">4.0 <=9.4"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"mikehaertl\\tmp\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Michael Härtl",
|
||||
"email": "haertl.mike@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "A convenience class for temporary files",
|
||||
"keywords": [
|
||||
"files"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/mikehaertl/php-tmpfile/issues",
|
||||
"source": "https://github.com/mikehaertl/php-tmpfile/tree/1.3.0"
|
||||
},
|
||||
"time": "2024-10-14T16:12:48+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
{
|
||||
"name": "bamarni/composer-bin-plugin",
|
||||
|
|
|
|||
|
|
@ -1,25 +1,10 @@
|
|||
<?php
|
||||
|
||||
// autoload.php @generated by Composer
|
||||
declare(strict_types=1);
|
||||
|
||||
if (PHP_VERSION_ID < 50600) {
|
||||
if (!headers_sent()) {
|
||||
header('HTTP/1.1 500 Internal Server Error');
|
||||
}
|
||||
$err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
|
||||
if (!ini_get('display_errors')) {
|
||||
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
|
||||
fwrite(STDERR, $err);
|
||||
} elseif (!headers_sent()) {
|
||||
echo $err;
|
||||
}
|
||||
}
|
||||
trigger_error(
|
||||
$err,
|
||||
E_USER_ERROR
|
||||
);
|
||||
}
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/composer/autoload_real.php';
|
||||
|
||||
return ComposerAutoloaderInitRichdocuments::getLoader();
|
||||
require_once __DIR__ . '/../vendor/autoload.php';
|
||||
|
|
|
|||
|
|
@ -1,15 +0,0 @@
|
|||
{
|
||||
"config" : {
|
||||
"vendor-dir": ".",
|
||||
"optimize-autoloader": true,
|
||||
"autoloader-suffix": "Richdocuments"
|
||||
},
|
||||
"autoload" : {
|
||||
"psr-4": {
|
||||
"OCA\\Richdocuments\\": "../lib/"
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"mikehaertl/php-pdftk": "^0.13.1"
|
||||
}
|
||||
}
|
||||
158
composer/composer.lock
generated
158
composer/composer.lock
generated
|
|
@ -1,158 +0,0 @@
|
|||
{
|
||||
"_readme": [
|
||||
"This file locks the dependencies of your project to a known state",
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "b0ad6a743550ac81e64e6d88bfd62ae6",
|
||||
"packages": [
|
||||
{
|
||||
"name": "mikehaertl/php-pdftk",
|
||||
"version": "0.13.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mikehaertl/php-pdftk.git",
|
||||
"reference": "3851b08c1027489e48387d7c14c27bc295d98239"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/mikehaertl/php-pdftk/zipball/3851b08c1027489e48387d7c14c27bc295d98239",
|
||||
"reference": "3851b08c1027489e48387d7c14c27bc295d98239",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"mikehaertl/php-shellcommand": "^1.6.3",
|
||||
"mikehaertl/php-tmpfile": "^1.1.0",
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": ">4.0 <9.4"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"mikehaertl\\pdftk\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Michael Haertl",
|
||||
"email": "haertl.mike@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "A PDF conversion and form utility based on pdftk.",
|
||||
"keywords": [
|
||||
"pdf",
|
||||
"pdftk"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/mikehaertl/php-pdftk/issues",
|
||||
"source": "https://github.com/mikehaertl/php-pdftk/tree/0.13.1"
|
||||
},
|
||||
"time": "2023-11-03T16:06:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "mikehaertl/php-shellcommand",
|
||||
"version": "1.7.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mikehaertl/php-shellcommand.git",
|
||||
"reference": "e79ea528be155ffdec6f3bf1a4a46307bb49e545"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/mikehaertl/php-shellcommand/zipball/e79ea528be155ffdec6f3bf1a4a46307bb49e545",
|
||||
"reference": "e79ea528be155ffdec6f3bf1a4a46307bb49e545",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">= 5.3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": ">4.0 <=9.4"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"mikehaertl\\shellcommand\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Michael Härtl",
|
||||
"email": "haertl.mike@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "An object oriented interface to shell commands",
|
||||
"keywords": [
|
||||
"shell"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/mikehaertl/php-shellcommand/issues",
|
||||
"source": "https://github.com/mikehaertl/php-shellcommand/tree/1.7.0"
|
||||
},
|
||||
"time": "2023-04-19T08:25:22+00:00"
|
||||
},
|
||||
{
|
||||
"name": "mikehaertl/php-tmpfile",
|
||||
"version": "1.2.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mikehaertl/php-tmpfile.git",
|
||||
"reference": "70a5b70b17bc0d9666388e6a551ecc93d0b40a10"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/mikehaertl/php-tmpfile/zipball/70a5b70b17bc0d9666388e6a551ecc93d0b40a10",
|
||||
"reference": "70a5b70b17bc0d9666388e6a551ecc93d0b40a10",
|
||||
"shasum": ""
|
||||
},
|
||||
"require-dev": {
|
||||
"php": ">=5.3.0",
|
||||
"phpunit/phpunit": ">4.0 <=9.4"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"mikehaertl\\tmp\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Michael Härtl",
|
||||
"email": "haertl.mike@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "A convenience class for temporary files",
|
||||
"keywords": [
|
||||
"files"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/mikehaertl/php-tmpfile/issues",
|
||||
"source": "https://github.com/mikehaertl/php-tmpfile/tree/1.2.1"
|
||||
},
|
||||
"time": "2021-03-01T18:26:25+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": [],
|
||||
"plugin-api-version": "2.6.0"
|
||||
}
|
||||
|
|
@ -1,579 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer\Autoload;
|
||||
|
||||
/**
|
||||
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
|
||||
*
|
||||
* $loader = new \Composer\Autoload\ClassLoader();
|
||||
*
|
||||
* // register classes with namespaces
|
||||
* $loader->add('Symfony\Component', __DIR__.'/component');
|
||||
* $loader->add('Symfony', __DIR__.'/framework');
|
||||
*
|
||||
* // activate the autoloader
|
||||
* $loader->register();
|
||||
*
|
||||
* // to enable searching the include path (eg. for PEAR packages)
|
||||
* $loader->setUseIncludePath(true);
|
||||
*
|
||||
* In this example, if you try to use a class in the Symfony\Component
|
||||
* namespace or one of its children (Symfony\Component\Console for instance),
|
||||
* the autoloader will first look for the class under the component/
|
||||
* directory, and it will then fallback to the framework/ directory if not
|
||||
* found before giving up.
|
||||
*
|
||||
* This class is loosely based on the Symfony UniversalClassLoader.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
* @see https://www.php-fig.org/psr/psr-0/
|
||||
* @see https://www.php-fig.org/psr/psr-4/
|
||||
*/
|
||||
class ClassLoader
|
||||
{
|
||||
/** @var \Closure(string):void */
|
||||
private static $includeFile;
|
||||
|
||||
/** @var string|null */
|
||||
private $vendorDir;
|
||||
|
||||
// PSR-4
|
||||
/**
|
||||
* @var array<string, array<string, int>>
|
||||
*/
|
||||
private $prefixLengthsPsr4 = array();
|
||||
/**
|
||||
* @var array<string, list<string>>
|
||||
*/
|
||||
private $prefixDirsPsr4 = array();
|
||||
/**
|
||||
* @var list<string>
|
||||
*/
|
||||
private $fallbackDirsPsr4 = array();
|
||||
|
||||
// PSR-0
|
||||
/**
|
||||
* List of PSR-0 prefixes
|
||||
*
|
||||
* Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2')))
|
||||
*
|
||||
* @var array<string, array<string, list<string>>>
|
||||
*/
|
||||
private $prefixesPsr0 = array();
|
||||
/**
|
||||
* @var list<string>
|
||||
*/
|
||||
private $fallbackDirsPsr0 = array();
|
||||
|
||||
/** @var bool */
|
||||
private $useIncludePath = false;
|
||||
|
||||
/**
|
||||
* @var array<string, string>
|
||||
*/
|
||||
private $classMap = array();
|
||||
|
||||
/** @var bool */
|
||||
private $classMapAuthoritative = false;
|
||||
|
||||
/**
|
||||
* @var array<string, bool>
|
||||
*/
|
||||
private $missingClasses = array();
|
||||
|
||||
/** @var string|null */
|
||||
private $apcuPrefix;
|
||||
|
||||
/**
|
||||
* @var array<string, self>
|
||||
*/
|
||||
private static $registeredLoaders = array();
|
||||
|
||||
/**
|
||||
* @param string|null $vendorDir
|
||||
*/
|
||||
public function __construct($vendorDir = null)
|
||||
{
|
||||
$this->vendorDir = $vendorDir;
|
||||
self::initializeIncludeClosure();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, list<string>>
|
||||
*/
|
||||
public function getPrefixes()
|
||||
{
|
||||
if (!empty($this->prefixesPsr0)) {
|
||||
return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, list<string>>
|
||||
*/
|
||||
public function getPrefixesPsr4()
|
||||
{
|
||||
return $this->prefixDirsPsr4;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<string>
|
||||
*/
|
||||
public function getFallbackDirs()
|
||||
{
|
||||
return $this->fallbackDirsPsr0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<string>
|
||||
*/
|
||||
public function getFallbackDirsPsr4()
|
||||
{
|
||||
return $this->fallbackDirsPsr4;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string> Array of classname => path
|
||||
*/
|
||||
public function getClassMap()
|
||||
{
|
||||
return $this->classMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string> $classMap Class to filename map
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addClassMap(array $classMap)
|
||||
{
|
||||
if ($this->classMap) {
|
||||
$this->classMap = array_merge($this->classMap, $classMap);
|
||||
} else {
|
||||
$this->classMap = $classMap;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-0 directories for a given prefix, either
|
||||
* appending or prepending to the ones previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param list<string>|string $paths The PSR-0 root directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add($prefix, $paths, $prepend = false)
|
||||
{
|
||||
$paths = (array) $paths;
|
||||
if (!$prefix) {
|
||||
if ($prepend) {
|
||||
$this->fallbackDirsPsr0 = array_merge(
|
||||
$paths,
|
||||
$this->fallbackDirsPsr0
|
||||
);
|
||||
} else {
|
||||
$this->fallbackDirsPsr0 = array_merge(
|
||||
$this->fallbackDirsPsr0,
|
||||
$paths
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$first = $prefix[0];
|
||||
if (!isset($this->prefixesPsr0[$first][$prefix])) {
|
||||
$this->prefixesPsr0[$first][$prefix] = $paths;
|
||||
|
||||
return;
|
||||
}
|
||||
if ($prepend) {
|
||||
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||
$paths,
|
||||
$this->prefixesPsr0[$first][$prefix]
|
||||
);
|
||||
} else {
|
||||
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||
$this->prefixesPsr0[$first][$prefix],
|
||||
$paths
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-4 directories for a given namespace, either
|
||||
* appending or prepending to the ones previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param list<string>|string $paths The PSR-4 base directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addPsr4($prefix, $paths, $prepend = false)
|
||||
{
|
||||
$paths = (array) $paths;
|
||||
if (!$prefix) {
|
||||
// Register directories for the root namespace.
|
||||
if ($prepend) {
|
||||
$this->fallbackDirsPsr4 = array_merge(
|
||||
$paths,
|
||||
$this->fallbackDirsPsr4
|
||||
);
|
||||
} else {
|
||||
$this->fallbackDirsPsr4 = array_merge(
|
||||
$this->fallbackDirsPsr4,
|
||||
$paths
|
||||
);
|
||||
}
|
||||
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
|
||||
// Register directories for a new namespace.
|
||||
$length = strlen($prefix);
|
||||
if ('\\' !== $prefix[$length - 1]) {
|
||||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||
}
|
||||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||
$this->prefixDirsPsr4[$prefix] = $paths;
|
||||
} elseif ($prepend) {
|
||||
// Prepend directories for an already registered namespace.
|
||||
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||
$paths,
|
||||
$this->prefixDirsPsr4[$prefix]
|
||||
);
|
||||
} else {
|
||||
// Append directories for an already registered namespace.
|
||||
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||
$this->prefixDirsPsr4[$prefix],
|
||||
$paths
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-0 directories for a given prefix,
|
||||
* replacing any others previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param list<string>|string $paths The PSR-0 base directories
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set($prefix, $paths)
|
||||
{
|
||||
if (!$prefix) {
|
||||
$this->fallbackDirsPsr0 = (array) $paths;
|
||||
} else {
|
||||
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-4 directories for a given namespace,
|
||||
* replacing any others previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param list<string>|string $paths The PSR-4 base directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setPsr4($prefix, $paths)
|
||||
{
|
||||
if (!$prefix) {
|
||||
$this->fallbackDirsPsr4 = (array) $paths;
|
||||
} else {
|
||||
$length = strlen($prefix);
|
||||
if ('\\' !== $prefix[$length - 1]) {
|
||||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||
}
|
||||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns on searching the include path for class files.
|
||||
*
|
||||
* @param bool $useIncludePath
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setUseIncludePath($useIncludePath)
|
||||
{
|
||||
$this->useIncludePath = $useIncludePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be used to check if the autoloader uses the include path to check
|
||||
* for classes.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getUseIncludePath()
|
||||
{
|
||||
return $this->useIncludePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns off searching the prefix and fallback directories for classes
|
||||
* that have not been registered with the class map.
|
||||
*
|
||||
* @param bool $classMapAuthoritative
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setClassMapAuthoritative($classMapAuthoritative)
|
||||
{
|
||||
$this->classMapAuthoritative = $classMapAuthoritative;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should class lookup fail if not found in the current class map?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isClassMapAuthoritative()
|
||||
{
|
||||
return $this->classMapAuthoritative;
|
||||
}
|
||||
|
||||
/**
|
||||
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
|
||||
*
|
||||
* @param string|null $apcuPrefix
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setApcuPrefix($apcuPrefix)
|
||||
{
|
||||
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The APCu prefix in use, or null if APCu caching is not enabled.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getApcuPrefix()
|
||||
{
|
||||
return $this->apcuPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers this instance as an autoloader.
|
||||
*
|
||||
* @param bool $prepend Whether to prepend the autoloader or not
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register($prepend = false)
|
||||
{
|
||||
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
|
||||
|
||||
if (null === $this->vendorDir) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($prepend) {
|
||||
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
|
||||
} else {
|
||||
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||
self::$registeredLoaders[$this->vendorDir] = $this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters this instance as an autoloader.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function unregister()
|
||||
{
|
||||
spl_autoload_unregister(array($this, 'loadClass'));
|
||||
|
||||
if (null !== $this->vendorDir) {
|
||||
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the given class or interface.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
* @return true|null True if loaded, null otherwise
|
||||
*/
|
||||
public function loadClass($class)
|
||||
{
|
||||
if ($file = $this->findFile($class)) {
|
||||
$includeFile = self::$includeFile;
|
||||
$includeFile($file);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the path to the file where the class is defined.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
*
|
||||
* @return string|false The path if found, false otherwise
|
||||
*/
|
||||
public function findFile($class)
|
||||
{
|
||||
// class map lookup
|
||||
if (isset($this->classMap[$class])) {
|
||||
return $this->classMap[$class];
|
||||
}
|
||||
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
|
||||
return false;
|
||||
}
|
||||
if (null !== $this->apcuPrefix) {
|
||||
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
|
||||
if ($hit) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
$file = $this->findFileWithExtension($class, '.php');
|
||||
|
||||
// Search for Hack files if we are running on HHVM
|
||||
if (false === $file && defined('HHVM_VERSION')) {
|
||||
$file = $this->findFileWithExtension($class, '.hh');
|
||||
}
|
||||
|
||||
if (null !== $this->apcuPrefix) {
|
||||
apcu_add($this->apcuPrefix.$class, $file);
|
||||
}
|
||||
|
||||
if (false === $file) {
|
||||
// Remember that this class does not exist.
|
||||
$this->missingClasses[$class] = true;
|
||||
}
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently registered loaders keyed by their corresponding vendor directories.
|
||||
*
|
||||
* @return array<string, self>
|
||||
*/
|
||||
public static function getRegisteredLoaders()
|
||||
{
|
||||
return self::$registeredLoaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $class
|
||||
* @param string $ext
|
||||
* @return string|false
|
||||
*/
|
||||
private function findFileWithExtension($class, $ext)
|
||||
{
|
||||
// PSR-4 lookup
|
||||
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
|
||||
|
||||
$first = $class[0];
|
||||
if (isset($this->prefixLengthsPsr4[$first])) {
|
||||
$subPath = $class;
|
||||
while (false !== $lastPos = strrpos($subPath, '\\')) {
|
||||
$subPath = substr($subPath, 0, $lastPos);
|
||||
$search = $subPath . '\\';
|
||||
if (isset($this->prefixDirsPsr4[$search])) {
|
||||
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
|
||||
foreach ($this->prefixDirsPsr4[$search] as $dir) {
|
||||
if (file_exists($file = $dir . $pathEnd)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-4 fallback dirs
|
||||
foreach ($this->fallbackDirsPsr4 as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 lookup
|
||||
if (false !== $pos = strrpos($class, '\\')) {
|
||||
// namespaced class name
|
||||
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
|
||||
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
|
||||
} else {
|
||||
// PEAR-like class name
|
||||
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
|
||||
}
|
||||
|
||||
if (isset($this->prefixesPsr0[$first])) {
|
||||
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
|
||||
if (0 === strpos($class, $prefix)) {
|
||||
foreach ($dirs as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 fallback dirs
|
||||
foreach ($this->fallbackDirsPsr0 as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 include paths.
|
||||
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
private static function initializeIncludeClosure()
|
||||
{
|
||||
if (self::$includeFile !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope isolated include.
|
||||
*
|
||||
* Prevents access to $this/self from included files.
|
||||
*
|
||||
* @param string $file
|
||||
* @return void
|
||||
*/
|
||||
self::$includeFile = \Closure::bind(static function($file) {
|
||||
include $file;
|
||||
}, null, null);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,378 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer;
|
||||
|
||||
use Composer\Autoload\ClassLoader;
|
||||
use Composer\Semver\VersionParser;
|
||||
|
||||
/**
|
||||
* This class is copied in every Composer installed project and available to all
|
||||
*
|
||||
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
|
||||
*
|
||||
* To require its presence, you can require `composer-runtime-api ^2.0`
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class InstalledVersions
|
||||
{
|
||||
/**
|
||||
* @var mixed[]|null
|
||||
* @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
|
||||
*/
|
||||
private static $installed;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private static $installedIsLocalDir;
|
||||
|
||||
/**
|
||||
* @var bool|null
|
||||
*/
|
||||
private static $canGetVendors;
|
||||
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||
*/
|
||||
private static $installedByVendor = array();
|
||||
|
||||
/**
|
||||
* Returns a list of all package names which are present, either by being installed, replaced or provided
|
||||
*
|
||||
* @return string[]
|
||||
* @psalm-return list<string>
|
||||
*/
|
||||
public static function getInstalledPackages()
|
||||
{
|
||||
$packages = array();
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
$packages[] = array_keys($installed['versions']);
|
||||
}
|
||||
|
||||
if (1 === \count($packages)) {
|
||||
return $packages[0];
|
||||
}
|
||||
|
||||
return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all package names with a specific type e.g. 'library'
|
||||
*
|
||||
* @param string $type
|
||||
* @return string[]
|
||||
* @psalm-return list<string>
|
||||
*/
|
||||
public static function getInstalledPackagesByType($type)
|
||||
{
|
||||
$packagesByType = array();
|
||||
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
foreach ($installed['versions'] as $name => $package) {
|
||||
if (isset($package['type']) && $package['type'] === $type) {
|
||||
$packagesByType[] = $name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $packagesByType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given package is installed
|
||||
*
|
||||
* This also returns true if the package name is provided or replaced by another package
|
||||
*
|
||||
* @param string $packageName
|
||||
* @param bool $includeDevRequirements
|
||||
* @return bool
|
||||
*/
|
||||
public static function isInstalled($packageName, $includeDevRequirements = true)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (isset($installed['versions'][$packageName])) {
|
||||
return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given package satisfies a version constraint
|
||||
*
|
||||
* e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
|
||||
*
|
||||
* Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
|
||||
*
|
||||
* @param VersionParser $parser Install composer/semver to have access to this class and functionality
|
||||
* @param string $packageName
|
||||
* @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
|
||||
* @return bool
|
||||
*/
|
||||
public static function satisfies(VersionParser $parser, $packageName, $constraint)
|
||||
{
|
||||
$constraint = $parser->parseConstraints((string) $constraint);
|
||||
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
|
||||
|
||||
return $provided->matches($constraint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a version constraint representing all the range(s) which are installed for a given package
|
||||
*
|
||||
* It is easier to use this via isInstalled() with the $constraint argument if you need to check
|
||||
* whether a given version of a package is installed, and not just whether it exists
|
||||
*
|
||||
* @param string $packageName
|
||||
* @return string Version constraint usable with composer/semver
|
||||
*/
|
||||
public static function getVersionRanges($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$ranges = array();
|
||||
if (isset($installed['versions'][$packageName]['pretty_version'])) {
|
||||
$ranges[] = $installed['versions'][$packageName]['pretty_version'];
|
||||
}
|
||||
if (array_key_exists('aliases', $installed['versions'][$packageName])) {
|
||||
$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
|
||||
}
|
||||
if (array_key_exists('replaced', $installed['versions'][$packageName])) {
|
||||
$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
|
||||
}
|
||||
if (array_key_exists('provided', $installed['versions'][$packageName])) {
|
||||
$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
|
||||
}
|
||||
|
||||
return implode(' || ', $ranges);
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
|
||||
*/
|
||||
public static function getVersion($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($installed['versions'][$packageName]['version'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $installed['versions'][$packageName]['version'];
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
|
||||
*/
|
||||
public static function getPrettyVersion($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($installed['versions'][$packageName]['pretty_version'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $installed['versions'][$packageName]['pretty_version'];
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
|
||||
*/
|
||||
public static function getReference($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($installed['versions'][$packageName]['reference'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $installed['versions'][$packageName]['reference'];
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
|
||||
*/
|
||||
public static function getInstallPath($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
|
||||
*/
|
||||
public static function getRootPackage()
|
||||
{
|
||||
$installed = self::getInstalled();
|
||||
|
||||
return $installed[0]['root'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw installed.php data for custom implementations
|
||||
*
|
||||
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
|
||||
* @return array[]
|
||||
* @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
|
||||
*/
|
||||
public static function getRawData()
|
||||
{
|
||||
@trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
|
||||
|
||||
if (null === self::$installed) {
|
||||
// only require the installed.php file if this file is loaded from its dumped location,
|
||||
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
|
||||
if (substr(__DIR__, -8, 1) !== 'C') {
|
||||
self::$installed = include __DIR__ . '/installed.php';
|
||||
} else {
|
||||
self::$installed = array();
|
||||
}
|
||||
}
|
||||
|
||||
return self::$installed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw data of all installed.php which are currently loaded for custom implementations
|
||||
*
|
||||
* @return array[]
|
||||
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||
*/
|
||||
public static function getAllRawData()
|
||||
{
|
||||
return self::getInstalled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Lets you reload the static array from another file
|
||||
*
|
||||
* This is only useful for complex integrations in which a project needs to use
|
||||
* this class but then also needs to execute another project's autoloader in process,
|
||||
* and wants to ensure both projects have access to their version of installed.php.
|
||||
*
|
||||
* A typical case would be PHPUnit, where it would need to make sure it reads all
|
||||
* the data it needs from this class, then call reload() with
|
||||
* `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
|
||||
* the project in which it runs can then also use this class safely, without
|
||||
* interference between PHPUnit's dependencies and the project's dependencies.
|
||||
*
|
||||
* @param array[] $data A vendor/composer/installed.php data set
|
||||
* @return void
|
||||
*
|
||||
* @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
|
||||
*/
|
||||
public static function reload($data)
|
||||
{
|
||||
self::$installed = $data;
|
||||
self::$installedByVendor = array();
|
||||
|
||||
// when using reload, we disable the duplicate protection to ensure that self::$installed data is
|
||||
// always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not,
|
||||
// so we have to assume it does not, and that may result in duplicate data being returned when listing
|
||||
// all installed packages for example
|
||||
self::$installedIsLocalDir = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||
*/
|
||||
private static function getInstalled()
|
||||
{
|
||||
if (null === self::$canGetVendors) {
|
||||
self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
|
||||
}
|
||||
|
||||
$installed = array();
|
||||
$copiedLocalDir = false;
|
||||
|
||||
if (self::$canGetVendors) {
|
||||
$selfDir = strtr(__DIR__, '\\', '/');
|
||||
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
|
||||
$vendorDir = strtr($vendorDir, '\\', '/');
|
||||
if (isset(self::$installedByVendor[$vendorDir])) {
|
||||
$installed[] = self::$installedByVendor[$vendorDir];
|
||||
} elseif (is_file($vendorDir.'/composer/installed.php')) {
|
||||
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
|
||||
$required = require $vendorDir.'/composer/installed.php';
|
||||
self::$installedByVendor[$vendorDir] = $required;
|
||||
$installed[] = $required;
|
||||
if (self::$installed === null && $vendorDir.'/composer' === $selfDir) {
|
||||
self::$installed = $required;
|
||||
self::$installedIsLocalDir = true;
|
||||
}
|
||||
}
|
||||
if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) {
|
||||
$copiedLocalDir = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (null === self::$installed) {
|
||||
// only require the installed.php file if this file is loaded from its dumped location,
|
||||
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
|
||||
if (substr(__DIR__, -8, 1) !== 'C') {
|
||||
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
|
||||
$required = require __DIR__ . '/installed.php';
|
||||
self::$installed = $required;
|
||||
} else {
|
||||
self::$installed = array();
|
||||
}
|
||||
}
|
||||
|
||||
if (self::$installed !== array() && !$copiedLocalDir) {
|
||||
$installed[] = self::$installed;
|
||||
}
|
||||
|
||||
return $installed;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
|
||||
Copyright (c) Nils Adermann, Jordi Boggiano
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
|
|
@ -1,106 +0,0 @@
|
|||
<?php
|
||||
|
||||
// autoload_classmap.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = $vendorDir;
|
||||
|
||||
return array(
|
||||
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
|
||||
'OCA\\Richdocuments\\AppConfig' => $baseDir . '/../lib/AppConfig.php',
|
||||
'OCA\\Richdocuments\\AppInfo\\Application' => $baseDir . '/../lib/AppInfo/Application.php',
|
||||
'OCA\\Richdocuments\\Backgroundjobs\\Cleanup' => $baseDir . '/../lib/Backgroundjobs/Cleanup.php',
|
||||
'OCA\\Richdocuments\\Backgroundjobs\\ObtainCapabilities' => $baseDir . '/../lib/Backgroundjobs/ObtainCapabilities.php',
|
||||
'OCA\\Richdocuments\\Capabilities' => $baseDir . '/../lib/Capabilities.php',
|
||||
'OCA\\Richdocuments\\Command\\ActivateConfig' => $baseDir . '/../lib/Command/ActivateConfig.php',
|
||||
'OCA\\Richdocuments\\Command\\ConvertToBigInt' => $baseDir . '/../lib/Command/ConvertToBigInt.php',
|
||||
'OCA\\Richdocuments\\Command\\InstallDefaultFonts' => $baseDir . '/../lib/Command/InstallDefaultFonts.php',
|
||||
'OCA\\Richdocuments\\Command\\UpdateEmptyTemplates' => $baseDir . '/../lib/Command/UpdateEmptyTemplates.php',
|
||||
'OCA\\Richdocuments\\Controller\\AssetsController' => $baseDir . '/../lib/Controller/AssetsController.php',
|
||||
'OCA\\Richdocuments\\Controller\\Attribute\\RestrictToWopiServer' => $baseDir . '/../lib/Controller/Attribute/RestrictToWopiServer.php',
|
||||
'OCA\\Richdocuments\\Controller\\DirectViewController' => $baseDir . '/../lib/Controller/DirectViewController.php',
|
||||
'OCA\\Richdocuments\\Controller\\DocumentAPIController' => $baseDir . '/../lib/Controller/DocumentAPIController.php',
|
||||
'OCA\\Richdocuments\\Controller\\DocumentController' => $baseDir . '/../lib/Controller/DocumentController.php',
|
||||
'OCA\\Richdocuments\\Controller\\DocumentTrait' => $baseDir . '/../lib/Controller/DocumentTrait.php',
|
||||
'OCA\\Richdocuments\\Controller\\FederationController' => $baseDir . '/../lib/Controller/FederationController.php',
|
||||
'OCA\\Richdocuments\\Controller\\MentionController' => $baseDir . '/../lib/Controller/MentionController.php',
|
||||
'OCA\\Richdocuments\\Controller\\OCSController' => $baseDir . '/../lib/Controller/OCSController.php',
|
||||
'OCA\\Richdocuments\\Controller\\SettingsController' => $baseDir . '/../lib/Controller/SettingsController.php',
|
||||
'OCA\\Richdocuments\\Controller\\TargetController' => $baseDir . '/../lib/Controller/TargetController.php',
|
||||
'OCA\\Richdocuments\\Controller\\TemplateFieldController' => $baseDir . '/../lib/Controller/TemplateFieldController.php',
|
||||
'OCA\\Richdocuments\\Controller\\TemplatesController' => $baseDir . '/../lib/Controller/TemplatesController.php',
|
||||
'OCA\\Richdocuments\\Controller\\WopiController' => $baseDir . '/../lib/Controller/WopiController.php',
|
||||
'OCA\\Richdocuments\\Conversion\\ConversionProvider' => $baseDir . '/../lib/Conversion/ConversionProvider.php',
|
||||
'OCA\\Richdocuments\\Db\\Asset' => $baseDir . '/../lib/Db/Asset.php',
|
||||
'OCA\\Richdocuments\\Db\\AssetMapper' => $baseDir . '/../lib/Db/AssetMapper.php',
|
||||
'OCA\\Richdocuments\\Db\\Direct' => $baseDir . '/../lib/Db/Direct.php',
|
||||
'OCA\\Richdocuments\\Db\\DirectMapper' => $baseDir . '/../lib/Db/DirectMapper.php',
|
||||
'OCA\\Richdocuments\\Db\\Wopi' => $baseDir . '/../lib/Db/Wopi.php',
|
||||
'OCA\\Richdocuments\\Db\\WopiMapper' => $baseDir . '/../lib/Db/WopiMapper.php',
|
||||
'OCA\\Richdocuments\\Events\\BeforeFederationRedirectEvent' => $baseDir . '/../lib/Events/BeforeFederationRedirectEvent.php',
|
||||
'OCA\\Richdocuments\\Events\\DocumentOpenedEvent' => $baseDir . '/../lib/Events/DocumentOpenedEvent.php',
|
||||
'OCA\\Richdocuments\\Exceptions\\ExpiredTokenException' => $baseDir . '/../lib/Exceptions/ExpiredTokenException.php',
|
||||
'OCA\\Richdocuments\\Exceptions\\UnknownTokenException' => $baseDir . '/../lib/Exceptions/UnknownTokenException.php',
|
||||
'OCA\\Richdocuments\\Helper' => $baseDir . '/../lib/Helper.php',
|
||||
'OCA\\Richdocuments\\Listener\\AddContentSecurityPolicyListener' => $baseDir . '/../lib/Listener/AddContentSecurityPolicyListener.php',
|
||||
'OCA\\Richdocuments\\Listener\\AddFeaturePolicyListener' => $baseDir . '/../lib/Listener/AddFeaturePolicyListener.php',
|
||||
'OCA\\Richdocuments\\Listener\\BeforeFetchPreviewListener' => $baseDir . '/../lib/Listener/BeforeFetchPreviewListener.php',
|
||||
'OCA\\Richdocuments\\Listener\\BeforeGetTemplatesListener' => $baseDir . '/../lib/Listener/BeforeGetTemplatesListener.php',
|
||||
'OCA\\Richdocuments\\Listener\\BeforeTemplateRenderedListener' => $baseDir . '/../lib/Listener/BeforeTemplateRenderedListener.php',
|
||||
'OCA\\Richdocuments\\Listener\\FileCreatedFromTemplateListener' => $baseDir . '/../lib/Listener/FileCreatedFromTemplateListener.php',
|
||||
'OCA\\Richdocuments\\Listener\\LoadAdditionalListener' => $baseDir . '/../lib/Listener/LoadAdditionalListener.php',
|
||||
'OCA\\Richdocuments\\Listener\\LoadViewerListener' => $baseDir . '/../lib/Listener/LoadViewerListener.php',
|
||||
'OCA\\Richdocuments\\Listener\\ReferenceListener' => $baseDir . '/../lib/Listener/ReferenceListener.php',
|
||||
'OCA\\Richdocuments\\Listener\\RegisterTemplateFileCreatorListener' => $baseDir . '/../lib/Listener/RegisterTemplateFileCreatorListener.php',
|
||||
'OCA\\Richdocuments\\Listener\\ShareLinkListener' => $baseDir . '/../lib/Listener/ShareLinkListener.php',
|
||||
'OCA\\Richdocuments\\Middleware\\WOPIMiddleware' => $baseDir . '/../lib/Middleware/WOPIMiddleware.php',
|
||||
'OCA\\Richdocuments\\Migration\\InstallDefaultFonts' => $baseDir . '/../lib/Migration/InstallDefaultFonts.php',
|
||||
'OCA\\Richdocuments\\Migration\\Version2060Date20200302131958' => $baseDir . '/../lib/Migration/Version2060Date20200302131958.php',
|
||||
'OCA\\Richdocuments\\Migration\\Version2060Date20200302132145' => $baseDir . '/../lib/Migration/Version2060Date20200302132145.php',
|
||||
'OCA\\Richdocuments\\Migration\\Version30704Date20200626072306' => $baseDir . '/../lib/Migration/Version30704Date20200626072306.php',
|
||||
'OCA\\Richdocuments\\Migration\\Version30709Date20201111104147' => $baseDir . '/../lib/Migration/Version30709Date20201111104147.php',
|
||||
'OCA\\Richdocuments\\Migration\\Version30717Date20210310164901' => $baseDir . '/../lib/Migration/Version30717Date20210310164901.php',
|
||||
'OCA\\Richdocuments\\Migration\\Version50200Date20211220212457' => $baseDir . '/../lib/Migration/Version50200Date20211220212457.php',
|
||||
'OCA\\Richdocuments\\Notification\\Notifier' => $baseDir . '/../lib/Notification/Notifier.php',
|
||||
'OCA\\Richdocuments\\PermissionManager' => $baseDir . '/../lib/PermissionManager.php',
|
||||
'OCA\\Richdocuments\\Preview\\EMF' => $baseDir . '/../lib/Preview/EMF.php',
|
||||
'OCA\\Richdocuments\\Preview\\MSExcel' => $baseDir . '/../lib/Preview/MSExcel.php',
|
||||
'OCA\\Richdocuments\\Preview\\MSWord' => $baseDir . '/../lib/Preview/MSWord.php',
|
||||
'OCA\\Richdocuments\\Preview\\OOXML' => $baseDir . '/../lib/Preview/OOXML.php',
|
||||
'OCA\\Richdocuments\\Preview\\Office' => $baseDir . '/../lib/Preview/Office.php',
|
||||
'OCA\\Richdocuments\\Preview\\OpenDocument' => $baseDir . '/../lib/Preview/OpenDocument.php',
|
||||
'OCA\\Richdocuments\\Preview\\Pdf' => $baseDir . '/../lib/Preview/Pdf.php',
|
||||
'OCA\\Richdocuments\\Reference\\OfficeTargetReferenceProvider' => $baseDir . '/../lib/Reference/OfficeTargetReferenceProvider.php',
|
||||
'OCA\\Richdocuments\\Service\\CachedRequestService' => $baseDir . '/../lib/Service/CachedRequestService.php',
|
||||
'OCA\\Richdocuments\\Service\\CapabilitiesService' => $baseDir . '/../lib/Service/CapabilitiesService.php',
|
||||
'OCA\\Richdocuments\\Service\\ConnectivityService' => $baseDir . '/../lib/Service/ConnectivityService.php',
|
||||
'OCA\\Richdocuments\\Service\\DemoService' => $baseDir . '/../lib/Service/DemoService.php',
|
||||
'OCA\\Richdocuments\\Service\\DiscoveryService' => $baseDir . '/../lib/Service/DiscoveryService.php',
|
||||
'OCA\\Richdocuments\\Service\\FederationService' => $baseDir . '/../lib/Service/FederationService.php',
|
||||
'OCA\\Richdocuments\\Service\\FileTargetService' => $baseDir . '/../lib/Service/FileTargetService.php',
|
||||
'OCA\\Richdocuments\\Service\\FontService' => $baseDir . '/../lib/Service/FontService.php',
|
||||
'OCA\\Richdocuments\\Service\\InitialStateService' => $baseDir . '/../lib/Service/InitialStateService.php',
|
||||
'OCA\\Richdocuments\\Service\\PdfService' => $baseDir . '/../lib/Service/PdfService.php',
|
||||
'OCA\\Richdocuments\\Service\\RemoteOptionsService' => $baseDir . '/../lib/Service/RemoteOptionsService.php',
|
||||
'OCA\\Richdocuments\\Service\\RemoteService' => $baseDir . '/../lib/Service/RemoteService.php',
|
||||
'OCA\\Richdocuments\\Service\\TemplateFieldService' => $baseDir . '/../lib/Service/TemplateFieldService.php',
|
||||
'OCA\\Richdocuments\\Service\\UserScopeService' => $baseDir . '/../lib/Service/UserScopeService.php',
|
||||
'OCA\\Richdocuments\\Settings\\Admin' => $baseDir . '/../lib/Settings/Admin.php',
|
||||
'OCA\\Richdocuments\\Settings\\Personal' => $baseDir . '/../lib/Settings/Personal.php',
|
||||
'OCA\\Richdocuments\\Settings\\Section' => $baseDir . '/../lib/Settings/Section.php',
|
||||
'OCA\\Richdocuments\\TaskProcessingManager' => $baseDir . '/../lib/TaskProcessingManager.php',
|
||||
'OCA\\Richdocuments\\TemplateManager' => $baseDir . '/../lib/TemplateManager.php',
|
||||
'OCA\\Richdocuments\\Template\\CollaboraTemplateProvider' => $baseDir . '/../lib/Template/CollaboraTemplateProvider.php',
|
||||
'OCA\\Richdocuments\\TokenManager' => $baseDir . '/../lib/TokenManager.php',
|
||||
'OCA\\Richdocuments\\UploadException' => $baseDir . '/../lib/UploadException.php',
|
||||
'OCA\\Richdocuments\\WOPI\\Parser' => $baseDir . '/../lib/WOPI/Parser.php',
|
||||
'mikehaertl\\pdftk\\Command' => $vendorDir . '/mikehaertl/php-pdftk/src/Command.php',
|
||||
'mikehaertl\\pdftk\\DataFields' => $vendorDir . '/mikehaertl/php-pdftk/src/DataFields.php',
|
||||
'mikehaertl\\pdftk\\FdfFile' => $vendorDir . '/mikehaertl/php-pdftk/src/FdfFile.php',
|
||||
'mikehaertl\\pdftk\\InfoFields' => $vendorDir . '/mikehaertl/php-pdftk/src/InfoFields.php',
|
||||
'mikehaertl\\pdftk\\InfoFile' => $vendorDir . '/mikehaertl/php-pdftk/src/InfoFile.php',
|
||||
'mikehaertl\\pdftk\\Pdf' => $vendorDir . '/mikehaertl/php-pdftk/src/Pdf.php',
|
||||
'mikehaertl\\pdftk\\XfdfFile' => $vendorDir . '/mikehaertl/php-pdftk/src/XfdfFile.php',
|
||||
'mikehaertl\\shellcommand\\Command' => $vendorDir . '/mikehaertl/php-shellcommand/src/Command.php',
|
||||
'mikehaertl\\tmp\\File' => $vendorDir . '/mikehaertl/php-tmpfile/src/File.php',
|
||||
);
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
<?php
|
||||
|
||||
// autoload_namespaces.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = $vendorDir;
|
||||
|
||||
return array(
|
||||
);
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
<?php
|
||||
|
||||
// autoload_psr4.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = $vendorDir;
|
||||
|
||||
return array(
|
||||
'mikehaertl\\tmp\\' => array($vendorDir . '/mikehaertl/php-tmpfile/src'),
|
||||
'mikehaertl\\shellcommand\\' => array($vendorDir . '/mikehaertl/php-shellcommand/src'),
|
||||
'mikehaertl\\pdftk\\' => array($vendorDir . '/mikehaertl/php-pdftk/src'),
|
||||
'OCA\\Richdocuments\\' => array($baseDir . '/../lib'),
|
||||
);
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
<?php
|
||||
|
||||
// autoload_real.php @generated by Composer
|
||||
|
||||
class ComposerAutoloaderInitRichdocuments
|
||||
{
|
||||
private static $loader;
|
||||
|
||||
public static function loadClassLoader($class)
|
||||
{
|
||||
if ('Composer\Autoload\ClassLoader' === $class) {
|
||||
require __DIR__ . '/ClassLoader.php';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Composer\Autoload\ClassLoader
|
||||
*/
|
||||
public static function getLoader()
|
||||
{
|
||||
if (null !== self::$loader) {
|
||||
return self::$loader;
|
||||
}
|
||||
|
||||
require __DIR__ . '/platform_check.php';
|
||||
|
||||
spl_autoload_register(array('ComposerAutoloaderInitRichdocuments', 'loadClassLoader'), true, true);
|
||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
|
||||
spl_autoload_unregister(array('ComposerAutoloaderInitRichdocuments', 'loadClassLoader'));
|
||||
|
||||
require __DIR__ . '/autoload_static.php';
|
||||
call_user_func(\Composer\Autoload\ComposerStaticInitRichdocuments::getInitializer($loader));
|
||||
|
||||
$loader->register(true);
|
||||
|
||||
return $loader;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,150 +0,0 @@
|
|||
<?php
|
||||
|
||||
// autoload_static.php @generated by Composer
|
||||
|
||||
namespace Composer\Autoload;
|
||||
|
||||
class ComposerStaticInitRichdocuments
|
||||
{
|
||||
public static $prefixLengthsPsr4 = array (
|
||||
'm' =>
|
||||
array (
|
||||
'mikehaertl\\tmp\\' => 15,
|
||||
'mikehaertl\\shellcommand\\' => 24,
|
||||
'mikehaertl\\pdftk\\' => 17,
|
||||
),
|
||||
'O' =>
|
||||
array (
|
||||
'OCA\\Richdocuments\\' => 18,
|
||||
),
|
||||
);
|
||||
|
||||
public static $prefixDirsPsr4 = array (
|
||||
'mikehaertl\\tmp\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/mikehaertl/php-tmpfile/src',
|
||||
),
|
||||
'mikehaertl\\shellcommand\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/mikehaertl/php-shellcommand/src',
|
||||
),
|
||||
'mikehaertl\\pdftk\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/mikehaertl/php-pdftk/src',
|
||||
),
|
||||
'OCA\\Richdocuments\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/../lib',
|
||||
),
|
||||
);
|
||||
|
||||
public static $classMap = array (
|
||||
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
|
||||
'OCA\\Richdocuments\\AppConfig' => __DIR__ . '/..' . '/../lib/AppConfig.php',
|
||||
'OCA\\Richdocuments\\AppInfo\\Application' => __DIR__ . '/..' . '/../lib/AppInfo/Application.php',
|
||||
'OCA\\Richdocuments\\Backgroundjobs\\Cleanup' => __DIR__ . '/..' . '/../lib/Backgroundjobs/Cleanup.php',
|
||||
'OCA\\Richdocuments\\Backgroundjobs\\ObtainCapabilities' => __DIR__ . '/..' . '/../lib/Backgroundjobs/ObtainCapabilities.php',
|
||||
'OCA\\Richdocuments\\Capabilities' => __DIR__ . '/..' . '/../lib/Capabilities.php',
|
||||
'OCA\\Richdocuments\\Command\\ActivateConfig' => __DIR__ . '/..' . '/../lib/Command/ActivateConfig.php',
|
||||
'OCA\\Richdocuments\\Command\\ConvertToBigInt' => __DIR__ . '/..' . '/../lib/Command/ConvertToBigInt.php',
|
||||
'OCA\\Richdocuments\\Command\\InstallDefaultFonts' => __DIR__ . '/..' . '/../lib/Command/InstallDefaultFonts.php',
|
||||
'OCA\\Richdocuments\\Command\\UpdateEmptyTemplates' => __DIR__ . '/..' . '/../lib/Command/UpdateEmptyTemplates.php',
|
||||
'OCA\\Richdocuments\\Controller\\AssetsController' => __DIR__ . '/..' . '/../lib/Controller/AssetsController.php',
|
||||
'OCA\\Richdocuments\\Controller\\Attribute\\RestrictToWopiServer' => __DIR__ . '/..' . '/../lib/Controller/Attribute/RestrictToWopiServer.php',
|
||||
'OCA\\Richdocuments\\Controller\\DirectViewController' => __DIR__ . '/..' . '/../lib/Controller/DirectViewController.php',
|
||||
'OCA\\Richdocuments\\Controller\\DocumentAPIController' => __DIR__ . '/..' . '/../lib/Controller/DocumentAPIController.php',
|
||||
'OCA\\Richdocuments\\Controller\\DocumentController' => __DIR__ . '/..' . '/../lib/Controller/DocumentController.php',
|
||||
'OCA\\Richdocuments\\Controller\\DocumentTrait' => __DIR__ . '/..' . '/../lib/Controller/DocumentTrait.php',
|
||||
'OCA\\Richdocuments\\Controller\\FederationController' => __DIR__ . '/..' . '/../lib/Controller/FederationController.php',
|
||||
'OCA\\Richdocuments\\Controller\\MentionController' => __DIR__ . '/..' . '/../lib/Controller/MentionController.php',
|
||||
'OCA\\Richdocuments\\Controller\\OCSController' => __DIR__ . '/..' . '/../lib/Controller/OCSController.php',
|
||||
'OCA\\Richdocuments\\Controller\\SettingsController' => __DIR__ . '/..' . '/../lib/Controller/SettingsController.php',
|
||||
'OCA\\Richdocuments\\Controller\\TargetController' => __DIR__ . '/..' . '/../lib/Controller/TargetController.php',
|
||||
'OCA\\Richdocuments\\Controller\\TemplateFieldController' => __DIR__ . '/..' . '/../lib/Controller/TemplateFieldController.php',
|
||||
'OCA\\Richdocuments\\Controller\\TemplatesController' => __DIR__ . '/..' . '/../lib/Controller/TemplatesController.php',
|
||||
'OCA\\Richdocuments\\Controller\\WopiController' => __DIR__ . '/..' . '/../lib/Controller/WopiController.php',
|
||||
'OCA\\Richdocuments\\Conversion\\ConversionProvider' => __DIR__ . '/..' . '/../lib/Conversion/ConversionProvider.php',
|
||||
'OCA\\Richdocuments\\Db\\Asset' => __DIR__ . '/..' . '/../lib/Db/Asset.php',
|
||||
'OCA\\Richdocuments\\Db\\AssetMapper' => __DIR__ . '/..' . '/../lib/Db/AssetMapper.php',
|
||||
'OCA\\Richdocuments\\Db\\Direct' => __DIR__ . '/..' . '/../lib/Db/Direct.php',
|
||||
'OCA\\Richdocuments\\Db\\DirectMapper' => __DIR__ . '/..' . '/../lib/Db/DirectMapper.php',
|
||||
'OCA\\Richdocuments\\Db\\Wopi' => __DIR__ . '/..' . '/../lib/Db/Wopi.php',
|
||||
'OCA\\Richdocuments\\Db\\WopiMapper' => __DIR__ . '/..' . '/../lib/Db/WopiMapper.php',
|
||||
'OCA\\Richdocuments\\Events\\BeforeFederationRedirectEvent' => __DIR__ . '/..' . '/../lib/Events/BeforeFederationRedirectEvent.php',
|
||||
'OCA\\Richdocuments\\Events\\DocumentOpenedEvent' => __DIR__ . '/..' . '/../lib/Events/DocumentOpenedEvent.php',
|
||||
'OCA\\Richdocuments\\Exceptions\\ExpiredTokenException' => __DIR__ . '/..' . '/../lib/Exceptions/ExpiredTokenException.php',
|
||||
'OCA\\Richdocuments\\Exceptions\\UnknownTokenException' => __DIR__ . '/..' . '/../lib/Exceptions/UnknownTokenException.php',
|
||||
'OCA\\Richdocuments\\Helper' => __DIR__ . '/..' . '/../lib/Helper.php',
|
||||
'OCA\\Richdocuments\\Listener\\AddContentSecurityPolicyListener' => __DIR__ . '/..' . '/../lib/Listener/AddContentSecurityPolicyListener.php',
|
||||
'OCA\\Richdocuments\\Listener\\AddFeaturePolicyListener' => __DIR__ . '/..' . '/../lib/Listener/AddFeaturePolicyListener.php',
|
||||
'OCA\\Richdocuments\\Listener\\BeforeFetchPreviewListener' => __DIR__ . '/..' . '/../lib/Listener/BeforeFetchPreviewListener.php',
|
||||
'OCA\\Richdocuments\\Listener\\BeforeGetTemplatesListener' => __DIR__ . '/..' . '/../lib/Listener/BeforeGetTemplatesListener.php',
|
||||
'OCA\\Richdocuments\\Listener\\BeforeTemplateRenderedListener' => __DIR__ . '/..' . '/../lib/Listener/BeforeTemplateRenderedListener.php',
|
||||
'OCA\\Richdocuments\\Listener\\FileCreatedFromTemplateListener' => __DIR__ . '/..' . '/../lib/Listener/FileCreatedFromTemplateListener.php',
|
||||
'OCA\\Richdocuments\\Listener\\LoadAdditionalListener' => __DIR__ . '/..' . '/../lib/Listener/LoadAdditionalListener.php',
|
||||
'OCA\\Richdocuments\\Listener\\LoadViewerListener' => __DIR__ . '/..' . '/../lib/Listener/LoadViewerListener.php',
|
||||
'OCA\\Richdocuments\\Listener\\ReferenceListener' => __DIR__ . '/..' . '/../lib/Listener/ReferenceListener.php',
|
||||
'OCA\\Richdocuments\\Listener\\RegisterTemplateFileCreatorListener' => __DIR__ . '/..' . '/../lib/Listener/RegisterTemplateFileCreatorListener.php',
|
||||
'OCA\\Richdocuments\\Listener\\ShareLinkListener' => __DIR__ . '/..' . '/../lib/Listener/ShareLinkListener.php',
|
||||
'OCA\\Richdocuments\\Middleware\\WOPIMiddleware' => __DIR__ . '/..' . '/../lib/Middleware/WOPIMiddleware.php',
|
||||
'OCA\\Richdocuments\\Migration\\InstallDefaultFonts' => __DIR__ . '/..' . '/../lib/Migration/InstallDefaultFonts.php',
|
||||
'OCA\\Richdocuments\\Migration\\Version2060Date20200302131958' => __DIR__ . '/..' . '/../lib/Migration/Version2060Date20200302131958.php',
|
||||
'OCA\\Richdocuments\\Migration\\Version2060Date20200302132145' => __DIR__ . '/..' . '/../lib/Migration/Version2060Date20200302132145.php',
|
||||
'OCA\\Richdocuments\\Migration\\Version30704Date20200626072306' => __DIR__ . '/..' . '/../lib/Migration/Version30704Date20200626072306.php',
|
||||
'OCA\\Richdocuments\\Migration\\Version30709Date20201111104147' => __DIR__ . '/..' . '/../lib/Migration/Version30709Date20201111104147.php',
|
||||
'OCA\\Richdocuments\\Migration\\Version30717Date20210310164901' => __DIR__ . '/..' . '/../lib/Migration/Version30717Date20210310164901.php',
|
||||
'OCA\\Richdocuments\\Migration\\Version50200Date20211220212457' => __DIR__ . '/..' . '/../lib/Migration/Version50200Date20211220212457.php',
|
||||
'OCA\\Richdocuments\\Notification\\Notifier' => __DIR__ . '/..' . '/../lib/Notification/Notifier.php',
|
||||
'OCA\\Richdocuments\\PermissionManager' => __DIR__ . '/..' . '/../lib/PermissionManager.php',
|
||||
'OCA\\Richdocuments\\Preview\\EMF' => __DIR__ . '/..' . '/../lib/Preview/EMF.php',
|
||||
'OCA\\Richdocuments\\Preview\\MSExcel' => __DIR__ . '/..' . '/../lib/Preview/MSExcel.php',
|
||||
'OCA\\Richdocuments\\Preview\\MSWord' => __DIR__ . '/..' . '/../lib/Preview/MSWord.php',
|
||||
'OCA\\Richdocuments\\Preview\\OOXML' => __DIR__ . '/..' . '/../lib/Preview/OOXML.php',
|
||||
'OCA\\Richdocuments\\Preview\\Office' => __DIR__ . '/..' . '/../lib/Preview/Office.php',
|
||||
'OCA\\Richdocuments\\Preview\\OpenDocument' => __DIR__ . '/..' . '/../lib/Preview/OpenDocument.php',
|
||||
'OCA\\Richdocuments\\Preview\\Pdf' => __DIR__ . '/..' . '/../lib/Preview/Pdf.php',
|
||||
'OCA\\Richdocuments\\Reference\\OfficeTargetReferenceProvider' => __DIR__ . '/..' . '/../lib/Reference/OfficeTargetReferenceProvider.php',
|
||||
'OCA\\Richdocuments\\Service\\CachedRequestService' => __DIR__ . '/..' . '/../lib/Service/CachedRequestService.php',
|
||||
'OCA\\Richdocuments\\Service\\CapabilitiesService' => __DIR__ . '/..' . '/../lib/Service/CapabilitiesService.php',
|
||||
'OCA\\Richdocuments\\Service\\ConnectivityService' => __DIR__ . '/..' . '/../lib/Service/ConnectivityService.php',
|
||||
'OCA\\Richdocuments\\Service\\DemoService' => __DIR__ . '/..' . '/../lib/Service/DemoService.php',
|
||||
'OCA\\Richdocuments\\Service\\DiscoveryService' => __DIR__ . '/..' . '/../lib/Service/DiscoveryService.php',
|
||||
'OCA\\Richdocuments\\Service\\FederationService' => __DIR__ . '/..' . '/../lib/Service/FederationService.php',
|
||||
'OCA\\Richdocuments\\Service\\FileTargetService' => __DIR__ . '/..' . '/../lib/Service/FileTargetService.php',
|
||||
'OCA\\Richdocuments\\Service\\FontService' => __DIR__ . '/..' . '/../lib/Service/FontService.php',
|
||||
'OCA\\Richdocuments\\Service\\InitialStateService' => __DIR__ . '/..' . '/../lib/Service/InitialStateService.php',
|
||||
'OCA\\Richdocuments\\Service\\PdfService' => __DIR__ . '/..' . '/../lib/Service/PdfService.php',
|
||||
'OCA\\Richdocuments\\Service\\RemoteOptionsService' => __DIR__ . '/..' . '/../lib/Service/RemoteOptionsService.php',
|
||||
'OCA\\Richdocuments\\Service\\RemoteService' => __DIR__ . '/..' . '/../lib/Service/RemoteService.php',
|
||||
'OCA\\Richdocuments\\Service\\TemplateFieldService' => __DIR__ . '/..' . '/../lib/Service/TemplateFieldService.php',
|
||||
'OCA\\Richdocuments\\Service\\UserScopeService' => __DIR__ . '/..' . '/../lib/Service/UserScopeService.php',
|
||||
'OCA\\Richdocuments\\Settings\\Admin' => __DIR__ . '/..' . '/../lib/Settings/Admin.php',
|
||||
'OCA\\Richdocuments\\Settings\\Personal' => __DIR__ . '/..' . '/../lib/Settings/Personal.php',
|
||||
'OCA\\Richdocuments\\Settings\\Section' => __DIR__ . '/..' . '/../lib/Settings/Section.php',
|
||||
'OCA\\Richdocuments\\TaskProcessingManager' => __DIR__ . '/..' . '/../lib/TaskProcessingManager.php',
|
||||
'OCA\\Richdocuments\\TemplateManager' => __DIR__ . '/..' . '/../lib/TemplateManager.php',
|
||||
'OCA\\Richdocuments\\Template\\CollaboraTemplateProvider' => __DIR__ . '/..' . '/../lib/Template/CollaboraTemplateProvider.php',
|
||||
'OCA\\Richdocuments\\TokenManager' => __DIR__ . '/..' . '/../lib/TokenManager.php',
|
||||
'OCA\\Richdocuments\\UploadException' => __DIR__ . '/..' . '/../lib/UploadException.php',
|
||||
'OCA\\Richdocuments\\WOPI\\Parser' => __DIR__ . '/..' . '/../lib/WOPI/Parser.php',
|
||||
'mikehaertl\\pdftk\\Command' => __DIR__ . '/..' . '/mikehaertl/php-pdftk/src/Command.php',
|
||||
'mikehaertl\\pdftk\\DataFields' => __DIR__ . '/..' . '/mikehaertl/php-pdftk/src/DataFields.php',
|
||||
'mikehaertl\\pdftk\\FdfFile' => __DIR__ . '/..' . '/mikehaertl/php-pdftk/src/FdfFile.php',
|
||||
'mikehaertl\\pdftk\\InfoFields' => __DIR__ . '/..' . '/mikehaertl/php-pdftk/src/InfoFields.php',
|
||||
'mikehaertl\\pdftk\\InfoFile' => __DIR__ . '/..' . '/mikehaertl/php-pdftk/src/InfoFile.php',
|
||||
'mikehaertl\\pdftk\\Pdf' => __DIR__ . '/..' . '/mikehaertl/php-pdftk/src/Pdf.php',
|
||||
'mikehaertl\\pdftk\\XfdfFile' => __DIR__ . '/..' . '/mikehaertl/php-pdftk/src/XfdfFile.php',
|
||||
'mikehaertl\\shellcommand\\Command' => __DIR__ . '/..' . '/mikehaertl/php-shellcommand/src/Command.php',
|
||||
'mikehaertl\\tmp\\File' => __DIR__ . '/..' . '/mikehaertl/php-tmpfile/src/File.php',
|
||||
);
|
||||
|
||||
public static function getInitializer(ClassLoader $loader)
|
||||
{
|
||||
return \Closure::bind(function () use ($loader) {
|
||||
$loader->prefixLengthsPsr4 = ComposerStaticInitRichdocuments::$prefixLengthsPsr4;
|
||||
$loader->prefixDirsPsr4 = ComposerStaticInitRichdocuments::$prefixDirsPsr4;
|
||||
$loader->classMap = ComposerStaticInitRichdocuments::$classMap;
|
||||
|
||||
}, null, ClassLoader::class);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,154 +0,0 @@
|
|||
{
|
||||
"packages": [
|
||||
{
|
||||
"name": "mikehaertl/php-pdftk",
|
||||
"version": "0.13.1",
|
||||
"version_normalized": "0.13.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mikehaertl/php-pdftk.git",
|
||||
"reference": "3851b08c1027489e48387d7c14c27bc295d98239"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/mikehaertl/php-pdftk/zipball/3851b08c1027489e48387d7c14c27bc295d98239",
|
||||
"reference": "3851b08c1027489e48387d7c14c27bc295d98239",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"mikehaertl/php-shellcommand": "^1.6.3",
|
||||
"mikehaertl/php-tmpfile": "^1.1.0",
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": ">4.0 <9.4"
|
||||
},
|
||||
"time": "2023-11-03T16:06:08+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"mikehaertl\\pdftk\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Michael Haertl",
|
||||
"email": "haertl.mike@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "A PDF conversion and form utility based on pdftk.",
|
||||
"keywords": [
|
||||
"pdf",
|
||||
"pdftk"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/mikehaertl/php-pdftk/issues",
|
||||
"source": "https://github.com/mikehaertl/php-pdftk/tree/0.13.1"
|
||||
},
|
||||
"install-path": "../mikehaertl/php-pdftk"
|
||||
},
|
||||
{
|
||||
"name": "mikehaertl/php-shellcommand",
|
||||
"version": "1.7.0",
|
||||
"version_normalized": "1.7.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mikehaertl/php-shellcommand.git",
|
||||
"reference": "e79ea528be155ffdec6f3bf1a4a46307bb49e545"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/mikehaertl/php-shellcommand/zipball/e79ea528be155ffdec6f3bf1a4a46307bb49e545",
|
||||
"reference": "e79ea528be155ffdec6f3bf1a4a46307bb49e545",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">= 5.3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": ">4.0 <=9.4"
|
||||
},
|
||||
"time": "2023-04-19T08:25:22+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"mikehaertl\\shellcommand\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Michael Härtl",
|
||||
"email": "haertl.mike@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "An object oriented interface to shell commands",
|
||||
"keywords": [
|
||||
"shell"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/mikehaertl/php-shellcommand/issues",
|
||||
"source": "https://github.com/mikehaertl/php-shellcommand/tree/1.7.0"
|
||||
},
|
||||
"install-path": "../mikehaertl/php-shellcommand"
|
||||
},
|
||||
{
|
||||
"name": "mikehaertl/php-tmpfile",
|
||||
"version": "1.2.1",
|
||||
"version_normalized": "1.2.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mikehaertl/php-tmpfile.git",
|
||||
"reference": "70a5b70b17bc0d9666388e6a551ecc93d0b40a10"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/mikehaertl/php-tmpfile/zipball/70a5b70b17bc0d9666388e6a551ecc93d0b40a10",
|
||||
"reference": "70a5b70b17bc0d9666388e6a551ecc93d0b40a10",
|
||||
"shasum": ""
|
||||
},
|
||||
"require-dev": {
|
||||
"php": ">=5.3.0",
|
||||
"phpunit/phpunit": ">4.0 <=9.4"
|
||||
},
|
||||
"time": "2021-03-01T18:26:25+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"mikehaertl\\tmp\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Michael Härtl",
|
||||
"email": "haertl.mike@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "A convenience class for temporary files",
|
||||
"keywords": [
|
||||
"files"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/mikehaertl/php-tmpfile/issues",
|
||||
"source": "https://github.com/mikehaertl/php-tmpfile/tree/1.2.1"
|
||||
},
|
||||
"install-path": "../mikehaertl/php-tmpfile"
|
||||
}
|
||||
],
|
||||
"dev": true,
|
||||
"dev-package-names": []
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
<?php return array(
|
||||
'root' => array(
|
||||
'name' => '__root__',
|
||||
'pretty_version' => 'dev-main',
|
||||
'version' => 'dev-main',
|
||||
'reference' => '8c21f5edd732074493f83a7e9c84b825ab8aab25',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../',
|
||||
'aliases' => array(),
|
||||
'dev' => true,
|
||||
),
|
||||
'versions' => array(
|
||||
'__root__' => array(
|
||||
'pretty_version' => 'dev-main',
|
||||
'version' => 'dev-main',
|
||||
'reference' => '8c21f5edd732074493f83a7e9c84b825ab8aab25',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'mikehaertl/php-pdftk' => array(
|
||||
'pretty_version' => '0.13.1',
|
||||
'version' => '0.13.1.0',
|
||||
'reference' => '3851b08c1027489e48387d7c14c27bc295d98239',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../mikehaertl/php-pdftk',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'mikehaertl/php-shellcommand' => array(
|
||||
'pretty_version' => '1.7.0',
|
||||
'version' => '1.7.0.0',
|
||||
'reference' => 'e79ea528be155ffdec6f3bf1a4a46307bb49e545',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../mikehaertl/php-shellcommand',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'mikehaertl/php-tmpfile' => array(
|
||||
'pretty_version' => '1.2.1',
|
||||
'version' => '1.2.1.0',
|
||||
'reference' => '70a5b70b17bc0d9666388e6a551ecc93d0b40a10',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../mikehaertl/php-tmpfile',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
<?php
|
||||
|
||||
// platform_check.php @generated by Composer
|
||||
|
||||
$issues = array();
|
||||
|
||||
if (!(PHP_VERSION_ID >= 50300)) {
|
||||
$issues[] = 'Your Composer dependencies require a PHP version ">= 5.3.0". You are running ' . PHP_VERSION . '.';
|
||||
}
|
||||
|
||||
if ($issues) {
|
||||
if (!headers_sent()) {
|
||||
header('HTTP/1.1 500 Internal Server Error');
|
||||
}
|
||||
if (!ini_get('display_errors')) {
|
||||
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
|
||||
fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
|
||||
} elseif (!headers_sent()) {
|
||||
echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
|
||||
}
|
||||
}
|
||||
trigger_error(
|
||||
'Composer detected issues in your platform: ' . implode(' ', $issues),
|
||||
E_USER_ERROR
|
||||
);
|
||||
}
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
name: Tests
|
||||
on: pull_request
|
||||
jobs:
|
||||
phpunit:
|
||||
name: PHP ${{ matrix.php }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
php:
|
||||
- "5.3"
|
||||
- "5.4"
|
||||
- "5.5"
|
||||
- "5.6"
|
||||
- "7.0"
|
||||
- "7.1"
|
||||
- "7.2"
|
||||
- "7.3"
|
||||
- "7.4"
|
||||
- "8.0"
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Install pdftk
|
||||
run: |
|
||||
cd /tmp
|
||||
sudo wget http://mirrors.kernel.org/ubuntu/pool/universe/p/pdftk-java/pdftk-java_3.0.9-1_all.deb
|
||||
sudo apt install -y -q ./pdftk-java_3.0.9-1_all.deb
|
||||
pdftk --version
|
||||
|
||||
- name: Install PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
tools: composer:v2
|
||||
|
||||
- name: Update composer
|
||||
run: composer self-update
|
||||
|
||||
- name: Get composer cache directory
|
||||
id: composer-cache
|
||||
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
|
||||
|
||||
- name: Cache composer cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}
|
||||
restore-keys: ${{ runner.os }}-composer-
|
||||
|
||||
- name: Install composer packages
|
||||
run: composer update --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi
|
||||
|
||||
- name: Run phpunit
|
||||
run: vendor/bin/phpunit --color=always
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Michael Härtl
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
|
@ -1,501 +0,0 @@
|
|||
php-pdftk
|
||||
=========
|
||||
|
||||
[](https://github.com/mikehaertl/php-pdftk/actions)
|
||||
[](https://packagist.org/packages/mikehaertl/php-pdftk)
|
||||
[](https://packagist.org/packages/mikehaertl/php-pdftk)
|
||||
[](https://github.com/mikehaertl/php-pdftk/blob/master/LICENSE)
|
||||
[](https://packagist.org/packages/mikehaertl/php-pdftk)
|
||||
|
||||
A PDF conversion and form utility based on pdftk.
|
||||
|
||||
## Features
|
||||
|
||||
*php-pdftk* brings the full power of `pdftk` to PHP - and more.
|
||||
|
||||
* Fill forms, either from a XFDF/FDF file or from a data array (UTF-8 safe for unflattened forms, requires pdftk 2.x !)
|
||||
* Create XFDF or FDF files from PHP arrays (UTF-8 safe!)
|
||||
* Create FDF files from filled PDF forms
|
||||
* Combine pages from several PDF files into a new PDF file
|
||||
* Split a PDF into one file per page
|
||||
* Add background or overlay PDFs
|
||||
* Read out meta data about PDF and form fields
|
||||
* Set passwords and permissions
|
||||
* Remove passwords
|
||||
|
||||
## Requirements
|
||||
|
||||
* The `pdftk` command must be installed and working on your system
|
||||
* This library is written for pdftk 2.x versions. You should be able to use it with pdftk 1.x but not all methods will work there.
|
||||
For details consult the man page of pdftk on your system.
|
||||
* There is a [known issue](https://github.com/mikehaertl/php-pdftk/issues/150)
|
||||
on Ubuntu if you installed the `pdftk` package from snap. This version has
|
||||
no permission to write to the `/tmp` directory. You can either set another
|
||||
temporay directory as described below or use another package. For Ubuntu
|
||||
18.10 there's also a `pdftk-java` package available via apt which should work
|
||||
fine. You can also install this package on Ubuntu 18.04 if you download it
|
||||
manually. Also check [this answer](https://askubuntu.com/a/1028983/175814)
|
||||
on askubuntu.
|
||||
|
||||
> **Note:** The pdftk version from the alternative PPA `ppa:malteworld/ppa` is
|
||||
> no longer available. The author instead now points to his answer on askubuntu
|
||||
> linked above.
|
||||
|
||||
## Installation
|
||||
|
||||
You should use [composer](https://getcomposer.org/) to install this library.
|
||||
|
||||
```
|
||||
composer require mikehaertl/php-pdftk
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Create instance for PDF files
|
||||
|
||||
There are several ways to tell the `Pdf` instance which file(s) it should use.
|
||||
Some files may also require a password or need an alias to be used as a handle
|
||||
in some operations (e.g. cat or shuffle).
|
||||
|
||||
> **Note:** In version 2.x of pdftk a handle can be one or more upper case letters.
|
||||
|
||||
```php
|
||||
// Create an instance for a single file
|
||||
$pdf = new Pdf('/path/to/form.pdf');
|
||||
|
||||
// Alternatively add files later. Handles are autogenerated in this case.
|
||||
$pdf = new Pdf();
|
||||
$pdf->addFile('/path/to/file1.pdf');
|
||||
$pdf->addFile('/path/to/file2.pdf');
|
||||
|
||||
// Add files with own handle
|
||||
$pdf = new Pdf();
|
||||
$pdf->addFile('/path/to/file1.pdf', 'A');
|
||||
$pdf->addFile('/path/to/file2.pdf', 'B');
|
||||
// Add file with handle and password
|
||||
$pdf->addFile('/path/to/file3.pdf', 'C', 'secret*password');
|
||||
|
||||
// Shortcut to pass all files to the constructor
|
||||
$pdf = new Pdf([
|
||||
'A' => ['/path/to/file1.pdf', 'secret*password1'],
|
||||
'B' => ['/path/to/file2.pdf', 'secret*password2'],
|
||||
]);
|
||||
```
|
||||
|
||||
### Operations
|
||||
|
||||
Please consult the `pdftk` man page for each operation to find out how each operation works
|
||||
in detail and which options are available.
|
||||
|
||||
For all operations you can either save the PDF locally through `saveAs($name)` or send it to the
|
||||
browser with `send()`. If you pass a filename to `send($name)` the client browser will open a download
|
||||
dialogue whereas without a filename it will usually display the PDF inline.
|
||||
|
||||
**IMPORTANT: You can always only perform *one* of the following operations on a single PDF instance.
|
||||
Below you can find a workaround if you need multiple operations.**
|
||||
|
||||
#### Fill Form
|
||||
|
||||
Fill a PDF form with data from a PHP array or an XFDF/FDF file.
|
||||
|
||||
```php
|
||||
use mikehaertl\pdftk\Pdf;
|
||||
|
||||
// Fill form with data array
|
||||
$pdf = new Pdf('/full/path/to/form.pdf');
|
||||
$result = $pdf->fillForm([
|
||||
'name'=>'ÄÜÖ äüö мирано čárka',
|
||||
'nested.name' => 'valX',
|
||||
])
|
||||
->needAppearances()
|
||||
->saveAs('filled.pdf');
|
||||
|
||||
// Always check for errors
|
||||
if ($result === false) {
|
||||
$error = $pdf->getError();
|
||||
}
|
||||
|
||||
// Fill form from FDF
|
||||
$pdf = new Pdf('form.pdf');
|
||||
$result = $pdf->fillForm('data.xfdf')
|
||||
->saveAs('filled.pdf');
|
||||
if ($result === false) {
|
||||
$error = $pdf->getError();
|
||||
}
|
||||
```
|
||||
|
||||
**Note:** When filling in UTF-8 data, you should always add the `needAppearances()` option.
|
||||
This will make sure, that the PDF reader takes care of using the right fonts for rendering,
|
||||
something that pdftk can't do for you. Also note that `flatten()` doesn't really work well
|
||||
if you have special characters in your data.
|
||||
|
||||
If you use `pdftk-java` >= 3.3.0 and the embedded font does not support UTF-8
|
||||
characters you can also replace it with a local font:
|
||||
|
||||
```php
|
||||
use mikehaertl\pdftk\Pdf;
|
||||
|
||||
// Fill form with data array
|
||||
$pdf = new Pdf('/full/path/to/form.pdf');
|
||||
$result = $pdf->fillForm($data)
|
||||
->replacementFont('/usr/share/fonts/dejavu/DejaVuSans.ttf')
|
||||
->saveAs('filled.pdf');
|
||||
```
|
||||
|
||||
#### Create a XFDF/FDF file from a PHP array
|
||||
|
||||
This is a bonus feature that is not available from `pdftk`.
|
||||
|
||||
```php
|
||||
use mikehaertl\pdftk\XfdfFile;
|
||||
use mikehaertl\pdftk\FdfFile;
|
||||
|
||||
$xfdf = new XfdfFile(['name' => 'Jürgen мирано']);
|
||||
$xfdf->saveAs('/path/to/data.xfdf');
|
||||
|
||||
$fdf = new FdfFile(['name' => 'Jürgen мирано']);
|
||||
$fdf->saveAs('/path/to/data.fdf');
|
||||
```
|
||||
|
||||
#### Cat
|
||||
|
||||
Assemble a PDF from pages from one or more PDF files.
|
||||
|
||||
```php
|
||||
use mikehaertl\pdftk\Pdf;
|
||||
|
||||
// Extract pages 1-5 and 7,4,9 into a new file
|
||||
$pdf = new Pdf('/path/to/my.pdf');
|
||||
$result = $pdf->cat(1, 5)
|
||||
->cat([7, 4, 9])
|
||||
->saveAs('/path/to/new.pdf');
|
||||
if ($result === false) {
|
||||
$error = $pdf->getError();
|
||||
}
|
||||
|
||||
// Combine pages from several files
|
||||
$pdf = new Pdf([
|
||||
'A' => '/path/file1.pdf', // A is alias for file1.pdf
|
||||
'B' => ['/path/file2.pdf','pass**word'], // B is alias for file2.pdf
|
||||
'C' => ['/path/file3.pdf','secret**pw'], // C is alias for file3.pdf
|
||||
]);
|
||||
$result = $pdf->cat(1, 5, 'A') // pages 1-5 from A
|
||||
->cat(3, null, 'B') // page 3 from B
|
||||
->cat(7, 'end', 'B', null, 'east') // pages 7-end from B, rotated East
|
||||
->cat('end',3,'A','even') // even pages 3-end in reverse order from A
|
||||
->cat([2,3,7], 'C') // pages 2,3 and 7 from C
|
||||
->saveAs('/path/new.pdf');
|
||||
if ($result === false) {
|
||||
$error = $pdf->getError();
|
||||
}
|
||||
```
|
||||
|
||||
#### Shuffle
|
||||
|
||||
Like `cat()` but create "*streams*" and fill the new PDF with one page from each
|
||||
stream at a time.
|
||||
|
||||
```php
|
||||
use mikehaertl\pdftk\Pdf;
|
||||
|
||||
$pdf = new Pdf([
|
||||
'A' => '/path/file1.pdf', // A is alias for file1.pdf
|
||||
'B' => '/path/file2.pdf', // B is alias for file2.pdf
|
||||
]);
|
||||
|
||||
// new.pdf will have pages A1, B3, A2, B4, A3, B5, ...
|
||||
$result = $pdf->shuffle(1, 5, 'A') // pages 1-5 from A
|
||||
->shuffle(3, 8, 'B') // pages 3-8 from B
|
||||
->saveAs('/path/new.pdf');
|
||||
if ($result === false) {
|
||||
$error = $pdf->getError();
|
||||
}
|
||||
```
|
||||
|
||||
#### Burst
|
||||
|
||||
Split a PDF file into one file per page.
|
||||
|
||||
```php
|
||||
use mikehaertl\pdftk\Pdf;
|
||||
|
||||
$pdf = new Pdf('/path/my.pdf');
|
||||
$result = $pdf->burst('/path/page_%d.pdf'); // Supply a printf() pattern
|
||||
if ($result === false) {
|
||||
$error = $pdf->getError();
|
||||
}
|
||||
```
|
||||
|
||||
#### Add background PDF
|
||||
|
||||
Add another PDF file as background.
|
||||
|
||||
```php
|
||||
use mikehaertl\pdftk\Pdf;
|
||||
|
||||
// Set background from another PDF (first page repeated)
|
||||
$pdf = new Pdf('/path/my.pdf');
|
||||
$result = $pdf->background('/path/back.pdf')
|
||||
->saveAs('/path/watermarked.pdf');
|
||||
if ($result === false) {
|
||||
$error = $pdf->getError();
|
||||
}
|
||||
|
||||
// Set background from another PDF (one page each)
|
||||
$pdf = new Pdf('/path/my.pdf');
|
||||
$result = $pdf->multiBackground('/path/back_pages.pdf')
|
||||
->saveAs('/path/watermarked.pdf');
|
||||
if ($result === false) {
|
||||
$error = $pdf->getError();
|
||||
}
|
||||
```
|
||||
|
||||
#### Add overlay PDF
|
||||
|
||||
Add another PDF file as overlay.
|
||||
|
||||
```php
|
||||
use mikehaertl\pdftk\Pdf;
|
||||
|
||||
// Stamp with another PDF (first page repeated)
|
||||
$pdf = new Pdf('/path/my.pdf');
|
||||
$result = $pdf->stamp('/path/overlay.pdf')
|
||||
->saveAs('/path/stamped.pdf');
|
||||
if ($result === false) {
|
||||
$error = $pdf->getError();
|
||||
}
|
||||
|
||||
// Stamp with another PDF (one page each)
|
||||
$pdf = new Pdf('/path/my.pdf');
|
||||
$result = $pdf->multiStamp('/path/overlay_pages.pdf')
|
||||
->saveAs('/path/stamped.pdf');
|
||||
if ($result === false) {
|
||||
$error = $pdf->getError();
|
||||
}
|
||||
```
|
||||
|
||||
#### Attach Files
|
||||
|
||||
Add file attachments to the document or to a specific page.
|
||||
|
||||
```php
|
||||
use mikehaertl\pdftk\Pdf;
|
||||
|
||||
$files = [
|
||||
'/path/to/file1',
|
||||
'/path/to/file2',
|
||||
]
|
||||
|
||||
// Add files at the document level
|
||||
$pdf = new Pdf('/path/my.pdf');
|
||||
$result = $pdf->attachFiles($files)
|
||||
->saveAs('/path/withfiles.pdf');
|
||||
if ($result === false) {
|
||||
$error = $pdf->getError();
|
||||
}
|
||||
|
||||
// Add files to a specific page
|
||||
$pdf = new Pdf('/path/my.pdf');
|
||||
$page = 7;
|
||||
$result = $pdf->attachFiles($files, $page)
|
||||
->saveAs('/path/withfiles.pdf');
|
||||
if ($result === false) {
|
||||
$error = $pdf->getError();
|
||||
}
|
||||
```
|
||||
#### Unpack Files
|
||||
|
||||
Copy file attachments from a PDF to the given directory.
|
||||
|
||||
```php
|
||||
use mikehaertl\pdftk\Pdf;
|
||||
|
||||
$pdf = new Pdf('/path/my.pdf');
|
||||
$result = $pdf->unpackFiles('/path/to/dir');
|
||||
if ($result === false) {
|
||||
$error = $pdf->getError();
|
||||
}
|
||||
```
|
||||
|
||||
#### Generate FDF
|
||||
|
||||
Create a FDF file from a given filled PDF form.
|
||||
|
||||
```php
|
||||
use mikehaertl\pdftk\Pdf;
|
||||
|
||||
// Create FDF from PDF
|
||||
$pdf = new Pdf('/path/form.pdf');
|
||||
$result = $pdf->generateFdfFile('/path/data.fdf');
|
||||
if ($result === false) {
|
||||
$error = $pdf->getError();
|
||||
}
|
||||
```
|
||||
|
||||
#### Get PDF data
|
||||
|
||||
Read out metadata or form field information from a PDF file.
|
||||
|
||||
```php
|
||||
use mikehaertl\pdftk\Pdf;
|
||||
|
||||
// Get data
|
||||
$pdf = new Pdf('/path/my.pdf');
|
||||
$data = $pdf->getData();
|
||||
if ($data === false) {
|
||||
$error = $pdf->getError();
|
||||
}
|
||||
|
||||
// Get form data fields
|
||||
$pdf = new Pdf('/path/my.pdf');
|
||||
$data = $pdf->getDataFields();
|
||||
if ($data === false) {
|
||||
$error = $pdf->getError();
|
||||
}
|
||||
|
||||
// Get data as string
|
||||
echo $data;
|
||||
$txt = (string) $data;
|
||||
$txt = $data->__toString();
|
||||
|
||||
// Get data as array
|
||||
$arr = (array) $data;
|
||||
$arr = $data->__toArray();
|
||||
$field1 = $data[0]['Field1'];
|
||||
```
|
||||
|
||||
#### How to perform more than one operation on a PDF
|
||||
|
||||
As stated above, you can only perform one of the preceeding operations on a single PDF instance.
|
||||
If you need more than one operation you can feed one `Pdf` instance into another:
|
||||
|
||||
```php
|
||||
use mikehaertl\pdftk\Pdf;
|
||||
|
||||
// Extract pages 1-5 and 7,4,9 into a new file
|
||||
$pdf = new Pdf('/path/my.pdf');
|
||||
$pdf->cat(1, 5)
|
||||
->cat([7, 4, 9]);
|
||||
|
||||
// We now use the above PDF as source file for a new PDF
|
||||
$pdf2 = new Pdf($pdf);
|
||||
$result = $pdf2->fillForm(['name' => 'ÄÜÖ äüö мирано čárka'])
|
||||
->needAppearances()
|
||||
->saveAs('/path/filled.pdf');
|
||||
if ($result === false) {
|
||||
$error = $pdf->getError();
|
||||
}
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
You can combine the above operations with one or more of the following options.
|
||||
|
||||
```php
|
||||
use mikehaertl\pdftk\Pdf;
|
||||
|
||||
$pdf = new Pdf('/path/my.pdf');
|
||||
|
||||
$result = $pdf->allow('AllFeatures') // Change permissions
|
||||
->flatten() // Merge form data into document (doesn't work well with UTF-8!)
|
||||
->compress($value) // Compress/Uncompress
|
||||
->keepId('first') // Keep first/last Id of combined files
|
||||
->dropXfa() // Drop newer XFA form from PDF
|
||||
->dropXmp() // Drop newer XMP data from PDF
|
||||
->needAppearances() // Make clients create appearance for form fields
|
||||
->setPassword($pw) // Set owner password
|
||||
->setUserPassword($pw) // Set user password
|
||||
->passwordEncryption(128) // Set password encryption strength
|
||||
->saveAs('new.pdf');
|
||||
if ($result === false) {
|
||||
$error = $pdf->getError();
|
||||
}
|
||||
|
||||
// Example: Fill PDF form and merge form data into PDF
|
||||
// Fill form with data array
|
||||
$result = $pdf = new Pdf('/path/form.pdf');
|
||||
$pdf->fillForm(['name' => 'My Name'])
|
||||
->flatten()
|
||||
->saveAs('/path/filled.pdf');
|
||||
if ($result === false) {
|
||||
$error = $pdf->getError();
|
||||
}
|
||||
|
||||
// Example: Remove password from a PDF
|
||||
$pdf = new Pdf;
|
||||
$result = $pdf->addFile('/path/my.pdf', null, 'some**password')
|
||||
->saveAs('/path/new.pdf');
|
||||
if ($result === false) {
|
||||
$error = $pdf->getError();
|
||||
}
|
||||
```
|
||||
|
||||
### Shell Command
|
||||
|
||||
The class uses [php-shellcommand](https://github.com/mikehaertl/php-shellcommand) to execute
|
||||
`pdftk`. You can pass `$options` for its `Command` class as second argument to the constructor:
|
||||
|
||||
```php
|
||||
use mikehaertl\pdftk\Pdf;
|
||||
|
||||
$pdf = new Pdf('/path/my.pdf', [
|
||||
'command' => '/some/other/path/to/pdftk',
|
||||
// or on most Windows systems:
|
||||
// 'command' => 'C:\Program Files (x86)\PDFtk\bin\pdftk.exe',
|
||||
'useExec' => true, // May help on Windows systems if execution fails
|
||||
]);
|
||||
```
|
||||
|
||||
#### Solve issues with UTF-8 characters in filenames or infofile content
|
||||
|
||||
If you have files with UTF-8 encoded characters in their filename or if you
|
||||
pass an infofile with such characters to `updateInfo()` you should supply the
|
||||
correct locale when excuting `pdftk`. You can therefore add these options:
|
||||
|
||||
```php
|
||||
$pdf = new Pdf($file, [
|
||||
'locale' => 'en_US.utf8',
|
||||
'procEnv' => [
|
||||
'LANG' => 'en_US.utf-8',
|
||||
],
|
||||
]);
|
||||
```
|
||||
|
||||
> **Note:** You need to ensure that the locale you set here is available on
|
||||
> your system. On Linux you can check with `locale -a` which locales are
|
||||
> installed. [This article](https://wiki.archlinux.org/title/locale) explains
|
||||
> the concept in more detail.
|
||||
|
||||
|
||||
|
||||
### Temporary File
|
||||
|
||||
Internally a temporary file is created via [php-tmpfile](https://github.com/mikehaertl/php-tmpfile).
|
||||
You can also access that file directly, e.g. if you neither want to send or save the
|
||||
file but only need the binary PDF content:
|
||||
|
||||
```php
|
||||
use mikehaertl\pdftk\Pdf;
|
||||
|
||||
$pdf = new Pdf('/path/my.pdf');
|
||||
$result = $pdf->fillForm(['name' => 'My Name'])
|
||||
->execute();
|
||||
if ($result === false) {
|
||||
$error = $pdf->getError();
|
||||
}
|
||||
$content = file_get_contents( (string) $pdf->getTmpFile() );
|
||||
```
|
||||
|
||||
If you have permission issues you may have to set a directory where your
|
||||
`pdftk` command can write to:
|
||||
|
||||
```php
|
||||
use mikehaertl\pdftk\Pdf;
|
||||
|
||||
$pdf = new Pdf('/path/my.pdf');
|
||||
$pdf->tempDir = '/home/john/temp';
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
Please consult the source files for a full documentation of each method.
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
{
|
||||
"name": "mikehaertl/php-pdftk",
|
||||
"description": "A PDF conversion and form utility based on pdftk.",
|
||||
"keywords": ["pdf", "pdftk"],
|
||||
"type": "library",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Michael Haertl",
|
||||
"email": "haertl.mike@gmail.com"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.3.0",
|
||||
"mikehaertl/php-shellcommand": "^1.6.3",
|
||||
"mikehaertl/php-tmpfile": "^1.1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": ">4.0 <9.4"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"mikehaertl\\pdftk\\": "src/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"tests\\": "tests"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,249 +0,0 @@
|
|||
<?php
|
||||
namespace mikehaertl\pdftk;
|
||||
|
||||
use mikehaertl\shellcommand\Command as BaseCommand;
|
||||
|
||||
/**
|
||||
* Command
|
||||
*
|
||||
* This class represents an pdftk shell command. It extends a standard
|
||||
* shellcommand and adds pdftk specific features to add options and operations.
|
||||
*
|
||||
* @author Michael Härtl <haertl.mike@gmail.com>
|
||||
* @license http://www.opensource.org/licenses/MIT
|
||||
*/
|
||||
class Command extends BaseCommand
|
||||
{
|
||||
/**
|
||||
* @var string the pdftk binary
|
||||
*/
|
||||
protected $_command = 'pdftk';
|
||||
|
||||
/**
|
||||
* @var array list of input files to process as array('name' => $filename,
|
||||
* 'password' => $pw) indexed by handle
|
||||
*/
|
||||
protected $_files = array();
|
||||
|
||||
/**
|
||||
* @var array list of command options, either strings or array with
|
||||
* arguments to addArg()
|
||||
*/
|
||||
protected $_options = array();
|
||||
|
||||
/**
|
||||
* @var string the operation to perform
|
||||
*/
|
||||
protected $_operation;
|
||||
|
||||
/**
|
||||
* @var string|array operation arguments, e.g. a list of page ranges or a
|
||||
* filename or tmp file instance
|
||||
*/
|
||||
protected $_operationArgument = array();
|
||||
|
||||
/**
|
||||
* @var bool whether to force escaping of the operation argument e.g. for
|
||||
* filenames
|
||||
*/
|
||||
protected $_escapeOperationArgument = false;
|
||||
|
||||
/**
|
||||
* @param string $name the PDF file to add for processing
|
||||
* @param string $handle one or more uppercase letters A..Z to reference
|
||||
* this file later.
|
||||
* @param string|null $password the owner (or user) password if any
|
||||
* @return Command the command instance for method chaining
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function addFile($name, $handle, $password = null)
|
||||
{
|
||||
$this->checkExecutionStatus();
|
||||
$file = array(
|
||||
'name' => $name,
|
||||
'password' => $password,
|
||||
);
|
||||
$this->_files[$handle] = $file;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $option the pdftk option to add
|
||||
* @param string|File|null $argument the argument to add, either string,
|
||||
* File instance or null if none
|
||||
* @param null|bool whether to escape the option. Default is null meaning
|
||||
* use Command default setting.
|
||||
* @return Command the command instance for method chaining
|
||||
*/
|
||||
public function addOption($option, $argument = null, $escape = null)
|
||||
{
|
||||
$this->_options[] = $argument === null ? $option : array($option, $argument, $escape);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $operation the operation to perform
|
||||
* @return Command the command instance for method chaining
|
||||
*/
|
||||
public function setOperation($operation)
|
||||
{
|
||||
$this->checkExecutionStatus();
|
||||
$this->_operation = $operation;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null the current operation or null if none set
|
||||
*/
|
||||
public function getOperation()
|
||||
{
|
||||
return $this->_operation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value the operation argument
|
||||
* @param bool $escape whether to escape the operation argument
|
||||
* @return Command the command instance for method chaining
|
||||
*/
|
||||
public function setOperationArgument($value, $escape = false)
|
||||
{
|
||||
$this->checkExecutionStatus();
|
||||
$this->_operationArgument = $value;
|
||||
$this->_escapeOperationArgument = $escape;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|array|null the current operation argument as string or
|
||||
* array or null if none set
|
||||
*/
|
||||
public function getOperationArgument()
|
||||
{
|
||||
// Typecast to string in case we have a File instance as argument
|
||||
return is_array($this->_operationArgument) ? $this->_operationArgument : (string) $this->_operationArgument;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int the number of files added to the command
|
||||
*/
|
||||
public function getFileCount()
|
||||
{
|
||||
return count($this->_files);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a page range as used by some operations
|
||||
*
|
||||
* @param int|string|array $start the start page number or an array of page
|
||||
* numbers. If an array, the other arguments will be ignored. $start can
|
||||
* also be bigger than $end for pages in reverse order.
|
||||
* @param int|string|null $end the end page number or null for single page
|
||||
* (or list if $start is an array)
|
||||
* @param string|null $handle the handle of the file to use. Can be null if
|
||||
* only a single file was added.
|
||||
* @param string|null $qualifier the page number qualifier, either 'even'
|
||||
* or 'odd' or null for none
|
||||
* @param string $rotation the rotation to apply to the pages.
|
||||
* @return Command the command instance for method chaining
|
||||
*/
|
||||
public function addPageRange($start, $end = null, $handle = null, $qualifier = null, $rotation = null)
|
||||
{
|
||||
$this->checkExecutionStatus();
|
||||
if (is_array($start)) {
|
||||
if ($handle !== null) {
|
||||
$start = array_map(function ($p) use ($handle) {
|
||||
return $handle . $p;
|
||||
}, $start);
|
||||
}
|
||||
$range = implode(' ', $start);
|
||||
} else {
|
||||
$range = $handle . $start;
|
||||
if ($end) {
|
||||
$range .= '-' . $end;
|
||||
}
|
||||
$range .= $qualifier . $rotation;
|
||||
}
|
||||
$this->_operationArgument[] = $range;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $filename the filename to add as 'output' option or
|
||||
* null if none
|
||||
* @return bool whether the command was executed successfully
|
||||
*/
|
||||
public function execute($filename = null)
|
||||
{
|
||||
$this->checkExecutionStatus();
|
||||
$this->processInputFiles();
|
||||
$this->processOperation();
|
||||
$this->processOptions($filename);
|
||||
return parent::execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process input PDF files and create respective command arguments
|
||||
*/
|
||||
protected function processInputFiles()
|
||||
{
|
||||
$passwords = array();
|
||||
foreach ($this->_files as $handle => $file) {
|
||||
$this->addArg($handle . '=', $file['name']);
|
||||
if ($file['password'] !== null) {
|
||||
$passwords[$handle] = $file['password'];
|
||||
}
|
||||
}
|
||||
if ($passwords !== array()) {
|
||||
$this->addArg('input_pw');
|
||||
foreach ($passwords as $handle => $password) {
|
||||
$this->addArg($handle . '=', $password);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process options and create respective command arguments
|
||||
* @param string|null $filename if provided an 'output' option will be
|
||||
* added
|
||||
*/
|
||||
protected function processOptions($filename = null)
|
||||
{
|
||||
// output must be first option after operation
|
||||
if ($filename !== null) {
|
||||
$this->addArg('output', $filename, true);
|
||||
}
|
||||
foreach ($this->_options as $option) {
|
||||
if (is_array($option)) {
|
||||
$this->addArg($option[0], $option[1], $option[2]);
|
||||
} else {
|
||||
$this->addArg($option);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process opearation and create respective command arguments
|
||||
*/
|
||||
protected function processOperation()
|
||||
{
|
||||
if ($this->_operation !== null) {
|
||||
$value = $this->_operationArgument ? $this->_operationArgument : null;
|
||||
if ($value instanceof TmpFile) {
|
||||
$value = (string) $value;
|
||||
}
|
||||
$this->addArg($this->_operation, $value, $this->_escapeOperationArgument);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that the command was not exectued yet. Throws exception
|
||||
* otherwise.
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function checkExecutionStatus()
|
||||
{
|
||||
if ($this->getExecuted()) {
|
||||
throw new \Exception('Operation was already executed');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,166 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace mikehaertl\pdftk;
|
||||
|
||||
use ArrayObject;
|
||||
|
||||
/**
|
||||
* This class is an array representation of the dump_data_fields output of
|
||||
* pdftk.
|
||||
*
|
||||
* @author Ray Holland <raymondaholland+php-pdftk@gmail.com>
|
||||
* @author Michael Härtl <haertl.mike@gmail.com>
|
||||
* @license http://www.opensource.org/licenses/MIT
|
||||
*/
|
||||
class DataFields extends ArrayObject
|
||||
{
|
||||
private $_string;
|
||||
private $_array;
|
||||
|
||||
/**
|
||||
* DataFields constructor.
|
||||
*
|
||||
* @param string $input
|
||||
* @param int $flags
|
||||
* @param string $iterator_class
|
||||
*/
|
||||
public function __construct($input = null, $flags = 0, $iterator_class = "ArrayIterator")
|
||||
{
|
||||
$this->_string = $input ?: '';
|
||||
$this->_array = self::parse($this->_string);
|
||||
|
||||
return parent::__construct($this->_array, $flags, $iterator_class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->_string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function __toArray()
|
||||
{
|
||||
return $this->_array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the output of dump_data_fields into an array.
|
||||
*
|
||||
* The string to parse can either be a single block of `Xyz:value` lines
|
||||
* or a set of such blocks, separated by and starting with `---`.
|
||||
*
|
||||
*
|
||||
* Here's an example:
|
||||
*
|
||||
* ```
|
||||
* ---
|
||||
* FieldType: Text
|
||||
* FieldName: Text1
|
||||
* FieldFlags: 0
|
||||
* FieldValue: University of Missouri : Ray-Holland
|
||||
* extended line value
|
||||
* FieldValueDefault: University of Missouri : Ray-Holland
|
||||
* extended line2 value
|
||||
* FieldJustification: Left
|
||||
* FieldMaxLength: 99
|
||||
* ---
|
||||
* FieldType: Text
|
||||
* FieldName: Text2
|
||||
* ...
|
||||
* ...
|
||||
* ```
|
||||
*
|
||||
* @param $input the string to parse
|
||||
* @return array the parsed result
|
||||
*/
|
||||
public static function parse($input)
|
||||
{
|
||||
if (strncmp('---', $input, 3) === 0) {
|
||||
// Split blocks only if '---' is followed by 'FieldType'
|
||||
$blocks = preg_split(
|
||||
'/^---(\r\n|\n|\r)(?=FieldType:)/m',
|
||||
substr($input, 3)
|
||||
);
|
||||
return array_map('\mikehaertl\pdftk\DataFields::parseBlock', $blocks);
|
||||
} else {
|
||||
return self::parseBlock($input);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a block of this form:
|
||||
*
|
||||
* ```
|
||||
* Name1: Value1
|
||||
* Name2: Value2
|
||||
* Name3: Value3
|
||||
* ...
|
||||
* ```
|
||||
*
|
||||
* @param string $block the block to parse
|
||||
* @return array the parsed block values indexed by respective names
|
||||
*/
|
||||
public static function parseBlock($block)
|
||||
{
|
||||
$data = array();
|
||||
$lines = preg_split("/(\r\n|\n|\r)/", trim($block));
|
||||
$continueKey = null;
|
||||
foreach ($lines as $n => $line) {
|
||||
if ($continueKey !== null) {
|
||||
$data[$continueKey] .= "\n" . $line;
|
||||
if (!self::lineContinues($lines, $n, $continueKey)) {
|
||||
$continueKey = null;
|
||||
}
|
||||
} elseif (preg_match('/([^:]*): ?(.*)/', $line, $match)) {
|
||||
$key = $match[1];
|
||||
$value = $match[2];
|
||||
// Convert multiple keys like 'FieldStateOption' or 'FieldValue'
|
||||
// from Choice fields to array
|
||||
if (isset($data[$key])) {
|
||||
$data[$key] = (array) $data[$key];
|
||||
$data[$key][] = $value;
|
||||
} else {
|
||||
$data[$key] = $value;
|
||||
}
|
||||
if (self::lineContinues($lines, $n, $key)) {
|
||||
$continueKey = $key;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the value for the given line number continues on the next
|
||||
* line, i.e. is a multiline string.
|
||||
*
|
||||
* This can be the case for 'FieldValue' and 'FieldValueDefault' keys. To
|
||||
* find the end of the string we don't simply test for /^Field/, as this
|
||||
* would also match multiline strings where a line starts with 'Field'.
|
||||
*
|
||||
* Instead we assume that the string is always followed by one of these
|
||||
* keys:
|
||||
*
|
||||
* - 'FieldValue:'
|
||||
* - 'FieldValueDefault:'
|
||||
* - 'FieldJustification:'
|
||||
*
|
||||
* @param array $lines all lines of the block
|
||||
* @param int $n the 0-based index of the current line
|
||||
* @param string the key for the value. Only 'FieldValue' and
|
||||
* 'FieldValueDefault' can span multiple lines
|
||||
* @return bool whether the value continues in line n + 1
|
||||
*/
|
||||
protected static function lineContinues($lines, $n, $key)
|
||||
{
|
||||
return
|
||||
in_array($key, array('FieldValue', 'FieldValueDefault')) &&
|
||||
array_key_exists($n + 1, $lines) &&
|
||||
!preg_match('/^Field(Value|ValueDefault|Justification):/', $lines[$n + 1]);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
<?php
|
||||
namespace mikehaertl\pdftk;
|
||||
|
||||
use mikehaertl\tmp\File;
|
||||
|
||||
/**
|
||||
* FdfFile
|
||||
*
|
||||
* This class represents a temporary FDF (1.2) file that can be used to fill a
|
||||
* PDF form with valid unicode characters.
|
||||
*
|
||||
* @author Michael Härtl <haertl.mike@gmail.com>
|
||||
* @license http://www.opensource.org/licenses/MIT
|
||||
*/
|
||||
class FdfFile extends File
|
||||
{
|
||||
// FDF file header
|
||||
const FDF_HEADER = <<<FDF
|
||||
%FDF-1.2
|
||||
1 0 obj<</FDF<< /Fields[
|
||||
FDF;
|
||||
|
||||
// FDF file footer
|
||||
const FDF_FOOTER = <<<FDF
|
||||
] >> >>
|
||||
endobj
|
||||
trailer
|
||||
<</Root 1 0 R>>
|
||||
%%EOF
|
||||
FDF;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $data the form data as name => value
|
||||
* @param string|null $suffix the optional suffix for the tmp file
|
||||
* @param string|null $suffix the optional prefix for the tmp file. If null
|
||||
* 'php_tmpfile_' is used.
|
||||
* @param string|null $directory directory where the file should be
|
||||
* created. Autodetected if not provided.
|
||||
* @param string|null $encoding of the data. Default is 'UTF-8'.
|
||||
*/
|
||||
public function __construct($data, $suffix = null, $prefix = null, $directory = null, $encoding = 'UTF-8')
|
||||
{
|
||||
if ($directory === null) {
|
||||
$directory = self::getTempDir();
|
||||
}
|
||||
$suffix = '.fdf';
|
||||
$prefix = 'php_pdftk_fdf_';
|
||||
|
||||
$this->_fileName = tempnam($directory, $prefix);
|
||||
$newName = $this->_fileName . $suffix;
|
||||
rename($this->_fileName, $newName);
|
||||
$this->_fileName = $newName;
|
||||
|
||||
if (!function_exists('mb_convert_encoding')) {
|
||||
throw new \Exception('MB extension required.');
|
||||
}
|
||||
|
||||
$fields = '';
|
||||
foreach ($data as $key => $value) {
|
||||
// Create UTF-16BE string encode as ASCII hex
|
||||
// See http://blog.tremily.us/posts/PDF_forms/
|
||||
$utf16Value = mb_convert_encoding($value, 'UTF-16BE', $encoding);
|
||||
|
||||
/* Also create UTF-16BE encoded key, this allows field names containing
|
||||
* german umlauts and most likely many other "special" characters.
|
||||
* See issue #17 (https://github.com/mikehaertl/php-pdftk/issues/17)
|
||||
*/
|
||||
$utf16Key = mb_convert_encoding($key, 'UTF-16BE', $encoding);
|
||||
|
||||
// Escape parenthesis
|
||||
$utf16Value = strtr($utf16Value, array('(' => '\\(', ')' => '\\)'));
|
||||
$fields .= "<</T(" . chr(0xFE) . chr(0xFF) . $utf16Key . ")/V(" . chr(0xFE) . chr(0xFF) . $utf16Value . ")>>\n";
|
||||
}
|
||||
|
||||
// Use fwrite, since file_put_contents() messes around with character encoding
|
||||
$fp = fopen($this->_fileName, 'w');
|
||||
fwrite($fp, self::FDF_HEADER);
|
||||
fwrite($fp, $fields);
|
||||
fwrite($fp, self::FDF_FOOTER);
|
||||
fclose($fp);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,139 +0,0 @@
|
|||
<?php
|
||||
namespace mikehaertl\pdftk;
|
||||
|
||||
use ArrayObject;
|
||||
|
||||
/**
|
||||
* Class InfoFields
|
||||
* Derived from DataFields
|
||||
*
|
||||
* @author Burak USGURLU <burak@uskur.com.tr>
|
||||
* @license http://www.opensource.org/licenses/MIT
|
||||
*/
|
||||
class InfoFields extends ArrayObject
|
||||
{
|
||||
private $_string;
|
||||
|
||||
private $_array;
|
||||
|
||||
/**
|
||||
* InfoFields constructor.
|
||||
*
|
||||
* @param string $input
|
||||
* @param int $flags
|
||||
* @param string $iterator_class
|
||||
*/
|
||||
public function __construct($input = null, $flags = 0, $iterator_class = "ArrayIterator")
|
||||
{
|
||||
$this->_string = $input ?: '';
|
||||
$this->_array = $this->parseData($this->_string);
|
||||
|
||||
return parent::__construct($this->_array, $flags, $iterator_class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->_string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function __toArray()
|
||||
{
|
||||
return $this->_array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the output of dump_data into something usable.
|
||||
*
|
||||
* The expected string looks similar to this:
|
||||
*
|
||||
* InfoBegin
|
||||
* InfoKey: Creator
|
||||
* InfoValue: Adobe Acrobat Pro DC 15.0
|
||||
* InfoBegin
|
||||
* InfoKey: Producer
|
||||
* InfoValue: XYZ
|
||||
* PdfID0: 1fdce9ed1153ab4c973334b512a67997
|
||||
* PdfID1: c7acc878cda02ad7bb401fa8080a8929
|
||||
* NumberOfPages: 11
|
||||
* BookmarkBegin
|
||||
* BookmarkTitle: First bookmark
|
||||
* BookmarkLevel: 1
|
||||
* BookmarkPageNumber: 1
|
||||
* BookmarkBegin
|
||||
* BookmarkTitle: Second bookmark
|
||||
* BookmarkLevel: 1
|
||||
* BookmarkPageNumber: 2
|
||||
*
|
||||
* @param $dataString
|
||||
* @return array
|
||||
*/
|
||||
private function parseData($dataString)
|
||||
{
|
||||
$output = array();
|
||||
foreach (explode(PHP_EOL, $dataString) as $line) {
|
||||
$trimmedLine = trim($line);
|
||||
// Parse blocks of the form:
|
||||
// AbcBegin
|
||||
// AbcData1: Value1
|
||||
// AbcData2: Value2
|
||||
// AbcBegin
|
||||
// AbcData1: Value3
|
||||
// AbcData2: Value4
|
||||
// ...
|
||||
if (preg_match('/^(\w+)Begin$/', $trimmedLine, $matches)) {
|
||||
// Previous group ended - if any - so add it to output
|
||||
if (!empty($group) && !empty($groupData)) {
|
||||
$output[$group][] = $groupData;
|
||||
}
|
||||
// Now start next group
|
||||
$group = $matches[1]; // Info, PageMedia, ...
|
||||
if (!isset($output[$group])) {
|
||||
$output[$group] = array();
|
||||
}
|
||||
$groupData = array();
|
||||
continue;
|
||||
}
|
||||
if (!empty($group)) {
|
||||
// Check for AbcData1: Value1
|
||||
if (preg_match("/^$group(\w+): ?(.*)$/", $trimmedLine, $matches)) {
|
||||
$groupData[$matches[1]] = $matches[2];
|
||||
continue;
|
||||
} else {
|
||||
// Something else, so group ended
|
||||
if (!empty($groupData)) {
|
||||
$output[$group][] = $groupData;
|
||||
$groupData = array();
|
||||
}
|
||||
$group = null;
|
||||
}
|
||||
}
|
||||
if (preg_match('/([^:]*): ?(.*)/', $trimmedLine, $matches)) {
|
||||
$output[$matches[1]] = $matches[2];
|
||||
}
|
||||
}
|
||||
// There could be a final group left if it was not followed by another
|
||||
// line in the loop
|
||||
if (!empty($group) && !empty($groupData)) {
|
||||
$output[$group][] = $groupData;
|
||||
}
|
||||
|
||||
// Info group is a list of ['Key' => 'x', 'Value' => 'y'], so
|
||||
// convert it to ['x' => 'y', ...]
|
||||
if (isset($output['Info'])) {
|
||||
$data = array();
|
||||
foreach ($output['Info'] as $infoGroup) {
|
||||
if (isset($infoGroup['Key'], $infoGroup['Value'])) {
|
||||
$data[$infoGroup['Key']] = $infoGroup['Value'];
|
||||
}
|
||||
}
|
||||
$output['Info'] = $data;
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,190 +0,0 @@
|
|||
<?php
|
||||
namespace mikehaertl\pdftk;
|
||||
|
||||
use Exception;
|
||||
use mikehaertl\tmp\File;
|
||||
|
||||
/**
|
||||
* InfoFile
|
||||
*
|
||||
* This class represents a temporary dump_data compatible file that can be used to update meta data of PDF
|
||||
* with valid unicode characters.
|
||||
*
|
||||
* @author Burak Usgurlu <burak@uskur.com.tr>
|
||||
* @license http://www.opensource.org/licenses/MIT
|
||||
*/
|
||||
class InfoFile extends File
|
||||
{
|
||||
/**
|
||||
* @var string[] list of valid keys for the document information directory of
|
||||
* the PDF. These will be converted into `InfoBegin... InfoKey... InvoValue`
|
||||
* blocks on the output.
|
||||
*
|
||||
* See section 14.3.3 in https://opensource.adobe.com/dc-acrobat-sdk-docs/pdfstandards/PDF32000_2008.pdf
|
||||
*/
|
||||
public static $documentInfoFields = array(
|
||||
'Title',
|
||||
'Author',
|
||||
'Subject',
|
||||
'Keywords',
|
||||
'Creator',
|
||||
'Producer',
|
||||
'CreationDate',
|
||||
'ModDate',
|
||||
'Trapped',
|
||||
);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array|InfoFields $data the data in this format:
|
||||
* ```
|
||||
* [
|
||||
* 'Info' => [
|
||||
* 'Title' => '...',
|
||||
* 'Author' => '...',
|
||||
* 'Subject' => '...',
|
||||
* 'Keywords' => '...',
|
||||
* 'Creator' => '...',
|
||||
* 'Producer' => '...',
|
||||
* 'CreationDate' => '...',
|
||||
* 'ModDate' => '...',
|
||||
* 'Trapped' => '...',
|
||||
* ],
|
||||
* 'Bookmark' => [
|
||||
* [
|
||||
* 'Title' => '...',
|
||||
* 'Level' => ...,
|
||||
* 'PageNumber' => ...,
|
||||
* ],
|
||||
* ],
|
||||
* 'PageMedia' => [ ... ],
|
||||
* 'PageLabel' => [ ... ],
|
||||
* // ...
|
||||
* ]
|
||||
* ```
|
||||
* This is the same format as the InfoFields object that is returned
|
||||
* by `getData()` if you cast it to an array. You can also pass such an
|
||||
* (optionally modified) object as input. Some fields like 'NumberOfPages'
|
||||
* or 'PdfID0' are ignored as those are not part of the PDF's metadata.
|
||||
* All array elements are optional.
|
||||
* @param string|null $suffix the optional suffix for the tmp file
|
||||
* @param string|null $suffix the optional prefix for the tmp file. If null
|
||||
* 'php_tmpfile_' is used.
|
||||
* @param string|null $directory directory where the file should be
|
||||
* created. Autodetected if not provided.
|
||||
* @param string|null $encoding of the data. Default is 'UTF-8'. If the
|
||||
* data has another encoding it will be converted to UTF-8. This requires
|
||||
* the mbstring extension to be installed.
|
||||
* @throws Exception on invalid data format or if mbstring extension is
|
||||
* missing and data must be converted
|
||||
*/
|
||||
public function __construct($data, $suffix = null, $prefix = null, $directory = null, $encoding = 'UTF-8')
|
||||
{
|
||||
if ($suffix === null) {
|
||||
$suffix = '.txt';
|
||||
}
|
||||
if ($prefix === null) {
|
||||
$prefix = 'php_pdftk_info_';
|
||||
}
|
||||
if ($directory === null) {
|
||||
$directory = self::getTempDir();
|
||||
}
|
||||
|
||||
$tempName = tempnam($directory, $prefix);
|
||||
$newName = $tempName . $suffix;
|
||||
rename($tempName, $newName);
|
||||
$this->_fileName = $newName;
|
||||
|
||||
if ($encoding !== 'UTF-8' && !function_exists('mb_convert_encoding')) {
|
||||
throw new Exception('mbstring extension required.');
|
||||
}
|
||||
|
||||
$fields = '';
|
||||
$normalizedData = self::normalize($data);
|
||||
|
||||
foreach ($normalizedData as $block => $items) {
|
||||
$fields .= self::renderBlock($block, $items, $encoding);
|
||||
}
|
||||
|
||||
// Use fwrite, since file_put_contents() messes around with character encoding
|
||||
$fp = fopen($this->_fileName, 'w');
|
||||
fwrite($fp, $fields);
|
||||
fclose($fp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize the input data
|
||||
*
|
||||
* This also converts data from the legacy format (<0.13.0) to the new
|
||||
* input format described in the constructor.
|
||||
*
|
||||
* @param array $data the data to normalize
|
||||
* @return array a normalized array in the format described in the constructor
|
||||
*/
|
||||
private static function normalize($data)
|
||||
{
|
||||
$normalized = array();
|
||||
foreach ($data as $key => $value) {
|
||||
if (in_array($key, self::$documentInfoFields)) {
|
||||
$normalized['Info'][$key] = $value;
|
||||
} elseif (is_array($value)) {
|
||||
if (!isset($normalized[$key])) {
|
||||
$normalized[$key] = array();
|
||||
}
|
||||
$normalized[$key] = array_merge($normalized[$key], $value);
|
||||
}
|
||||
}
|
||||
return $normalized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a set of block fields
|
||||
*
|
||||
* @param string $block like 'Info', 'Bookmark', etc.
|
||||
* @param array $items the field items to render
|
||||
* @param string $encoding the encoding of the item data
|
||||
* @return string the rendered fields
|
||||
*/
|
||||
private static function renderBlock($block, $items, $encoding)
|
||||
{
|
||||
$fields = '';
|
||||
foreach ($items as $key => $value) {
|
||||
if ($block === 'Info') {
|
||||
$fields .= self::renderField($block, $key, $value, $encoding, true);
|
||||
} else {
|
||||
$fields .= "{$block}Begin\n";
|
||||
foreach ($value as $subKey => $subValue) {
|
||||
$fields .= self::renderField($block, $subKey, $subValue, $encoding, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a field in a given input block
|
||||
*
|
||||
* @param string $prefix the prefix to use for the field
|
||||
* @param string $key the field key
|
||||
* @param string $value the field value
|
||||
* @param string $encoding the endoding of key and value
|
||||
* @param bool $isInfo whether it's an 'Info' field
|
||||
* @return string the rendered field
|
||||
*/
|
||||
private static function renderField($prefix, $key, $value, $encoding, $isInfo)
|
||||
{
|
||||
if ($encoding !== 'UTF-8') {
|
||||
$value = mb_convert_encoding($value, 'UTF-8', $encoding);
|
||||
$key = mb_convert_encoding($key, 'UTF-8', $encoding);
|
||||
$value = defined('ENT_XML1') ? htmlspecialchars($key, ENT_XML1, 'UTF-8') : htmlspecialchars($key);
|
||||
$key = defined('ENT_XML1') ? htmlspecialchars($value, ENT_XML1, 'UTF-8') : htmlspecialchars($value);
|
||||
}
|
||||
if ($isInfo) {
|
||||
return "InfoBegin\nInfoKey: $key\nInfoValue: $value\n";
|
||||
} else {
|
||||
return "{$prefix}{$key}: $value\n";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,749 +0,0 @@
|
|||
<?php
|
||||
namespace mikehaertl\pdftk;
|
||||
|
||||
use mikehaertl\tmp\File;
|
||||
|
||||
/**
|
||||
* Pdf
|
||||
*
|
||||
* This class is a wrapper around pdftk.
|
||||
*
|
||||
* The class was developed for pdftk 2.x but should also work with older
|
||||
* versions, but you may have to use slightly different page rotation options
|
||||
* (e.g 'E' instead 'east').
|
||||
*
|
||||
* @author Michael Härtl <haertl.mike@gmail.com>
|
||||
* @license http://www.opensource.org/licenses/MIT
|
||||
*/
|
||||
class Pdf
|
||||
{
|
||||
// The prefix for temporary files
|
||||
const TMP_PREFIX = 'tmp_php_pdftk_';
|
||||
|
||||
/**
|
||||
* @var bool whether to ignore any errors if some non-empty output file was
|
||||
* still created. Default is false.
|
||||
*/
|
||||
public $ignoreWarnings = false;
|
||||
|
||||
/**
|
||||
* @var null|string an optional directory where temporary files should be
|
||||
* created. If left empty the directory is autodetected.
|
||||
*/
|
||||
public $tempDir;
|
||||
|
||||
/**
|
||||
* @var File the temporary output file
|
||||
*/
|
||||
protected $_tmpFile;
|
||||
|
||||
/**
|
||||
* @var string the content type of the tmp output
|
||||
*/
|
||||
protected $_tmpOutputContentType = 'application/pdf';
|
||||
|
||||
/**
|
||||
* @var Command the command instance that executes pdftk
|
||||
*/
|
||||
protected $_command;
|
||||
|
||||
/**
|
||||
* @var int a counter for autogenerated handles
|
||||
*/
|
||||
protected $_handle = 0;
|
||||
|
||||
/**
|
||||
* @var string the error message
|
||||
*/
|
||||
protected $_error = '';
|
||||
|
||||
/**
|
||||
* @var string|null the output filename. If null (default) a tmp file is
|
||||
* used as output. If false, no output option is added at all.
|
||||
*/
|
||||
protected $_output;
|
||||
|
||||
/**
|
||||
* @var string the PDF data as returned from getData()
|
||||
*/
|
||||
protected $_data;
|
||||
protected $_data_utf8;
|
||||
|
||||
/**
|
||||
* @var DataFields the PDF form field data as returned from getDataFields()
|
||||
*/
|
||||
protected $_dataFields;
|
||||
protected $_dataFields_utf8;
|
||||
|
||||
/**
|
||||
* @var Pdf[]|null if the input was an instance, we keep a reference here,
|
||||
* so that it won't get unlinked before this object gets destroyed
|
||||
*/
|
||||
protected $_pdfs;
|
||||
|
||||
/**
|
||||
* @param string|Pdf|array $pdf a pdf filename or Pdf instance or an array
|
||||
* of filenames/instances indexed by a handle. The array values can also
|
||||
* be arrays of the form array($filename, $password) if some files are
|
||||
* password protected.
|
||||
* @param array $options Options to pass to set on the Command instance,
|
||||
* e.g. the pdftk binary path
|
||||
*/
|
||||
public function __construct($pdf = null, $options = array())
|
||||
{
|
||||
$command = $this->getCommand();
|
||||
if ($options !== array()) {
|
||||
$command->setOptions($options);
|
||||
}
|
||||
if (is_string($pdf) || $pdf instanceof Pdf) {
|
||||
$this->addFile($pdf);
|
||||
} elseif (is_array($pdf)) {
|
||||
foreach ($pdf as $handle => $file) {
|
||||
if (is_array($file)) {
|
||||
$this->addFile($file[0], $handle, $file[1]);
|
||||
} else {
|
||||
$this->addFile($file, $handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|Pdf $name the PDF filename or Pdf instance to add for
|
||||
* processing
|
||||
* @param string|null $handle one or more uppercase letters A..Z to
|
||||
* reference this file later. If no handle is provided, an internal handle
|
||||
* is autocreated, consuming the range Z..A
|
||||
* @param string|null $password the owner (or user) password if any
|
||||
* @return Pdf the pdf instance for method chaining
|
||||
*/
|
||||
public function addFile($name, $handle = null, $password = null)
|
||||
{
|
||||
if ($handle === null || is_numeric($handle)) {
|
||||
$handle = $this->nextHandle();
|
||||
}
|
||||
if ($name instanceof Pdf) {
|
||||
// Keep a reference to the object to prevent unlinking
|
||||
$this->_pdfs[] = $name;
|
||||
if (!$name->getCommand()->getExecuted()) {
|
||||
// @todo: Catch errors!
|
||||
$name->execute();
|
||||
}
|
||||
$name = (string) $name->getTmpFile();
|
||||
}
|
||||
$this->getCommand()->addFile($name, $handle, $password);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assemble (catenate) pages from the input files.
|
||||
*
|
||||
* Values for rotation are (in degrees): north: 0, east: 90, south: 180,
|
||||
* west: 270, left: -90, right: +90, down: +180. left, right and down make
|
||||
* relative adjustments to a page's rotation. Note: Older pdftk versions
|
||||
* use N, E, S, W, L, R, and D instead.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* $pdf = new Pdf;
|
||||
* $pdf->addFile('file1.pdf', 'A')
|
||||
* ->addFile('file2.pdf', 'B')
|
||||
* ->cat(array(1,3),'B')) // pages 1 and 3 of file B
|
||||
* ->cat(1, 5, 'A', 'odd') // pages 1, 3, 5 of file A
|
||||
* ->cat('end', 5, 'B') // pages 5 to end of file B in reverse order
|
||||
* ->cat(null, null, 'B', 'east') // All pages from file B rotated by 90 degree
|
||||
* ->saveAs('out.pdf');
|
||||
* or
|
||||
* $files = ['file1.pdf', 'file2.pdf', 'file3.pdf'];
|
||||
* $pdf = new Pdf($files);
|
||||
* $pdf->cat() // all files, all pages
|
||||
* ->saveAs('out.pdf');
|
||||
*
|
||||
* @param int|string|array|null $start the start page number or an array of page
|
||||
* numbers. If an array, the other arguments will be ignored. $start can
|
||||
* also be bigger than $end for pages in reverse order. If $start is null all
|
||||
* pages of all files will be added.
|
||||
* @param int|string|null $end the end page number or null for single page
|
||||
* (or list if $start is an array)
|
||||
* @param string|null $handle the handle of the file to use. Can be null if
|
||||
* only a single file was added.
|
||||
* @param string|null $qualifier the page number qualifier, either 'even'
|
||||
* or 'odd' or null for none
|
||||
* @param string $rotation the rotation to apply to the pages.
|
||||
* @return Pdf the pdf instance for method chaining
|
||||
*/
|
||||
public function cat($start = null, $end = null, $handle = null, $qualifier = null, $rotation = null)
|
||||
{
|
||||
$this->getCommand()
|
||||
->setOperation('cat')
|
||||
->addPageRange($start, $end, $handle, $qualifier, $rotation);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shuffle pages from the input files.
|
||||
*
|
||||
* This works the same as cat(), but each call to this method creates a
|
||||
* "stream" of pages. The outfile will be assembled by adding one page from
|
||||
* each stream at a time.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* $pdf = new Pdf;
|
||||
* $pdf1 = $pdf->addFile('file1.pdf');
|
||||
* $pdf->shuffle($pdf1, array(1,3,2))
|
||||
* ->shuffle($pdf1, array(4,5,9)
|
||||
* ->saveAs('out.pdf');
|
||||
*
|
||||
* This will give the page order 1, 4, 3, 5, 2, 9 in the out.pdf
|
||||
*
|
||||
* @param string $handle the handle of the input file to use
|
||||
* @param int|array $start the start page number or an array of page
|
||||
* numbers.
|
||||
* @param int|null $end the end page number or null for single page (or
|
||||
* list if $start is an array)
|
||||
* @param string|null $qualifier the page number qualifier, either 'even'
|
||||
* or 'odd' or null for none
|
||||
* @param string $rotation the rotation to apply to the pages. See cat()
|
||||
* for more details.
|
||||
* @return Pdf the pdf instance for method chaining
|
||||
*/
|
||||
public function shuffle($start, $end = null, $handle = null, $qualifier = null, $rotation = null)
|
||||
{
|
||||
$this->getCommand()
|
||||
->setOperation('shuffle')
|
||||
->addPageRange($start, $end, $handle, $qualifier, $rotation);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Split the PDF document into pages
|
||||
*
|
||||
* @param string|null $filepattern the output name in sprintf format or
|
||||
* null for default 'pg_%04d.pdf'
|
||||
* @return bool whether the burst operation was successful
|
||||
*/
|
||||
public function burst($filepattern = null)
|
||||
{
|
||||
$this->constrainSingleFile();
|
||||
$this->getCommand()->setOperation('burst');
|
||||
$this->_output = $filepattern === null ? 'pg_%04d.pdf' : $filepattern;
|
||||
return $this->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach files to the PDF
|
||||
*
|
||||
* @param array $files the list of full paths to the files to attach
|
||||
* @param string $toPage the page to add the attachment to. If omitted the
|
||||
* files are attached at the document level.
|
||||
* @return bool whether the operation was successful
|
||||
*/
|
||||
public function attachFiles($files, $toPage = null)
|
||||
{
|
||||
$this->constrainSingleFile();
|
||||
if ($toPage !== null) {
|
||||
$files[] = 'to_page';
|
||||
$files[] = $toPage;
|
||||
}
|
||||
$this->getCommand()
|
||||
->setOperation('attach_files')
|
||||
->setOperationArgument($files, true);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy all attachments from the PDF to the given directory
|
||||
*
|
||||
* @param string|null $dir the output directory
|
||||
* @return bool whether the operation was successful
|
||||
*/
|
||||
public function unpackFiles($dir = null)
|
||||
{
|
||||
$this->constrainSingleFile();
|
||||
$this->getCommand()->setOperation('unpack_files');
|
||||
$this->_output = $dir;
|
||||
return $this->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the FDF file for a single PDF file.
|
||||
*
|
||||
* @param string $name name of the FDF file
|
||||
* @return bool whether the pdf is generated successful
|
||||
*/
|
||||
public function generateFdfFile($name)
|
||||
{
|
||||
$this->constrainSingleFile();
|
||||
$this->getCommand()->setOperation('generate_fdf');
|
||||
$this->_output = $name;
|
||||
return $this->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill a PDF form
|
||||
*
|
||||
* @param string|array $data either a XFDF/FDF filename or an array with
|
||||
* form field data (name => value)
|
||||
* @param string $encoding the encoding of the data. Default is 'UTF-8'.
|
||||
* @param bool $dropXfa whether to drop XFA forms (see dropXfa()). Default
|
||||
* is true.
|
||||
* @param string $format the file format to use for form filling when
|
||||
* passing an array in `$data`. This can be `xfdf` or `fdf`. `xfdf` should
|
||||
* give best results so you should not have to change the default.
|
||||
* @return Pdf the pdf instance for method chaining
|
||||
*/
|
||||
public function fillForm($data, $encoding = 'UTF-8', $dropXfa = true, $format = 'xfdf')
|
||||
{
|
||||
$this->constrainSingleFile();
|
||||
if (is_array($data)) {
|
||||
$className = '\mikehaertl\pdftk\\' . ($format === 'xfdf' ? 'XfdfFile' : 'FdfFile');
|
||||
$data = new $className($data, null, null, $this->tempDir, $encoding);
|
||||
}
|
||||
$this->getCommand()
|
||||
->setOperation('fill_form')
|
||||
->setOperationArgument($data, true);
|
||||
|
||||
if ($dropXfa) {
|
||||
$this->dropXfa();
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update meta data of PDF
|
||||
*
|
||||
* @param string|array $data either a InfoFile filename or an array with
|
||||
* form field data (name => value)
|
||||
* @param string the encoding of the data. Default is 'UTF-8'.
|
||||
* @return Pdf the pdf instance for method chaining
|
||||
*/
|
||||
public function updateInfo($data, $encoding = 'UTF-8')
|
||||
{
|
||||
$this->constrainSingleFile();
|
||||
if (is_array($data) || $data instanceof InfoFields) {
|
||||
$data = new InfoFile($data, null, null, $this->tempDir, $encoding);
|
||||
}
|
||||
$this->getCommand()
|
||||
->setOperation($encoding == 'UTF-8' ? 'update_info_utf8' : 'update_info')
|
||||
->setOperationArgument($data, true);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a PDF as watermark to the background of a single PDF file.
|
||||
*
|
||||
* The PDF file must have a transparent background for the watermark to be
|
||||
* visible.
|
||||
*
|
||||
* @param string $file name of the background PDF file. Only the first page
|
||||
* is used.
|
||||
* @return Pdf the pdf instance for method chaining
|
||||
*/
|
||||
public function background($file)
|
||||
{
|
||||
$this->constrainSingleFile();
|
||||
$this->getCommand()
|
||||
->setOperation('background')
|
||||
->setOperationArgument($file, true);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply multiple PDF pages as watermark to the corresponding pages of a
|
||||
* single PDF file.
|
||||
*
|
||||
* If $file has fewer pages than the PDF file then the last page is
|
||||
* repeated as background.
|
||||
*
|
||||
* @param string $file name of the background PDF file.
|
||||
* @return Pdf the pdf instance for method chaining
|
||||
*/
|
||||
public function multiBackground($file)
|
||||
{
|
||||
$this->getCommand()
|
||||
->setOperation('multibackground')
|
||||
->setOperationArgument($file, true);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add $file as overlay to a single PDF file.
|
||||
*
|
||||
* The $file should have a transparent background.
|
||||
*
|
||||
* @param string $file name of the PDF file to add as overlay. Only the
|
||||
* first page is used.
|
||||
* @return Pdf the pdf instance for method chaining
|
||||
*/
|
||||
public function stamp($file)
|
||||
{
|
||||
$this->constrainSingleFile();
|
||||
$this->getCommand()
|
||||
->setOperation('stamp')
|
||||
->setOperationArgument($file, true);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add multiple pages from $file as overlay to the corresponding pages of a
|
||||
* single PDF file.
|
||||
*
|
||||
* If $file has fewer pages than the PDF file then the last page is
|
||||
* repeated as overlay.
|
||||
*
|
||||
* @param string $file name of the PDF file to add as overlay
|
||||
* @return Pdf the pdf instance for method chaining
|
||||
*/
|
||||
public function multiStamp($file)
|
||||
{
|
||||
$this->getCommand()
|
||||
->setOperation('multistamp')
|
||||
->setOperationArgument($file, true);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $utf8 whether to dump the data UTF-8 encoded. Default is
|
||||
* true.
|
||||
* @return InfoFields|bool meta data about the PDF or false on failure
|
||||
*/
|
||||
public function getData($utf8 = true)
|
||||
{
|
||||
$property = $utf8 ? '_data_utf8' : '_data';
|
||||
if ($this->$property === null) {
|
||||
$command = $this->getCommand();
|
||||
$command->setOperation($utf8 ? 'dump_data_utf8' : 'dump_data');
|
||||
if (!$command->execute()) {
|
||||
$this->_error = $command->getError();
|
||||
return false;
|
||||
} else {
|
||||
$this->$property = new InfoFields(trim($command->getOutput()));
|
||||
}
|
||||
}
|
||||
return $this->$property;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $utf8 whether to dump the data UTF-8 encoded. Default is
|
||||
* true.
|
||||
* @return DataFields|bool data about the PDF form fields or false on
|
||||
* failure
|
||||
*/
|
||||
public function getDataFields($utf8 = true)
|
||||
{
|
||||
$property = $utf8 ? '_dataFields_utf8' : '_dataFields';
|
||||
if ($this->$property === null) {
|
||||
$command = $this->getCommand();
|
||||
$command->setOperation($utf8 ? 'dump_data_fields_utf8' : 'dump_data_fields');
|
||||
if (!$command->execute()) {
|
||||
$this->_error = $command->getError();
|
||||
return false;
|
||||
} else {
|
||||
$this->$property = new DataFields(trim($command->getOutput()));
|
||||
}
|
||||
}
|
||||
return $this->$property;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set PDF permissions
|
||||
*
|
||||
*
|
||||
* @param string|null $permissions list of space separated permissions or
|
||||
* null for none. The available permissions are Printing, DegradedPrinting,
|
||||
* ModifyContents, Assembly, CopyContents, ScreenReaders,
|
||||
* ModifyAnnotations, FillIn, AllFeatures.
|
||||
* @return Pdf the pdf instance for method chaining
|
||||
*/
|
||||
public function allow($permissions = null)
|
||||
{
|
||||
$this->getCommand()
|
||||
->addOption('allow', $permissions, false);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flatten the PDF form fields values into a single PDF file.
|
||||
*
|
||||
* @return Pdf the pdf instance for method chaining
|
||||
*/
|
||||
public function flatten()
|
||||
{
|
||||
$this->getCommand()
|
||||
->addOption('flatten');
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore/remove compression
|
||||
*
|
||||
* @param bool $compress whether to restore (default) or remove the
|
||||
* compression
|
||||
* @return Pdf the pdf instance for method chaining
|
||||
*/
|
||||
public function compress($compress = true)
|
||||
{
|
||||
$this->getCommand()
|
||||
->addOption($compress ? 'compress' : 'uncompress');
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* When combining multiple PDFs, use either the first or last ID in the
|
||||
* output. If not called, a new ID is created.
|
||||
*
|
||||
* @param string $id, either 'first' (default) or 'last'
|
||||
* @return Pdf the pdf instance for method chaining
|
||||
*/
|
||||
public function keepId($id = 'first')
|
||||
{
|
||||
$this->getCommand()
|
||||
->addOption($id === 'first' ? 'keep_first_id' : 'keep_final_id');
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set need_appearances flag in PDF
|
||||
*
|
||||
* This flag makes sure, that a PDF reader takes care of rendering form
|
||||
* field content, even if it contains non ASCII characters. You should
|
||||
* always use this option if you fill in forms e.g. with Unicode
|
||||
* characters. You can't combine this option with flatten() though!
|
||||
*
|
||||
* @return Pdf the pdf instance for method chaining
|
||||
*/
|
||||
public function needAppearances()
|
||||
{
|
||||
$this->getCommand()
|
||||
->addOption('need_appearances');
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop XFA data from forms created with newer Acrobat.
|
||||
*
|
||||
* Newer PDF forms contain both, the newer XFA and the older AcroForm form
|
||||
* fields. PDF readers can use both, but will prefer XFA if present. Since
|
||||
* pdftk can only fill in AcroForm data you should always add this option
|
||||
* when filling in forms with pdftk.
|
||||
*
|
||||
* @return Pdf the pdf instance for method chaining
|
||||
*/
|
||||
public function dropXfa()
|
||||
{
|
||||
$this->getCommand()
|
||||
->addOption('drop_xfa');
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop XMP meta data
|
||||
*
|
||||
* Newer PDFs can contain both, new style XMP data and old style info
|
||||
* directory. PDF readers can use both, but will prefer XMP if present.
|
||||
* Since pdftk can only update the info directory you should always add
|
||||
* this option when updating PDF info.
|
||||
*
|
||||
* @return Pdf the pdf instance for method chaining
|
||||
*/
|
||||
public function dropXmp()
|
||||
{
|
||||
$this->getCommand()
|
||||
->addOption('drop_xmp');
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $password the owner password to set on the output PDF
|
||||
* @return Pdf the pdf instance for method chaining
|
||||
*/
|
||||
public function setPassword($password)
|
||||
{
|
||||
$this->getCommand()
|
||||
->addOption('owner_pw', $password, true);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $password the user password to set on the output PDF
|
||||
* @return Pdf the pdf instance for method chaining
|
||||
*/
|
||||
public function setUserPassword($password)
|
||||
{
|
||||
$this->getCommand()
|
||||
->addOption('user_pw', $password, true);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $strength the password encryption strength. Default is 128
|
||||
* @return Pdf the pdf instance for method chaining
|
||||
*/
|
||||
public function passwordEncryption($strength = 128)
|
||||
{
|
||||
$this->getCommand()
|
||||
->addOption($strength == 128 ? 'encrypt_128bit' : 'encrypt_40bit');
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace embedded font with a local font when filling a form.
|
||||
*
|
||||
* This option is only available for pdftk-java >= 3.3.0. It is useful when
|
||||
* filling a form with non-ASCII text that is not supported by the fonts
|
||||
* included in the input PDF.
|
||||
*
|
||||
* @param string $fontName the path to the font or the name of a font family.
|
||||
* @return Pdf the pdf instance for method chaining
|
||||
*/
|
||||
public function replacementFont($path)
|
||||
{
|
||||
$this->getCommand()
|
||||
->addOption('replacement_font', $path);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the operation and save the output file
|
||||
*
|
||||
* @param string $name of output file
|
||||
* @return bool whether the PDF could be processed and saved
|
||||
*/
|
||||
public function saveAs($name)
|
||||
{
|
||||
if (!$this->getCommand()->getExecuted() && !$this->execute()) {
|
||||
return false;
|
||||
}
|
||||
$tmpFile = (string) $this->getTmpFile();
|
||||
if (!copy($tmpFile, $name)) {
|
||||
$this->_error = "Could not copy PDF from tmp location '$tmpFile' to '$name'";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send PDF to client, either inline or as download (triggers PDF creation)
|
||||
*
|
||||
* @param string|null $filename the filename to send. If empty, the PDF is
|
||||
* streamed inline.
|
||||
* @param bool $inline whether to force inline display of the PDF, even if
|
||||
* filename is present.
|
||||
* @param array $headers a list of additional HTTP headers to send in the
|
||||
* response as an array. The array keys are the header names like
|
||||
* 'Cache-Control' and the array values the header value strings to send.
|
||||
* Each array value can also be another array of strings if the same header
|
||||
* should be sent multiple times. This can also be used to override
|
||||
* automatically created headers like 'Expires' or 'Content-Length'. To suppress
|
||||
* automatically created headers, `false` can also be used as header value.
|
||||
* @return bool whether PDF was created successfully
|
||||
*/
|
||||
public function send($filename = null, $inline = false, $headers = array())
|
||||
{
|
||||
if (!$this->getCommand()->getExecuted() && !$this->execute()) {
|
||||
return false;
|
||||
}
|
||||
$this->getTmpFile()->send($filename, $this->_tmpOutputContentType, $inline, $headers);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the raw PDF contents (triggers PDF creation).
|
||||
*
|
||||
* @return string|bool the PDF content as a string or `false` if the PDF
|
||||
* wasn't created successfully.
|
||||
*/
|
||||
public function toString()
|
||||
{
|
||||
if (!$this->getCommand()->getExecuted() && !$this->execute()) {
|
||||
return false;
|
||||
}
|
||||
return file_get_contents($this->getTmpFile()->getFileName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Command the command instance that executes pdftk
|
||||
*/
|
||||
public function getCommand()
|
||||
{
|
||||
if ($this->_command === null) {
|
||||
$this->_command = new Command;
|
||||
}
|
||||
return $this->_command;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return File the temporary output file instance
|
||||
*/
|
||||
public function getTmpFile()
|
||||
{
|
||||
if ($this->_tmpFile === null) {
|
||||
$this->_tmpFile = new File('', '.pdf', self::TMP_PREFIX, $this->tempDir);
|
||||
}
|
||||
return $this->_tmpFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string the error message or an empty string if none
|
||||
*/
|
||||
public function getError()
|
||||
{
|
||||
return $this->_error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the pdftk command and store the output file to a temporary
|
||||
* location or $this->_output if set. You should probably never call this
|
||||
* method unless you only need a temporary PDF file as result.
|
||||
*
|
||||
* @return bool whether the command was executed successfully
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
$command = $this->getCommand();
|
||||
if ($command->getExecuted()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->_output === false) {
|
||||
$filename = null;
|
||||
} else {
|
||||
$filename = $this->_output ? $this->_output : (string) $this->getTmpFile();
|
||||
}
|
||||
if (!$command->execute($filename)) {
|
||||
$this->_error = $command->getError();
|
||||
if ($filename && !(file_exists($filename) && filesize($filename) !== 0 && $this->ignoreWarnings)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure, that only one file is present
|
||||
*/
|
||||
protected function constrainSingleFile()
|
||||
{
|
||||
if ($this->getCommand()->getFileCount() > 1) {
|
||||
throw new \Exception('This operation can only process single files');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string the next handle in the series A, B, C, ... Z, AA, AB...
|
||||
*/
|
||||
protected function nextHandle()
|
||||
{
|
||||
// N.B. Multi-character handles are only available in pdftk 1.45+
|
||||
|
||||
$i = $this->_handle++;
|
||||
$char = 'A';
|
||||
while ($i-- > 0) {
|
||||
$char++;
|
||||
}
|
||||
|
||||
return $char;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,233 +0,0 @@
|
|||
<?php
|
||||
namespace mikehaertl\pdftk;
|
||||
|
||||
use mikehaertl\tmp\File;
|
||||
|
||||
/**
|
||||
* XfdfFile
|
||||
*
|
||||
* This class represents a temporary XFDF file that can be used to fill a PDF
|
||||
* form with valid unicode characters.
|
||||
*
|
||||
* Form data must be passed to the constructor as an array in this form:
|
||||
*
|
||||
* ```
|
||||
* [
|
||||
* // Field name => field value
|
||||
* 'Firstname' => 'John',
|
||||
*
|
||||
* // Hierarchical/nested fields in dot notation
|
||||
* 'Address.Street' => 'Some Street',
|
||||
* 'Address.City' => 'Any City',
|
||||
*
|
||||
* // Multi value fields
|
||||
* 'Pets' => ['Cat', 'Mouse'],
|
||||
* ]
|
||||
* ```
|
||||
*
|
||||
* This will result in the following XML structure (header/footer omitted):
|
||||
*
|
||||
* ```
|
||||
* <field name="Firstname">
|
||||
* <Value>John</Value>
|
||||
* </field>
|
||||
* <field name="Address">
|
||||
* <field name="Street">
|
||||
* <Value>Some Street</Value>
|
||||
* </field>
|
||||
* <field name="City">
|
||||
* <Value>Any City</Value>
|
||||
* </field>
|
||||
* </field>
|
||||
* <field name="Pets">
|
||||
* <Value>Cat</Value>
|
||||
* <Value>Mouse</Value>
|
||||
* </field>
|
||||
* ```
|
||||
*
|
||||
* @author Tomas Holy <holy@interconnect.cz>
|
||||
* @author Michael Härtl <haertl.mike@gmail.com>
|
||||
* @license http://www.opensource.org/licenses/MIT
|
||||
*/
|
||||
class XfdfFile extends File
|
||||
{
|
||||
// XFDF file header
|
||||
const XFDF_HEADER = <<<FDF
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xfdf xmlns="http://ns.adobe.com/xfdf/" xml:space="preserve">
|
||||
<fields>
|
||||
|
||||
FDF;
|
||||
|
||||
// XFDF file footer
|
||||
const XFDF_FOOTER = <<<FDF
|
||||
</fields>
|
||||
</xfdf>
|
||||
|
||||
FDF;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
*
|
||||
* @param array $data the form data as name => value
|
||||
* @param string|null $suffix the optional suffix for the tmp file
|
||||
* @param string|null $prefix the optional prefix for the tmp file. If null
|
||||
* 'php_tmpfile_' is used.
|
||||
* @param string|null $directory directory where the file should be
|
||||
* created. Autodetected if not provided.
|
||||
* @param string|null $encoding of the data. Default is 'UTF-8'.
|
||||
*/
|
||||
public function __construct($data, $suffix = null, $prefix = null, $directory = null, $encoding = 'UTF-8')
|
||||
{
|
||||
if ($directory === null) {
|
||||
$directory = self::getTempDir();
|
||||
}
|
||||
if ($suffix === null) {
|
||||
$suffix = '.xfdf';
|
||||
}
|
||||
if ($prefix === null) {
|
||||
$prefix = 'php_pdftk_xfdf_';
|
||||
}
|
||||
|
||||
$tempfile = tempnam($directory, $prefix);
|
||||
$this->_fileName = $tempfile . $suffix;
|
||||
rename($tempfile, $this->_fileName);
|
||||
|
||||
$fields = $this->parseData($data, $encoding);
|
||||
$this->writeXml($fields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an array of key/value data into a nested array structure.
|
||||
*
|
||||
* The data may use keys in dot notation (#55). Values can also be arrays in
|
||||
* case of multi value fields (#148). To make both distinguishable in the
|
||||
* result array keys that represent field names are prefixed with `_`. This
|
||||
* also allows for numeric field names (#260).
|
||||
*
|
||||
* For example an array like this:
|
||||
*
|
||||
* ```
|
||||
* [
|
||||
* 'a' => 'value a',
|
||||
* 'b.x' => 'value b.x',
|
||||
* 'b.y' => 'value b.y',
|
||||
*
|
||||
* 'c.0' => 'val c.0',
|
||||
* 'c.1' => 'val c.1',
|
||||
*
|
||||
* 'd' => ['m1', 'm2'],
|
||||
* ]
|
||||
* ```
|
||||
*
|
||||
* Will become:
|
||||
*
|
||||
* ```
|
||||
* [
|
||||
* '_a' => 'value a',
|
||||
* '_b' => [
|
||||
* '_x' => 'value b.x',
|
||||
* '_y' => 'value b.y',
|
||||
* ],
|
||||
* '_c' => [
|
||||
* '_0' => 'value c.0',
|
||||
* '_1' => 'value c.1',
|
||||
* ],
|
||||
* '_d' => [
|
||||
* // notice the missing underscore in the keys
|
||||
* 0 => 'm1',
|
||||
* 1 => 'm2',
|
||||
* ],
|
||||
* ]
|
||||
*
|
||||
*
|
||||
* @param mixed $data the data to parse
|
||||
* @param string the encoding of the data
|
||||
* @return array the result array in UTF-8 encoding with dot keys converted
|
||||
* to nested arrays
|
||||
*/
|
||||
protected function parseData($data, $encoding)
|
||||
{
|
||||
$result = array();
|
||||
foreach ($data as $key => $value) {
|
||||
if ($encoding !== 'UTF-8' && function_exists('mb_convert_encoding')) {
|
||||
$key = mb_convert_encoding($key, 'UTF-8', $encoding);
|
||||
$value = mb_convert_encoding($value, 'UTF-8', $encoding);
|
||||
}
|
||||
if (strpos($key, '.') === false) {
|
||||
$result['_' . $key] = $value;
|
||||
} else {
|
||||
$target = &$result;
|
||||
$keyParts = explode('.', $key);
|
||||
$lastPart = array_pop($keyParts);
|
||||
foreach ($keyParts as $part) {
|
||||
if (!isset($target['_' . $part])) {
|
||||
$target['_' . $part] = array();
|
||||
}
|
||||
$target = &$target['_' . $part];
|
||||
}
|
||||
$target['_' . $lastPart] = $value;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the given fields to an XML file
|
||||
*
|
||||
* @param array $fields the fields in a nested array structure
|
||||
*/
|
||||
protected function writeXml($fields)
|
||||
{
|
||||
// Use fwrite, since file_put_contents() messes around with character encoding
|
||||
$fp = fopen($this->_fileName, 'w');
|
||||
fwrite($fp, self::XFDF_HEADER);
|
||||
$this->writeFields($fp, $fields);
|
||||
fwrite($fp, self::XFDF_FOOTER);
|
||||
fclose($fp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the fields to the given filepointer
|
||||
*
|
||||
* @param int $fp
|
||||
* @param mixed[] $fields an array of field values as returned by
|
||||
* `parseData()`.
|
||||
*/
|
||||
protected function writeFields($fp, $fields)
|
||||
{
|
||||
foreach ($fields as $key => $value) {
|
||||
$key = $this->xmlEncode(substr($key,1));
|
||||
fwrite($fp, "<field name=\"$key\">\n");
|
||||
if (!is_array($value)) {
|
||||
$value = array($value);
|
||||
}
|
||||
if (array_key_exists(0, $value)) {
|
||||
// Numeric keys: single or multi-value field
|
||||
foreach($value as $val) {
|
||||
$val = $this->xmlEncode($val);
|
||||
fwrite($fp, "<value>$val</value>\n");
|
||||
}
|
||||
} else {
|
||||
// String keys: nested/hierarchical fields
|
||||
$this->writeFields($fp, $value);
|
||||
}
|
||||
fwrite($fp, "</field>\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $value the value to encode
|
||||
* @return string|null the value correctly encoded for use in a XML document
|
||||
*/
|
||||
protected function xmlEncode($value)
|
||||
{
|
||||
if ($value === null) {
|
||||
return null;
|
||||
}
|
||||
return defined('ENT_XML1') ?
|
||||
htmlspecialchars($value, ENT_XML1, 'UTF-8') :
|
||||
htmlspecialchars($value);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
name: Tests
|
||||
on: pull_request
|
||||
jobs:
|
||||
phpunit:
|
||||
name: PHP ${{ matrix.php }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
php:
|
||||
- "5.3"
|
||||
- "5.4"
|
||||
- "5.5"
|
||||
- "5.6"
|
||||
- "7.0"
|
||||
- "7.1"
|
||||
- "7.2"
|
||||
- "7.3"
|
||||
- "7.4"
|
||||
- "8.0"
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Install PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
tools: composer:v2
|
||||
|
||||
- name: Update composer
|
||||
run: composer self-update
|
||||
|
||||
- name: Get composer cache directory
|
||||
id: composer-cache
|
||||
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
|
||||
|
||||
- name: Cache dependencies
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}
|
||||
restore-keys: ${{ runner.os }}-composer-
|
||||
|
||||
- name: Install composer packages
|
||||
run: composer update --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi
|
||||
|
||||
- name: Run phpunit
|
||||
run: vendor/bin/phpunit --color=always
|
||||
|
|
@ -1,102 +0,0 @@
|
|||
# CHANGELOG
|
||||
|
||||
## 1.6.4
|
||||
|
||||
* Let getExecCommand() not cache the created command string
|
||||
|
||||
## 1.6.3
|
||||
|
||||
* Include PHP 5.3 in version requirements
|
||||
|
||||
## 1.6.2
|
||||
|
||||
* Add .gitattributes to reduce package size
|
||||
|
||||
## 1.6.1
|
||||
|
||||
* Issue #44 Fix potential security issue with escaping shell args (@Kirill89 / https://snyk.io/)
|
||||
|
||||
## 1.6.0
|
||||
|
||||
* Issue #24 Implement timeout feature
|
||||
|
||||
## 1.5.0
|
||||
|
||||
* Issue #20 Refactor handling of stdin/stdou/sterr streams with proc_open().
|
||||
By default these streams now operate in non-blocking mode which should fix
|
||||
many hanging issues that were caused when the command received/sent a lot of
|
||||
input/output. This is the new default on Non-Windows systems (it's not
|
||||
supported on Windows, though). To get the old behavior the nonBlockingMode
|
||||
option can be set to false.
|
||||
|
||||
## 1.4.1
|
||||
|
||||
* Allow command names with spaces on Windows (@Robindfuller )
|
||||
|
||||
## 1.4.0
|
||||
|
||||
* Allow stdin to be a stream or a file handle (@Arzaroth)
|
||||
|
||||
## 1.3.0
|
||||
|
||||
* Add setStdIn() which allows to pipe an input string to the command (@martinqvistgard)
|
||||
|
||||
## 1.2.5
|
||||
|
||||
* Issue #22 Fix execution of relative file paths on windows
|
||||
|
||||
## 1.2.4
|
||||
|
||||
* Reverted changes for Issue #20 as this introduced BC breaking problems
|
||||
|
||||
## 1.2.3
|
||||
|
||||
* Issue #20: Read stderr before stdout to avoid hanging processes
|
||||
|
||||
## 1.2.2
|
||||
|
||||
* Issue #16: Command on different drive didn't work on windows
|
||||
|
||||
## 1.2.1
|
||||
|
||||
* Issue #1: Command with spaces didn't work on windows
|
||||
|
||||
## 1.2.0
|
||||
|
||||
* Add option to return untrimmed output and error
|
||||
|
||||
## 1.1.0
|
||||
|
||||
* Issue #7: UTF-8 encoded arguments where truncated
|
||||
|
||||
## 1.0.7
|
||||
|
||||
* Issue #6: Solve `proc_open()` pipe configuration for both, Windows / Linux
|
||||
|
||||
## 1.0.6
|
||||
|
||||
* Undid `proc_open()` changes as it broke error capturing
|
||||
|
||||
## 1.0.5
|
||||
|
||||
* Improve `proc_open()` pipe configuration
|
||||
|
||||
## 1.0.4
|
||||
|
||||
* Add `$useExec` option to fix Windows issues (#3)
|
||||
|
||||
## 1.0.3
|
||||
|
||||
* Add `getExecuted()` to find out execution status of the command
|
||||
|
||||
## 1.0.2
|
||||
|
||||
* Add `$escape` parameter to `addArg()` to override escaping settings per call
|
||||
|
||||
## 1.0.1
|
||||
|
||||
* Minor fixes
|
||||
|
||||
## 1.0.0
|
||||
|
||||
* Initial release
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Michael Härtl
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
|
@ -1,204 +0,0 @@
|
|||
php-shellcommand
|
||||
================
|
||||
|
||||
[](https://github.com/mikehaertl/php-shellcommand/actions)
|
||||
[](https://packagist.org/packages/mikehaertl/php-shellcommand)
|
||||
[](https://packagist.org/packages/mikehaertl/php-shellcommand)
|
||||
[](https://github.com/mikehaertl/php-shellcommand/blob/master/LICENSE)
|
||||
[](https://packagist.org/packages/mikehaertl/php-shellcommand)
|
||||
|
||||
php-shellcommand provides a simple object oriented interface to execute shell commands.
|
||||
|
||||
## Installing
|
||||
|
||||
### Prerequisites
|
||||
|
||||
Your php version must be `5.4` or later.
|
||||
|
||||
### Installing with composer
|
||||
|
||||
This package can be installed easily using composer.
|
||||
|
||||
```
|
||||
composer require mikehaertl/php-shellcommand
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
* Catches `stdOut`, `stdErr` and `exitCode`
|
||||
* Handle argument escaping
|
||||
* Pass environment vars and other options to `proc_open()`
|
||||
* Pipe resources like files or streams into the command
|
||||
* Timeout for execution
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic Example
|
||||
|
||||
```php
|
||||
<?php
|
||||
use mikehaertl\shellcommand\Command;
|
||||
|
||||
// Basic example
|
||||
$command = new Command('/usr/local/bin/mycommand -a -b');
|
||||
if ($command->execute()) {
|
||||
echo $command->getOutput();
|
||||
} else {
|
||||
echo $command->getError();
|
||||
$exitCode = $command->getExitCode();
|
||||
}
|
||||
```
|
||||
|
||||
### Advanced Features
|
||||
|
||||
#### Add Arguments
|
||||
```php
|
||||
<?php
|
||||
$command = new Command('/bin/somecommand');
|
||||
// Add arguments with correct escaping:
|
||||
// results in --name='d'\''Artagnan'
|
||||
$command->addArg('--name=', "d'Artagnan");
|
||||
|
||||
// Add argument with several values
|
||||
// results in --keys key1 key2
|
||||
$command->addArg('--keys', ['key1','key2']);
|
||||
```
|
||||
|
||||
### Pipe Input Into Command
|
||||
|
||||
From string:
|
||||
```php
|
||||
<?php
|
||||
$command = new ('jq'); // jq is a pretty printer
|
||||
$command->setStdIn('{"foo": 0}');
|
||||
if (!$command->execute()) {
|
||||
echo $command->getError();
|
||||
} else {
|
||||
echo $command->getOutput();
|
||||
}
|
||||
// Output:
|
||||
// {
|
||||
// "foo": 0
|
||||
// }
|
||||
```
|
||||
|
||||
From file:
|
||||
```php
|
||||
<?php
|
||||
$fh = fopen('test.json', 'r');
|
||||
// error checks left out...
|
||||
$command = new Command('jq');
|
||||
$command->setStdIn($fh);
|
||||
if (!$command->execute()) {
|
||||
echo $command->getError();
|
||||
} else {
|
||||
echo $command->getOutput();
|
||||
}
|
||||
fclose($fh);
|
||||
```
|
||||
From URL:
|
||||
```php
|
||||
<?php
|
||||
$fh = fopen('https://api.open-meteo.com/v1/forecast?latitude=52.52&longitude=13.41&hourly=temperature_2m,relativehumidity_2m,windspeed_10m', 'r');
|
||||
// error checks left out...
|
||||
$command = new Command('jq');
|
||||
$command->setStdIn($fh);
|
||||
if (!$command->execute()) {
|
||||
echo $command->getError();
|
||||
} else {
|
||||
echo $command->getOutput();
|
||||
}
|
||||
fclose($fh);
|
||||
```
|
||||
|
||||
#### Set Command Instance Options
|
||||
```php
|
||||
<?php
|
||||
// Create command with options array
|
||||
$command = new Command([
|
||||
'command' => '/usr/local/bin/mycommand',
|
||||
|
||||
// Will be passed as environment variables to the command
|
||||
'procEnv' => [
|
||||
'DEMOVAR' => 'demovalue'
|
||||
],
|
||||
|
||||
// Will be passed as options to proc_open()
|
||||
'procOptions' => [
|
||||
'bypass_shell' => true,
|
||||
],
|
||||
]);
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### Properties
|
||||
|
||||
* `$escapeArgs`: Whether to escape any argument passed through `addArg()`. Default is `true`.
|
||||
* `$escapeCommand`: Whether to escape the command passed to `setCommand()` or the constructor.
|
||||
This is only useful if `$escapeArgs` is `false`. Default is `false`.
|
||||
* `$useExec`: Whether to use `exec()` instead of `proc_open()`. This is a workaround for OS which
|
||||
have problems with `proc_open()`. Default is `false`.
|
||||
* `$captureStdErr`: Whether to capture stderr when `useExec` is set. This will try to redirect
|
||||
the otherwhise unavailable `stderr` to `stdout`, so that both have the same content on error.
|
||||
Default is `true`.
|
||||
* `$procCwd`: The initial working dir passed to `proc_open()`. Default is `null` for current
|
||||
PHP working dir.
|
||||
* `$procEnv`: An array with environment variables to pass to `proc_open()`. Default is `null` for none.
|
||||
* `$procOptions`: An array of `other_options` for `proc_open()`. Default is `null` for none.
|
||||
* `$nonBlockingMode`: Whether to set the stdin/stdout/stderr streams to non-blocking
|
||||
mode when `proc_open()` is used. This allows to have huge inputs/outputs
|
||||
without making the process hang. The default is `null` which will enable
|
||||
the feature on Non-Windows systems. Set it to `true` or `false` to manually
|
||||
enable/disable it. Note that it doesn't work on Windows.
|
||||
* `$timeout`: The time in seconds after which the command should be
|
||||
terminated. This only works in non-blocking mode. Default is `null` which
|
||||
means the process is never terminated.
|
||||
* `$locale`: The locale to (temporarily) set with `setlocale()` before running the command.
|
||||
This can be set to e.g. `en_US.UTF-8` if you have issues with UTF-8 encoded arguments.
|
||||
|
||||
You can configure all these properties via an array that you pass in the constructor. You can also
|
||||
pass `command`, `execCommand` and `args` as options. This will call the respective setter (`setCommand()`,
|
||||
`setExecCommand()`, etc.).
|
||||
|
||||
### Methods
|
||||
|
||||
* `__construct($options = null)`
|
||||
* `$options`: either a command string or an options array (see `setOptions()`)
|
||||
* `__toString()`: The result from `getExecCommand()`
|
||||
* `setOptions($options)`: Set command options
|
||||
* `$options`: array of name => value options that should be applied to the object.
|
||||
You can also pass options that use a setter, e.g. you can pass a `command` option which
|
||||
will be passed to `setCommand().`
|
||||
* `setCommand($command)`: Set command
|
||||
* `$command`: The command or full command string to execute, like `gzip` or `gzip -d`.
|
||||
You can still call `addArg()` to add more arguments to the command. If `$escapeCommand` was
|
||||
set to `true`, the command gets escaped through `escapeshellcmd()`.
|
||||
* `getCommand()`: The command that was set through `setCommand()` or passed to the constructor.
|
||||
* `getExecCommand()`: The full command string to execute.
|
||||
* `setArgs($args)`: Set argument as string
|
||||
* `$args`: The command arguments as string. Note, that these will not get escaped. This
|
||||
will overwrite the args added with `addArgs()`.
|
||||
* `getArgs()`: The command arguments that where set through `setArgs()` or `addArg()`, as string
|
||||
* `addArg($key, $value=null, $escape=null)`: Add argument with correct escaping
|
||||
* `$key`: The argument key to add e.g. `--feature` or `--name=`. If the key does not end with
|
||||
and `=`, the (optional) `$value` will be separated by a space. The key will get
|
||||
escaped if `$escapeArgs` is `true`.
|
||||
* `$value`: The optional argument value which will get escaped if `$escapeArgs` is `true`.
|
||||
An array can be passed to add more than one value for a key, e.g. `addArg('--exclude', ['val1','val2'])`
|
||||
which will create the option "--exclude 'val1' 'val2'".
|
||||
* `$escape`: If set, this overrides the `$escapeArgs` setting and enforces escaping/no escaping
|
||||
* `setStdIn()`: String or resource to supply to command via standard input.
|
||||
This enables the same functionality as piping on the command line. It can
|
||||
also be a resource like a file handle or a stream in which case its content
|
||||
will be piped into the command like an input redirection.
|
||||
* `getOutput()`: The command output as string. Empty if none.
|
||||
* `getError()`: The error message, either stderr or internal message. Empty if no error.
|
||||
* `getStdErr()`: The stderr output. Empty if none.
|
||||
* `getExitCode()`: The exit code or `null` if command was not executed.
|
||||
* `getExecuted()`: Whether the command was successfully executed.
|
||||
* `getIsWindows()`: Whether we are on a Windows Owe are on a Windows OS
|
||||
* `execute()`: Executes the command and returns `true` on success, `false` otherwhise.
|
||||
|
||||
> **Note:** `getError()`, `getStdErr()` and `getOutput()` return the trimmed output.
|
||||
> You can pass `false` to these methods if you need any possible line breaks at the end.
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
{
|
||||
"name": "mikehaertl/php-shellcommand",
|
||||
"description": "An object oriented interface to shell commands",
|
||||
"keywords": ["shell"],
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Michael Härtl",
|
||||
"email": "haertl.mike@gmail.com"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">= 5.3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": ">4.0 <=9.4"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"mikehaertl\\shellcommand\\": "src/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"tests\\": "tests"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,568 +0,0 @@
|
|||
<?php
|
||||
namespace mikehaertl\shellcommand;
|
||||
|
||||
/**
|
||||
* Command
|
||||
*
|
||||
* This class represents a shell command.
|
||||
*
|
||||
* Its meant for exuting a single command and capturing stdout and stderr.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```
|
||||
* $command = new Command('/usr/local/bin/mycommand -a -b');
|
||||
* $command->addArg('--name=', "d'Artagnan");
|
||||
* if ($command->execute()) {
|
||||
* echo $command->getOutput();
|
||||
* } else {
|
||||
* echo $command->getError();
|
||||
* $exitCode = $command->getExitCode();
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @author Michael Härtl <haertl.mike@gmail.com>
|
||||
* @license http://www.opensource.org/licenses/MIT
|
||||
*/
|
||||
class Command
|
||||
{
|
||||
/**
|
||||
* @var bool whether to escape any argument passed through `addArg()`.
|
||||
* Default is `true`.
|
||||
*/
|
||||
public $escapeArgs = true;
|
||||
|
||||
/**
|
||||
* @var bool whether to escape the command passed to `setCommand()` or the
|
||||
* constructor. This is only useful if `$escapeArgs` is `false`. Default
|
||||
* is `false`.
|
||||
*/
|
||||
public $escapeCommand = false;
|
||||
|
||||
/**
|
||||
* @var bool whether to use `exec()` instead of `proc_open()`. This can be
|
||||
* used on Windows system to workaround some quirks there. Note, that any
|
||||
* errors from your command will be output directly to the PHP output
|
||||
* stream. `getStdErr()` will also not work anymore and thus you also won't
|
||||
* get the error output from `getError()` in this case. You also can't pass
|
||||
* any environment variables to the command if this is enabled. Default is
|
||||
* `false`.
|
||||
*/
|
||||
public $useExec = false;
|
||||
|
||||
/**
|
||||
* @var bool whether to capture stderr (2>&1) when `useExec` is true. This
|
||||
* will try to redirect the stderr to stdout and provide the complete
|
||||
* output of both in `getStdErr()` and `getError()`. Default is `true`.
|
||||
*/
|
||||
public $captureStdErr = true;
|
||||
|
||||
/**
|
||||
* @var string|null the initial working dir for `proc_open()`. Default is
|
||||
* `null` for current PHP working dir.
|
||||
*/
|
||||
public $procCwd;
|
||||
|
||||
/**
|
||||
* @var array|null an array with environment variables to pass to
|
||||
* `proc_open()`. Default is `null` for none.
|
||||
*/
|
||||
public $procEnv;
|
||||
|
||||
/**
|
||||
* @var array|null an array of other_options for `proc_open()`. Default is
|
||||
* `null` for none.
|
||||
*/
|
||||
public $procOptions;
|
||||
|
||||
/**
|
||||
* @var bool|null whether to set the stdin/stdout/stderr streams to
|
||||
* non-blocking mode when `proc_open()` is used. This allows to have huge
|
||||
* inputs/outputs without making the process hang. The default is `null`
|
||||
* which will enable the feature on Non-Windows systems. Set it to `true`
|
||||
* or `false` to manually enable/disable it. It does not work on Windows.
|
||||
*/
|
||||
public $nonBlockingMode;
|
||||
|
||||
/**
|
||||
* @var int the time in seconds after which a command should be terminated.
|
||||
* This only works in non-blocking mode. Default is `null` which means the
|
||||
* process is never terminated.
|
||||
*/
|
||||
public $timeout;
|
||||
|
||||
/**
|
||||
* @var null|string the locale to temporarily set before calling
|
||||
* `escapeshellargs()`. Default is `null` for none.
|
||||
*/
|
||||
public $locale;
|
||||
|
||||
/**
|
||||
* @var null|string|resource to pipe to standard input
|
||||
*/
|
||||
protected $_stdIn;
|
||||
|
||||
/**
|
||||
* @var string the command to execute
|
||||
*/
|
||||
protected $_command;
|
||||
|
||||
/**
|
||||
* @var array the list of command arguments
|
||||
*/
|
||||
protected $_args = array();
|
||||
|
||||
/**
|
||||
* @var string the stdout output
|
||||
*/
|
||||
protected $_stdOut = '';
|
||||
|
||||
/**
|
||||
* @var string the stderr output
|
||||
*/
|
||||
protected $_stdErr = '';
|
||||
|
||||
/**
|
||||
* @var int the exit code
|
||||
*/
|
||||
protected $_exitCode;
|
||||
|
||||
/**
|
||||
* @var string the error message
|
||||
*/
|
||||
protected $_error = '';
|
||||
|
||||
/**
|
||||
* @var bool whether the command was successfully executed
|
||||
*/
|
||||
protected $_executed = false;
|
||||
|
||||
/**
|
||||
* @param string|array $options either a command string or an options array
|
||||
* @see setOptions
|
||||
*/
|
||||
public function __construct($options = null)
|
||||
{
|
||||
if (is_array($options)) {
|
||||
$this->setOptions($options);
|
||||
} elseif (is_string($options)) {
|
||||
$this->setCommand($options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $options array of name => value options (i.e. public
|
||||
* properties) that should be applied to this object. You can also pass
|
||||
* options that use a setter, e.g. you can pass a `fileName` option which
|
||||
* will be passed to `setFileName()`.
|
||||
* @throws \Exception on unknown option keys
|
||||
* @return static for method chaining
|
||||
*/
|
||||
public function setOptions($options)
|
||||
{
|
||||
foreach ($options as $key => $value) {
|
||||
if (property_exists($this, $key)) {
|
||||
$this->$key = $value;
|
||||
} else {
|
||||
$method = 'set'.ucfirst($key);
|
||||
if (method_exists($this, $method)) {
|
||||
call_user_func(array($this,$method), $value);
|
||||
} else {
|
||||
throw new \Exception("Unknown configuration option '$key'");
|
||||
}
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $command the command or full command string to execute,
|
||||
* like 'gzip' or 'gzip -d'. You can still call addArg() to add more
|
||||
* arguments to the command. If `$escapeCommand` was set to true, the command
|
||||
* gets escaped with `escapeshellcmd()`.
|
||||
* @return static for method chaining
|
||||
*/
|
||||
public function setCommand($command)
|
||||
{
|
||||
if ($this->escapeCommand) {
|
||||
$command = escapeshellcmd($command);
|
||||
}
|
||||
if ($this->getIsWindows()) {
|
||||
// Make sure to switch to correct drive like "E:" first if we have
|
||||
// a full path in command
|
||||
if (isset($command[1]) && $command[1] === ':') {
|
||||
$position = 1;
|
||||
// Could be a quoted absolute path because of spaces.
|
||||
// i.e. "C:\Program Files (x86)\file.exe"
|
||||
} elseif (isset($command[2]) && $command[2] === ':') {
|
||||
$position = 2;
|
||||
} else {
|
||||
$position = false;
|
||||
}
|
||||
|
||||
// Absolute path. If it's a relative path, let it slide.
|
||||
if ($position) {
|
||||
$command = sprintf(
|
||||
$command[$position - 1] . ': && cd %s && %s',
|
||||
escapeshellarg(dirname($command)),
|
||||
escapeshellarg(basename($command))
|
||||
);
|
||||
}
|
||||
}
|
||||
$this->_command = $command;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|resource $stdIn If set, the string will be piped to the
|
||||
* command via standard input. This enables the same functionality as
|
||||
* piping on the command line. It can also be a resource like a file
|
||||
* handle or a stream in which case its content will be piped into the
|
||||
* command like an input redirection.
|
||||
* @return static for method chaining
|
||||
*/
|
||||
public function setStdIn($stdIn) {
|
||||
$this->_stdIn = $stdIn;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null the command that was set through `setCommand()` or
|
||||
* passed to the constructor. `null` if none.
|
||||
*/
|
||||
public function getCommand()
|
||||
{
|
||||
return $this->_command;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|bool the full command string to execute. If no command
|
||||
* was set with `setCommand()` or passed to the constructor it will return
|
||||
* `false`.
|
||||
*/
|
||||
public function getExecCommand()
|
||||
{
|
||||
$command = $this->getCommand();
|
||||
if (!$command) {
|
||||
$this->_error = 'Could not locate any executable command';
|
||||
return false;
|
||||
}
|
||||
|
||||
$args = $this->getArgs();
|
||||
return $args ? $command.' '.$args : $command;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $args the command arguments as string like `'--arg1=value1
|
||||
* --arg2=value2'`. Note that this string will not get escaped. This will
|
||||
* overwrite the args added with `addArgs()`.
|
||||
* @return static for method chaining
|
||||
*/
|
||||
public function setArgs($args)
|
||||
{
|
||||
$this->_args = array($args);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string the command args that where set with `setArgs()` or added
|
||||
* with `addArg()` separated by spaces.
|
||||
*/
|
||||
public function getArgs()
|
||||
{
|
||||
return implode(' ', $this->_args);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key the argument key to add e.g. `--feature` or
|
||||
* `--name=`. If the key does not end with `=`, the (optional) $value will
|
||||
* be separated by a space. The key will get escaped if `$escapeArgs` is `true`.
|
||||
* @param string|array|null $value the optional argument value which will
|
||||
* get escaped if $escapeArgs is true. An array can be passed to add more
|
||||
* than one value for a key, e.g.
|
||||
* `addArg('--exclude', array('val1','val2'))`
|
||||
* which will create the option
|
||||
* `'--exclude' 'val1' 'val2'`.
|
||||
* @param bool|null $escape if set, this overrides the `$escapeArgs` setting
|
||||
* and enforces escaping/no escaping of keys and values
|
||||
* @return static for method chaining
|
||||
*/
|
||||
public function addArg($key, $value = null, $escape = null)
|
||||
{
|
||||
$doEscape = $escape !== null ? $escape : $this->escapeArgs;
|
||||
$useLocale = $doEscape && $this->locale !== null;
|
||||
|
||||
if ($useLocale) {
|
||||
$locale = setlocale(LC_CTYPE, 0); // Returns current locale setting
|
||||
setlocale(LC_CTYPE, $this->locale);
|
||||
}
|
||||
if ($value === null) {
|
||||
$this->_args[] = $doEscape ? escapeshellarg($key) : $key;
|
||||
} else {
|
||||
if (substr($key, -1) === '=') {
|
||||
$separator = '=';
|
||||
$argKey = substr($key, 0, -1);
|
||||
} else {
|
||||
$separator = ' ';
|
||||
$argKey = $key;
|
||||
}
|
||||
$argKey = $doEscape ? escapeshellarg($argKey) : $argKey;
|
||||
|
||||
if (is_array($value)) {
|
||||
$params = array();
|
||||
foreach ($value as $v) {
|
||||
$params[] = $doEscape ? escapeshellarg($v) : $v;
|
||||
}
|
||||
$this->_args[] = $argKey . $separator . implode(' ', $params);
|
||||
} else {
|
||||
$this->_args[] = $argKey . $separator .
|
||||
($doEscape ? escapeshellarg($value) : $value);
|
||||
}
|
||||
}
|
||||
if ($useLocale) {
|
||||
setlocale(LC_CTYPE, $locale);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $trim whether to `trim()` the return value. The default is `true`.
|
||||
* @param string $characters the list of characters to trim. The default
|
||||
* is ` \t\n\r\0\v\f`.
|
||||
* @return string the command output (stdout). Empty if none.
|
||||
*/
|
||||
public function getOutput($trim = true, $characters = " \t\n\r\0\v\f")
|
||||
{
|
||||
return $trim ? trim($this->_stdOut, $characters) : $this->_stdOut;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $trim whether to `trim()` the return value. The default is `true`.
|
||||
* @param string $characters the list of characters to trim. The default
|
||||
* is ` \t\n\r\0\v\f`.
|
||||
* @return string the error message, either stderr or an internal message.
|
||||
* Empty string if none.
|
||||
*/
|
||||
public function getError($trim = true, $characters = " \t\n\r\0\v\f")
|
||||
{
|
||||
return $trim ? trim($this->_error, $characters) : $this->_error;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $trim whether to `trim()` the return value. The default is `true`.
|
||||
* @param string $characters the list of characters to trim. The default
|
||||
* is ` \t\n\r\0\v\f`.
|
||||
* @return string the stderr output. Empty if none.
|
||||
*/
|
||||
public function getStdErr($trim = true, $characters = " \t\n\r\0\v\f")
|
||||
{
|
||||
return $trim ? trim($this->_stdErr, $characters) : $this->_stdErr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|null the exit code or null if command was not executed yet
|
||||
*/
|
||||
public function getExitCode()
|
||||
{
|
||||
return $this->_exitCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string whether the command was successfully executed
|
||||
*/
|
||||
public function getExecuted()
|
||||
{
|
||||
return $this->_executed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the command
|
||||
*
|
||||
* @return bool whether execution was successful. If `false`, error details
|
||||
* can be obtained from `getError()`, `getStdErr()` and `getExitCode()`.
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
$command = $this->getExecCommand();
|
||||
|
||||
if (!$command) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->useExec) {
|
||||
$execCommand = $this->captureStdErr ? "$command 2>&1" : $command;
|
||||
exec($execCommand, $output, $this->_exitCode);
|
||||
$this->_stdOut = implode("\n", $output);
|
||||
if ($this->_exitCode !== 0) {
|
||||
$this->_stdErr = $this->_stdOut;
|
||||
$this->_error = empty($this->_stdErr) ? 'Command failed' : $this->_stdErr;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
$isInputStream = $this->_stdIn !== null &&
|
||||
is_resource($this->_stdIn) &&
|
||||
in_array(get_resource_type($this->_stdIn), array('file', 'stream'));
|
||||
$isInputString = is_string($this->_stdIn);
|
||||
$hasInput = $isInputStream || $isInputString;
|
||||
$hasTimeout = $this->timeout !== null && $this->timeout > 0;
|
||||
|
||||
$descriptors = array(
|
||||
1 => array('pipe','w'),
|
||||
2 => array('pipe', $this->getIsWindows() ? 'a' : 'w'),
|
||||
);
|
||||
if ($hasInput) {
|
||||
$descriptors[0] = array('pipe', 'r');
|
||||
}
|
||||
|
||||
|
||||
// Issue #20 Set non-blocking mode to fix hanging processes
|
||||
$nonBlocking = $this->nonBlockingMode === null ?
|
||||
!$this->getIsWindows() : $this->nonBlockingMode;
|
||||
|
||||
$startTime = $hasTimeout ? time() : 0;
|
||||
$process = proc_open($command, $descriptors, $pipes, $this->procCwd, $this->procEnv, $this->procOptions);
|
||||
|
||||
if (is_resource($process)) {
|
||||
|
||||
if ($nonBlocking) {
|
||||
stream_set_blocking($pipes[1], false);
|
||||
stream_set_blocking($pipes[2], false);
|
||||
if ($hasInput) {
|
||||
$writtenBytes = 0;
|
||||
$isInputOpen = true;
|
||||
stream_set_blocking($pipes[0], false);
|
||||
if ($isInputStream) {
|
||||
stream_set_blocking($this->_stdIn, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Due to the non-blocking streams we now have to check in
|
||||
// a loop if the process is still running. We also need to
|
||||
// ensure that all the pipes are written/read alternately
|
||||
// until there's nothing left to write/read.
|
||||
$isRunning = true;
|
||||
while ($isRunning) {
|
||||
$status = proc_get_status($process);
|
||||
$isRunning = $status['running'];
|
||||
|
||||
// We first write to stdIn if we have an input. For big
|
||||
// inputs it will only write until the input buffer of
|
||||
// the command is full (the command may now wait that
|
||||
// we read the output buffers - see below). So we may
|
||||
// have to continue writing in another cycle.
|
||||
//
|
||||
// After everything is written it's safe to close the
|
||||
// input pipe.
|
||||
if ($isRunning && $hasInput && $isInputOpen) {
|
||||
if ($isInputStream) {
|
||||
$written = stream_copy_to_stream($this->_stdIn, $pipes[0], 16 * 1024, $writtenBytes);
|
||||
if ($written === false || $written === 0) {
|
||||
$isInputOpen = false;
|
||||
fclose($pipes[0]);
|
||||
} else {
|
||||
$writtenBytes += $written;
|
||||
}
|
||||
} else {
|
||||
if ($writtenBytes < strlen($this->_stdIn)) {
|
||||
$writtenBytes += fwrite($pipes[0], substr($this->_stdIn, $writtenBytes));
|
||||
} else {
|
||||
$isInputOpen = false;
|
||||
fclose($pipes[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Read out the output buffers because if they are full
|
||||
// the command may block execution. We do this even if
|
||||
// $isRunning is `false`, because there could be output
|
||||
// left in the buffers.
|
||||
//
|
||||
// The latter is only an assumption and needs to be
|
||||
// verified - but it does not hurt either and works as
|
||||
// expected.
|
||||
//
|
||||
while (($out = fgets($pipes[1])) !== false) {
|
||||
$this->_stdOut .= $out;
|
||||
}
|
||||
while (($err = fgets($pipes[2])) !== false) {
|
||||
$this->_stdErr .= $err;
|
||||
}
|
||||
|
||||
$runTime = $hasTimeout ? time() - $startTime : 0;
|
||||
if ($isRunning && $hasTimeout && $runTime >= $this->timeout) {
|
||||
// Only send a SIGTERM and handle status in the next cycle
|
||||
proc_terminate($process);
|
||||
}
|
||||
|
||||
if (!$isRunning) {
|
||||
$this->_exitCode = $status['exitcode'];
|
||||
if ($this->_exitCode !== 0 && empty($this->_stdErr)) {
|
||||
if ($status['stopped']) {
|
||||
$signal = $status['stopsig'];
|
||||
$this->_stdErr = "Command stopped by signal $signal";
|
||||
} elseif ($status['signaled']) {
|
||||
$signal = $status['termsig'];
|
||||
$this->_stdErr = "Command terminated by signal $signal";
|
||||
} else {
|
||||
$this->_stdErr = 'Command unexpectedly terminated without error message';
|
||||
}
|
||||
}
|
||||
fclose($pipes[1]);
|
||||
fclose($pipes[2]);
|
||||
proc_close($process);
|
||||
} else {
|
||||
// The command is still running. Let's wait some
|
||||
// time before we start the next cycle.
|
||||
usleep(10000);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ($hasInput) {
|
||||
if ($isInputStream) {
|
||||
stream_copy_to_stream($this->_stdIn, $pipes[0]);
|
||||
} elseif ($isInputString) {
|
||||
fwrite($pipes[0], $this->_stdIn);
|
||||
}
|
||||
fclose($pipes[0]);
|
||||
}
|
||||
$this->_stdOut = stream_get_contents($pipes[1]);
|
||||
$this->_stdErr = stream_get_contents($pipes[2]);
|
||||
fclose($pipes[1]);
|
||||
fclose($pipes[2]);
|
||||
$this->_exitCode = proc_close($process);
|
||||
}
|
||||
|
||||
if ($this->_exitCode !== 0) {
|
||||
$this->_error = $this->_stdErr ?
|
||||
$this->_stdErr :
|
||||
"Failed without error message: $command (Exit code: {$this->_exitCode})";
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
$this->_error = "Could not run command $command";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$this->_executed = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool whether we are on a Windows OS
|
||||
*/
|
||||
public function getIsWindows()
|
||||
{
|
||||
return strncasecmp(PHP_OS, 'WIN', 3)===0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string the current command string to execute
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return (string) $this->getExecCommand();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
name: Tests
|
||||
on: pull_request
|
||||
jobs:
|
||||
phpunit:
|
||||
name: PHP ${{ matrix.php }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
php:
|
||||
- "5.3"
|
||||
- "5.4"
|
||||
- "5.5"
|
||||
- "5.6"
|
||||
- "7.0"
|
||||
- "7.1"
|
||||
- "7.2"
|
||||
- "7.3"
|
||||
- "7.4"
|
||||
- "8.0"
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Install PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
tools: composer:v2
|
||||
|
||||
- name: Update composer
|
||||
run: composer self-update
|
||||
|
||||
- name: Get composer cache directory
|
||||
id: composer-cache
|
||||
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
|
||||
|
||||
- name: Cache dependencies
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}
|
||||
restore-keys: ${{ runner.os }}-composer-
|
||||
|
||||
- name: Install composer packages
|
||||
run: composer update --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi
|
||||
|
||||
- name: Run phpunit
|
||||
run: vendor/bin/phpunit --color=always
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Michael Härtl
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
php-tmpfile
|
||||
===========
|
||||
|
||||
[](https://github.com/mikehaertl/php-tmpfile/actions)
|
||||
[](https://packagist.org/packages/mikehaertl/php-tmpfile)
|
||||
[](https://packagist.org/packages/mikehaertl/php-tmpfile)
|
||||
[](https://github.com/mikehaertl/php-tmpfile/blob/master/LICENSE)
|
||||
|
||||
A convenience class for temporary files.
|
||||
|
||||
## Features
|
||||
|
||||
* Create temporary file with arbitrary content
|
||||
* Delete file after use (can be disabled)
|
||||
* Send file to client, either inline or with save dialog, optionally with custom HTTP headers
|
||||
* Save file locally
|
||||
|
||||
## Examples
|
||||
|
||||
```php
|
||||
<?php
|
||||
use mikehaertl\tmp\File;
|
||||
|
||||
$file = new File('some content', '.html');
|
||||
|
||||
// send to client for download
|
||||
$file->send('home.html');
|
||||
// ... with custom content type (autodetected otherwhise)
|
||||
$file->send('home.html', 'application/pdf');
|
||||
// ... for inline display (download dialog otherwhise)
|
||||
$file->send('home.html', 'application/pdf', true);
|
||||
// ... with custom headers
|
||||
$file->send('home.html', 'application/pdf', true, [
|
||||
'X-Header' => 'Example',
|
||||
]);
|
||||
|
||||
// save to disk
|
||||
$file->saveAs('/dir/test.html');
|
||||
|
||||
// Access file name and directory
|
||||
echo $file->getFileName();
|
||||
echo $file->getTempDir();
|
||||
```
|
||||
|
||||
If you want to keep the temporary file, e.g. for debugging, you can set the `$delete` property to false:
|
||||
|
||||
```php
|
||||
<?php
|
||||
use mikehaertl\tmp\File;
|
||||
|
||||
$file = new File('some content', '.html');
|
||||
$file->delete = false;
|
||||
```
|
||||
|
||||
Default HTTP headers can also be added:
|
||||
```php
|
||||
<?php
|
||||
use mikehaertl\tmp\File;
|
||||
|
||||
File::$defaultHeader['X-Header'] = 'My Default';
|
||||
|
||||
$file = new File('some content', '.html');
|
||||
$file->send('home.html');
|
||||
```
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
{
|
||||
"name": "mikehaertl/php-tmpfile",
|
||||
"description": "A convenience class for temporary files",
|
||||
"keywords": ["files"],
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Michael Härtl",
|
||||
"email": "haertl.mike@gmail.com"
|
||||
}
|
||||
],
|
||||
"require-dev": {
|
||||
"php": ">=5.3.0",
|
||||
"phpunit/phpunit": ">4.0 <=9.4"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"mikehaertl\\tmp\\": "src/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"tests\\": "tests"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,197 +0,0 @@
|
|||
<?php
|
||||
namespace mikehaertl\tmp;
|
||||
|
||||
/**
|
||||
* File
|
||||
*
|
||||
* A convenience class for temporary files.
|
||||
*
|
||||
* @author Michael Härtl <haertl.mike@gmail.com>
|
||||
* @license http://www.opensource.org/licenses/MIT
|
||||
*/
|
||||
class File
|
||||
{
|
||||
const DEFAULT_CONTENT_TYPE = 'application/octet-stream';
|
||||
|
||||
/**
|
||||
* @var bool whether to delete the tmp file when it's no longer referenced
|
||||
* or when the request ends. Default is `true`.
|
||||
*/
|
||||
public $delete = true;
|
||||
|
||||
/**
|
||||
* @var array the list of static default headers to send when `send()` is
|
||||
* called as key/value pairs.
|
||||
*/
|
||||
public static $defaultHeaders = array(
|
||||
'Pragma' => 'public',
|
||||
'Expires' => 0,
|
||||
'Cache-Control' => 'must-revalidate, post-check=0, pre-check=0',
|
||||
'Content-Transfer-Encoding' => 'binary',
|
||||
);
|
||||
|
||||
/**
|
||||
* @var string the name of this file
|
||||
*/
|
||||
protected $_fileName;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $content the tmp file content
|
||||
* @param string|null $suffix the optional suffix for the tmp file
|
||||
* @param string|null $prefix the optional prefix for the tmp file. If null
|
||||
* 'php_tmpfile_' is used.
|
||||
* @param string|null $directory directory where the file should be
|
||||
* created. Autodetected if not provided.
|
||||
*/
|
||||
public function __construct($content, $suffix = null, $prefix = null, $directory = null)
|
||||
{
|
||||
if ($directory === null) {
|
||||
$directory = self::getTempDir();
|
||||
}
|
||||
|
||||
if ($prefix === null) {
|
||||
$prefix = 'php_tmpfile_';
|
||||
}
|
||||
|
||||
$this->_fileName = tempnam($directory,$prefix);
|
||||
if ($suffix !== null) {
|
||||
$newName = $this->_fileName . $suffix;
|
||||
rename($this->_fileName, $newName);
|
||||
$this->_fileName = $newName;
|
||||
}
|
||||
file_put_contents($this->_fileName, $content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete tmp file on shutdown if `$delete` is `true`
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
if ($this->delete && file_exists($this->_fileName)) {
|
||||
unlink($this->_fileName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send tmp file to client, either inline or as download
|
||||
*
|
||||
* @param string|null $filename the filename to send. If empty, the file is
|
||||
* streamed inline.
|
||||
* @param string|null $contentType the Content-Type header to send. If
|
||||
* `null` the type is auto-detected and if that fails
|
||||
* 'application/octet-stream' is used.
|
||||
* @param bool $inline whether to force inline display of the file, even if
|
||||
* filename is present.
|
||||
* @param array $headers a list of additional HTTP headers to send in the
|
||||
* response as an array. The array keys are the header names like
|
||||
* 'Cache-Control' and the array values the header value strings to send.
|
||||
* Each array value can also be another array of strings if the same header
|
||||
* should be sent multiple times. This can also be used to override
|
||||
* automatically created headers like 'Expires' or 'Content-Length'. To suppress
|
||||
* automatically created headers, `false` can also be used as header value.
|
||||
*/
|
||||
public function send($filename = null, $contentType = null, $inline = false, $headers = array())
|
||||
{
|
||||
$headers = array_merge(self::$defaultHeaders, $headers);
|
||||
|
||||
if ($contentType !== null) {
|
||||
$headers['Content-Type'] = $contentType;
|
||||
} elseif (!isset($headers['Content-Type'])) {
|
||||
$contentType = @mime_content_type($this->_filename);
|
||||
if ($contentType === false) {
|
||||
$contentType = self::DEFAULT_CONTENT_TYPE;
|
||||
}
|
||||
$headers['Content-Type'] = $contentType;
|
||||
}
|
||||
|
||||
if (!isset($headers['Content-Length'])) {
|
||||
// #11 Undefined index: HTTP_USER_AGENT
|
||||
$userAgent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
|
||||
|
||||
// #84: Content-Length leads to "network connection was lost" on iOS
|
||||
$isIOS = preg_match('/i(phone|pad|pod)/i', $userAgent);
|
||||
if (!$isIOS) {
|
||||
$headers['Content-Length'] = filesize($this->_fileName);
|
||||
}
|
||||
}
|
||||
|
||||
if (($filename !== null || $inline) && !isset($headers['Content-Disposition'])) {
|
||||
$disposition = $inline ? 'inline' : 'attachment';
|
||||
$encodedFilename = rawurlencode($filename);
|
||||
$headers['Content-Disposition'] = "$disposition; " .
|
||||
"filename=\"$filename\"; " .
|
||||
"filename*=UTF-8''$encodedFilename";
|
||||
}
|
||||
|
||||
$this->sendHeaders($headers);
|
||||
readfile($this->_fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name the name to save the file as
|
||||
* @return bool whether the file could be saved
|
||||
*/
|
||||
public function saveAs($name)
|
||||
{
|
||||
return copy($this->_fileName, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string the full file name
|
||||
*/
|
||||
public function getFileName()
|
||||
{
|
||||
return $this->_fileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string the path to the temp directory
|
||||
*/
|
||||
public static function getTempDir()
|
||||
{
|
||||
if (function_exists('sys_get_temp_dir')) {
|
||||
return sys_get_temp_dir();
|
||||
} elseif (
|
||||
($tmp = getenv('TMP')) ||
|
||||
($tmp = getenv('TEMP')) ||
|
||||
($tmp = getenv('TMPDIR'))
|
||||
) {
|
||||
return realpath($tmp);
|
||||
} else {
|
||||
return '/tmp';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string the full file name
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->_fileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the given list of headers
|
||||
*
|
||||
* @param array $headers the list of headers to send as key/value pairs.
|
||||
* Value can either be a string or an array of strings to send the same
|
||||
* header multiple times.
|
||||
*/
|
||||
protected function sendHeaders($headers)
|
||||
{
|
||||
foreach ($headers as $name => $value) {
|
||||
if ($value === false) {
|
||||
continue;
|
||||
}
|
||||
if (is_array($value)) {
|
||||
foreach ($value as $v) {
|
||||
header("$name: $v");
|
||||
}
|
||||
} else {
|
||||
header("$name: $value");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
before_cmds = [
|
||||
"composer install --working-dir=composer/",
|
||||
"composer dump --working-dir=composer/",
|
||||
"composer install --no-dev",
|
||||
"composer dump",
|
||||
"bash ./build/download-fonts.sh",
|
||||
"npm ci",
|
||||
"npm run build"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue