Create email class
This commit is contained in:
parent
e866f9ae49
commit
cb47a12005
42 changed files with 7360 additions and 18 deletions
|
@ -8,6 +8,12 @@
|
|||
"grandel/include-directory": "^0.2.2",
|
||||
"knplabs/github-api": "^3.0",
|
||||
"guzzlehttp/guzzle": "^7.0.1",
|
||||
"http-interop/http-factory-guzzle": "^1.0"
|
||||
"http-interop/http-factory-guzzle": "^1.0",
|
||||
"qferr/mjml-php": "^1.1"
|
||||
},
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
107
composer.lock
generated
107
composer.lock
generated
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "c370a196fb020d63e645d8ea571d04ac",
|
||||
"content-hash": "25846fd23f7252ccce4ba4832e5697ad",
|
||||
"packages": [
|
||||
{
|
||||
"name": "clue/stream-filter",
|
||||
|
@ -1722,6 +1722,47 @@
|
|||
},
|
||||
"time": "2016-08-06T14:39:51+00:00"
|
||||
},
|
||||
{
|
||||
"name": "qferr/mjml-php",
|
||||
"version": "1.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/qferr/mjml-php.git",
|
||||
"reference": "c6ea36c190e304e399a957f7e03b5a378faf41b9"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/qferr/mjml-php/zipball/c6ea36c190e304e399a957f7e03b5a378faf41b9",
|
||||
"reference": "c6ea36c190e304e399a957f7e03b5a378faf41b9",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"guzzlehttp/guzzle": "~6.0|~7.0",
|
||||
"php": ">=7.2",
|
||||
"symfony/process": "~4.0|~5.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~7.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Qferrer\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Quentin",
|
||||
"email": "qferrer@outook.com"
|
||||
}
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/qferr/mjml-php/issues",
|
||||
"source": "https://github.com/qferr/mjml-php/tree/1.1.0"
|
||||
},
|
||||
"time": "2021-03-19T19:03:44+00:00"
|
||||
},
|
||||
{
|
||||
"name": "ralouphie/getallheaders",
|
||||
"version": "3.0.3",
|
||||
|
@ -1982,6 +2023,68 @@
|
|||
}
|
||||
],
|
||||
"time": "2021-09-13T13:58:33+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/process",
|
||||
"version": "v5.4.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/process.git",
|
||||
"reference": "95440409896f90a5f85db07a32b517ecec17fa4c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/process/zipball/95440409896f90a5f85db07a32b517ecec17fa4c",
|
||||
"reference": "95440409896f90a5f85db07a32b517ecec17fa4c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.2.5",
|
||||
"symfony/polyfill-php80": "^1.16"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\Process\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Executes commands in sub-processes",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/process/tree/v5.4.5"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-01-30T18:16:22+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
|
@ -2124,5 +2227,5 @@
|
|||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": [],
|
||||
"plugin-api-version": "2.0.0"
|
||||
"plugin-api-version": "2.2.0"
|
||||
}
|
||||
|
|
|
@ -215,6 +215,9 @@ p .ui.horizontal.label {
|
|||
/**
|
||||
* Menu
|
||||
*/
|
||||
.pusher {
|
||||
min-height: 100vh;
|
||||
}
|
||||
.pusher .menu.toggle {
|
||||
display: none;
|
||||
}
|
||||
|
|
36
src/classes/email.php
Normal file
36
src/classes/email.php
Normal file
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Send an email
|
||||
*
|
||||
* Requires MJML input.
|
||||
*
|
||||
* @see https://mjml.io
|
||||
*
|
||||
* @author Jay Trees <github.jay@grandel.anonaddy.me>
|
||||
*/
|
||||
|
||||
namespace wishthis;
|
||||
|
||||
class Email
|
||||
{
|
||||
public function __construct(
|
||||
private string $to,
|
||||
private string $subject,
|
||||
private string $mjml
|
||||
) {
|
||||
}
|
||||
|
||||
public function send()
|
||||
{
|
||||
$to = $this->to;
|
||||
$subject = $this->subject;
|
||||
$message = $this->mjml;
|
||||
$headers = array(
|
||||
'From' => 'no-reply@' . $_SERVER['HTTP_HOST'],
|
||||
'Content-type' => 'text/html; charset=utf-8',
|
||||
);
|
||||
|
||||
$success = mail($to, $subject, $message, $headers);
|
||||
}
|
||||
}
|
|
@ -10,7 +10,10 @@ use wishthis\Page;
|
|||
|
||||
$page = new Page(__FILE__, 'Login');
|
||||
|
||||
if (isset($_POST['email'], $_POST['password'])) {
|
||||
/**
|
||||
* Login
|
||||
*/
|
||||
if (isset($_POST['login'], $_POST['email'], $_POST['password'])) {
|
||||
$email = $_POST['email'];
|
||||
$password = sha1($_POST['password']);
|
||||
|
||||
|
@ -36,6 +39,21 @@ if (isset($_SESSION['user'])) {
|
|||
die();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset
|
||||
*/
|
||||
if (isset($_POST['reset'], $_POST['email'])) {
|
||||
$user = $database
|
||||
->query('SELECT *
|
||||
FROM `users`
|
||||
WHERE `email` = ' . $_POST['email'] . ';')
|
||||
->fetch();
|
||||
|
||||
if ($user) {
|
||||
$emailReset = new email($_POST['email']);
|
||||
}
|
||||
}
|
||||
|
||||
$page->header();
|
||||
$page->bodyStart();
|
||||
$page->navigation();
|
||||
|
@ -51,19 +69,67 @@ $page->navigation();
|
|||
?>
|
||||
|
||||
<div class="ui segment">
|
||||
<form class="ui form" method="post">
|
||||
<div class="field">
|
||||
<label>Email</label>
|
||||
<input type="email" name="email" placeholder="john.doe@domain.tld" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Password</label>
|
||||
<input type="password" name="password" />
|
||||
<div class="ui divided relaxed stackable two column grid">
|
||||
|
||||
<div class="row">
|
||||
<div class="column">
|
||||
<h2 class="ui header">Credentials</h2>
|
||||
|
||||
<form class="ui form login" method="post">
|
||||
<div class="field">
|
||||
<label>Email</label>
|
||||
|
||||
<div class="ui left icon input">
|
||||
<input type="email" name="email" placeholder="john.doe@domain.tld" />
|
||||
<i class="envelope icon"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label>Password</label>
|
||||
|
||||
<div class="ui left icon input">
|
||||
<input type="password" name="password" />
|
||||
<i class="key icon"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<input class="ui primary button" type="submit" name="login" value="Login" />
|
||||
<a class="ui tertiary button" href="/?page=register">Register</a>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="column">
|
||||
<h2 class="ui header">Forgot password?</h2>
|
||||
|
||||
<p>
|
||||
Consider using a password manager.
|
||||
It will save all your passwords and allow you to access them with one master password.
|
||||
Never forget a password ever again.
|
||||
</p>
|
||||
<p><a href="https://bitwarden.com/" target="_blank">Bitwarden</a> is the most trusted open source password manager.</p>
|
||||
|
||||
<p>
|
||||
<form class="ui form reset" method="post">
|
||||
<div class="field">
|
||||
<div class="ui action input">
|
||||
<div class="ui left icon action input">
|
||||
<input type="email" name="email" placeholder="john.doe@domain.tld" />
|
||||
<i class="envelope icon"></i>
|
||||
</div>
|
||||
|
||||
<input class="ui primary button" type="submit" name="reset" value="Send email" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</form>
|
||||
</p>
|
||||
|
||||
<p>Please note that you have to enter the email address, you have registered with.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<input class="ui primary button" type="submit" value="Login" />
|
||||
<a href="/?page=register">Register</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
|
|
@ -101,11 +101,20 @@ $page->navigation();
|
|||
|
||||
<div class="field">
|
||||
<label>Email</label>
|
||||
<input type="email" name="email" placeholder="john.doe@domain.tld" />
|
||||
|
||||
<div class="ui left icon input">
|
||||
<input type="email" name="email" placeholder="john.doe@domain.tld" />
|
||||
<i class="envelope icon"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label>Password</label>
|
||||
<input type="password" name="password" />
|
||||
|
||||
<div class="ui left icon input">
|
||||
<input type="password" name="password" />
|
||||
<i class="key icon"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -118,7 +127,11 @@ $page->navigation();
|
|||
|
||||
<div class="field">
|
||||
<label>Planet</label>
|
||||
<input type="text" name="planet" />
|
||||
|
||||
<div class="ui left icon input">
|
||||
<input type="text" name="planet" />
|
||||
<i class="globe icon"></i>
|
||||
</div>
|
||||
</div>
|
||||
<p>Robots are obivously from another solar system so this will keep them at bay.</p>
|
||||
</div>
|
||||
|
|
3
vendor/qferr/mjml-php/.gitignore
vendored
Normal file
3
vendor/qferr/mjml-php/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
.idea/
|
||||
vendor/
|
||||
node_modules/
|
79
vendor/qferr/mjml-php/README.md
vendored
Normal file
79
vendor/qferr/mjml-php/README.md
vendored
Normal file
|
@ -0,0 +1,79 @@
|
|||
MJML in PHP
|
||||
===========
|
||||
|
||||
A simple PHP library to render MJML to HTML.
|
||||
|
||||
There are two ways for integrating MJML in PHP:
|
||||
* using the MJML API
|
||||
* using the MJML library
|
||||
|
||||
### Installation
|
||||
|
||||
```shell script
|
||||
composer require qferr/mjml-php
|
||||
```
|
||||
|
||||
### Using MJML library
|
||||
|
||||
Install the MJML library:
|
||||
|
||||
```shell script
|
||||
npm install mjml --save
|
||||
```
|
||||
|
||||
If you want a specific version, use the following syntax: `npm install mjml@4.7.1 --save`
|
||||
|
||||
```php
|
||||
<?php
|
||||
require_once 'vendor/autoload.php';
|
||||
|
||||
$renderer = new \Qferrer\Mjml\Renderer\BinaryRenderer(__DIR__ . '/node_modules/.bin/mjml');
|
||||
|
||||
$html = $renderer->render('
|
||||
<mjml>
|
||||
<mj-body>
|
||||
<mj-section>
|
||||
<mj-column>
|
||||
<mj-text>Hello world</mj-text>
|
||||
</mj-column>
|
||||
</mj-section>
|
||||
</mj-body>
|
||||
</mjml>
|
||||
');
|
||||
```
|
||||
|
||||
### Using MJML API
|
||||
|
||||
```php
|
||||
<?php
|
||||
require_once 'vendor/autoload.php';
|
||||
|
||||
$apiId = 'abcdef-1234-5678-ghijkl';
|
||||
$secretKey = 'ghijkl-5678-1234-abcdef';
|
||||
|
||||
$renderer = new \Qferrer\Mjml\Renderer\ApiRenderer($apiId, $secretKey);
|
||||
|
||||
$html = $renderer->render('
|
||||
<mjml>
|
||||
<mj-body>
|
||||
<mj-section>
|
||||
<mj-column>
|
||||
<mj-text>Hello world</mj-text>
|
||||
</mj-column>
|
||||
</mj-section>
|
||||
</mj-body>
|
||||
</mjml>
|
||||
');
|
||||
```
|
||||
|
||||
To find out which version of the library is used by the API, check the `mjml_version` key in the payload returned by the API:
|
||||
```
|
||||
{
|
||||
"html": "\n <!doctype html>\n <html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:v=\"urn:schemas-microsoft-com:vml\" xmlns:o=\"urn:schemas-microsoft-com:office:office\">\n <head>\n <title>\n \n </title>\n <!--[if !mso]><!-- -->\n <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n <!--<![endif]-->\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <style type=\"text/css\">\n #outlook a { padding:0; }\n body { margin:0;padding:0;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%; }\n table, td { border-collapse:collapse;mso-table-lspace:0pt;mso-table-rspace:0pt; }\n img { border:0;height:auto;line-height:100%; outline:none;text-decoration:none;-ms-interpolation-mode:bicubic; }\n p { display:block;margin:13px 0; }\n </style>\n <!--[if mso]>\n <xml>\n <o:OfficeDocumentSettings>\n <o:AllowPNG/>\n <o:PixelsPerInch>96</o:PixelsPerInch>\n </o:OfficeDocumentSettings>\n </xml>\n <![endif]-->\n <!--[if lte mso 11]>\n <style type=\"text/css\">\n .mj-outlook-group-fix { width:100% !important; }\n </style>\n <![endif]-->\n \n <!--[if !mso]><!-->\n <link href=\"https://fonts.googleapis.com/css?family=Ubuntu:300,400,500,700\" rel=\"stylesheet\" type=\"text/css\">\n <style type=\"text/css\">\n @import url(https://fonts.googleapis.com/css?family=Ubuntu:300,400,500,700);\n </style>\n <!--<![endif]-->\n\n \n \n <style type=\"text/css\">\n @media only screen and (min-width:480px) {\n .mj-column-per-100 { width:100% !important; max-width: 100%; }\n }\n </style>\n \n \n <style type=\"text/css\">\n \n \n </style>\n \n \n </head>\n <body>\n \n \n <div\n style=\"\"\n >\n \n \n <!--[if mso | IE]>\n <table\n align=\"center\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" class=\"\" style=\"width:600px;\" width=\"600\"\n >\n <tr>\n <td style=\"line-height:0px;font-size:0px;mso-line-height-rule:exactly;\">\n <![endif]-->\n \n \n <div style=\"margin:0px auto;max-width:600px;\">\n \n <table\n align=\"center\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" role=\"presentation\" style=\"width:100%;\"\n >\n <tbody>\n <tr>\n <td\n style=\"direction:ltr;font-size:0px;padding:20px 0;text-align:center;\"\n >\n <!--[if mso | IE]>\n <table role=\"presentation\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\">\n \n <tr>\n \n <td\n class=\"\" style=\"vertical-align:top;width:600px;\"\n >\n <![endif]-->\n \n <div\n class=\"mj-column-per-100 mj-outlook-group-fix\" style=\"font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;\"\n >\n \n <table\n border=\"0\" cellpadding=\"0\" cellspacing=\"0\" role=\"presentation\" style=\"vertical-align:top;\" width=\"100%\"\n >\n \n <tr>\n <td\n align=\"left\" style=\"font-size:0px;padding:10px 25px;word-break:break-word;\"\n >\n \n <div\n style=\"font-family:Ubuntu, Helvetica, Arial, sans-serif;font-size:13px;line-height:1;text-align:left;color:#000000;\"\n >Hello World</div>\n \n </td>\n </tr>\n \n </table>\n \n </div>\n \n <!--[if mso | IE]>\n </td>\n \n </tr>\n \n </table>\n <![endif]-->\n </td>\n </tr>\n </tbody>\n </table>\n \n </div>\n \n \n <!--[if mso | IE]>\n </td>\n </tr>\n </table>\n <![endif]-->\n \n \n </div>\n \n </body>\n </html>\n ",
|
||||
"errors": [],
|
||||
"mjml": "<mjml><mj-body><mj-container><mj-section><mj-column><mj-text>Hello World</mj-text></mj-column></mj-section></mj-container></mj-body></mjml>",
|
||||
"mjml_version": "4.6.1"
|
||||
}
|
||||
```
|
||||
|
||||
More details in the API documentation: https://mjml.io/api/documentation/
|
28
vendor/qferr/mjml-php/composer.json
vendored
Normal file
28
vendor/qferr/mjml-php/composer.json
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"name": "qferr/mjml-php",
|
||||
"type": "library",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Quentin",
|
||||
"email": "qferrer@outook.com"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=7.2",
|
||||
"symfony/process": "~4.0|~5.0",
|
||||
"guzzlehttp/guzzle": "~6.0|~7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~7.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Qferrer\\" : "src/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Qferrer\\Tests\\" : "tests/"
|
||||
}
|
||||
}
|
||||
}
|
2101
vendor/qferr/mjml-php/composer.lock
generated
vendored
Normal file
2101
vendor/qferr/mjml-php/composer.lock
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
1353
vendor/qferr/mjml-php/package-lock.json
generated
vendored
Normal file
1353
vendor/qferr/mjml-php/package-lock.json
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
12
vendor/qferr/mjml-php/package.json
vendored
Normal file
12
vendor/qferr/mjml-php/package.json
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"name": "mjml-php",
|
||||
"description": "MJML in PHP",
|
||||
"author": "Quentin Ferrer",
|
||||
"bugs": {
|
||||
"url": "https://github.com/qferr/mjml-php/issues"
|
||||
},
|
||||
"homepage": "https://github.com/qferr/mjml-php#readme",
|
||||
"devDependencies": {
|
||||
"mjml": "^4.9.0"
|
||||
}
|
||||
}
|
71
vendor/qferr/mjml-php/src/Mjml/Renderer/ApiRenderer.php
vendored
Normal file
71
vendor/qferr/mjml-php/src/Mjml/Renderer/ApiRenderer.php
vendored
Normal file
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
|
||||
namespace Qferrer\Mjml\Renderer;
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
|
||||
/**
|
||||
* Class ApiRenderer
|
||||
*/
|
||||
class ApiRenderer implements RendererInterface
|
||||
{
|
||||
/**
|
||||
* The client
|
||||
*
|
||||
* @var Client
|
||||
*/
|
||||
private $client;
|
||||
|
||||
/**
|
||||
* The application ID
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $appId;
|
||||
|
||||
/**
|
||||
* The secret key
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $secretKey;
|
||||
|
||||
/**
|
||||
* The MJML base uri.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const BASE_URI = "https://api.mjml.io/v1/";
|
||||
|
||||
/**
|
||||
* ApiRenderer constructor.
|
||||
*
|
||||
* @param string $appId
|
||||
* @param string $secretKey
|
||||
*/
|
||||
public function __construct(string $appId, string $secretKey)
|
||||
{
|
||||
$this->appId = $appId;
|
||||
$this->secretKey = $secretKey;
|
||||
$this->client = new Client(['base_uri' => self::BASE_URI]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function render(string $content): string
|
||||
{
|
||||
$response = $this->client->post('render', [
|
||||
'auth' => [$this->appId, $this->secretKey],
|
||||
'body' => json_encode([
|
||||
'mjml' => $content
|
||||
])
|
||||
]);
|
||||
|
||||
if (false === $data = json_decode($response->getBody()->getContents(), true)) {
|
||||
throw new \RuntimeException('Unable to decode response');
|
||||
}
|
||||
|
||||
return $data['html'];
|
||||
}
|
||||
}
|
54
vendor/qferr/mjml-php/src/Mjml/Renderer/BinaryRenderer.php
vendored
Normal file
54
vendor/qferr/mjml-php/src/Mjml/Renderer/BinaryRenderer.php
vendored
Normal file
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
|
||||
namespace Qferrer\Mjml\Renderer;
|
||||
|
||||
use Symfony\Component\Process\Exception\ProcessFailedException;
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
/**
|
||||
* Class BinaryRenderer
|
||||
*/
|
||||
class BinaryRenderer implements RendererInterface
|
||||
{
|
||||
/**
|
||||
* The MJML CLI path.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $bin;
|
||||
|
||||
/**
|
||||
* BinaryRenderer constructor.
|
||||
*
|
||||
* @param string $bin
|
||||
*/
|
||||
public function __construct(string $bin)
|
||||
{
|
||||
$this->bin = $bin;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function render(string $content): string
|
||||
{
|
||||
$arguments = [
|
||||
$this->bin,
|
||||
'-i',
|
||||
'-s',
|
||||
'--config.validationLevel',
|
||||
'--config.minify'
|
||||
];
|
||||
|
||||
$process = new Process($arguments);
|
||||
$process->setInput($content);
|
||||
|
||||
try {
|
||||
$process->mustRun();
|
||||
} catch (ProcessFailedException $e) {
|
||||
throw new \RuntimeException('Unable to compile MJML. Stack error: '.$e->getMessage());
|
||||
}
|
||||
|
||||
return $process->getOutput();
|
||||
}
|
||||
}
|
18
vendor/qferr/mjml-php/src/Mjml/Renderer/RendererInterface.php
vendored
Normal file
18
vendor/qferr/mjml-php/src/Mjml/Renderer/RendererInterface.php
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
namespace Qferrer\Mjml\Renderer;
|
||||
|
||||
/**
|
||||
* Interface RendererInterface
|
||||
*/
|
||||
interface RendererInterface
|
||||
{
|
||||
/**
|
||||
* Renderer MJML to HTML content
|
||||
*
|
||||
* @param string $content The MJML content
|
||||
*
|
||||
* @return string The generated HTML
|
||||
*/
|
||||
public function render(string $content): string;
|
||||
}
|
30
vendor/qferr/mjml-php/tests/Mjml/Renderer/ApiRendererTests.php
vendored
Normal file
30
vendor/qferr/mjml-php/tests/Mjml/Renderer/ApiRendererTests.php
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace Qferrer\Tests\Mjml\Renderer;
|
||||
|
||||
use GuzzleHttp\Exception\ClientException;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Qferrer\Mjml\Renderer\ApiRenderer;
|
||||
use Qferrer\Tests\ResourcesTrait;
|
||||
|
||||
class ApiRendererTests extends TestCase
|
||||
{
|
||||
use ResourcesTrait;
|
||||
|
||||
public function testRender()
|
||||
{
|
||||
$renderer = new ApiRenderer($_ENV['MJML_API_ID'], $_ENV['MJML_API_SECRET_KEY']);
|
||||
|
||||
$html = $renderer->render($this->loadResource('hello_world.mjml'));
|
||||
|
||||
$this->assertEquals($this->loadResource('hello_world.html'), $html);
|
||||
}
|
||||
|
||||
public function testRenderWithInvalidCredentialsThrowException()
|
||||
{
|
||||
$this->expectException(ClientException::class);
|
||||
|
||||
$renderer = new ApiRenderer('test', 'test');
|
||||
$renderer->render($this->loadResource('hello_world.html'));
|
||||
}
|
||||
}
|
29
vendor/qferr/mjml-php/tests/Mjml/Renderer/BinaryRendererTest.php
vendored
Normal file
29
vendor/qferr/mjml-php/tests/Mjml/Renderer/BinaryRendererTest.php
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace Qferrer\Tests\Mjml\Renderer;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Qferrer\Mjml\Renderer\BinaryRenderer;
|
||||
use Qferrer\Tests\ResourcesTrait;
|
||||
|
||||
class BinaryRendererTest extends TestCase
|
||||
{
|
||||
use ResourcesTrait;
|
||||
|
||||
public function testRender()
|
||||
{
|
||||
$renderer = new BinaryRenderer(__DIR__ . '/../../../node_modules/.bin/mjml');
|
||||
|
||||
$html = $renderer->render($this->loadResource('hello_world.mjml'));
|
||||
|
||||
$this->assertEquals($this->loadResource('hello_world.min.html'), $html);
|
||||
}
|
||||
|
||||
public function testRenderWithInvalidBinaryThrowException()
|
||||
{
|
||||
$this->expectException(\RuntimeException::class);
|
||||
|
||||
$renderer = new BinaryRenderer('unknown');
|
||||
$renderer->render($this->loadResource('hello_world.mjml'));
|
||||
}
|
||||
}
|
144
vendor/qferr/mjml-php/tests/Resources/hello_world.html
vendored
Normal file
144
vendor/qferr/mjml-php/tests/Resources/hello_world.html
vendored
Normal file
|
@ -0,0 +1,144 @@
|
|||
|
||||
<!doctype html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
|
||||
<head>
|
||||
<title>
|
||||
|
||||
</title>
|
||||
<!--[if !mso]><!-- -->
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<!--<![endif]-->
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<style type="text/css">
|
||||
#outlook a { padding:0; }
|
||||
body { margin:0;padding:0;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%; }
|
||||
table, td { border-collapse:collapse;mso-table-lspace:0pt;mso-table-rspace:0pt; }
|
||||
img { border:0;height:auto;line-height:100%; outline:none;text-decoration:none;-ms-interpolation-mode:bicubic; }
|
||||
p { display:block;margin:13px 0; }
|
||||
</style>
|
||||
<!--[if mso]>
|
||||
<xml>
|
||||
<o:OfficeDocumentSettings>
|
||||
<o:AllowPNG/>
|
||||
<o:PixelsPerInch>96</o:PixelsPerInch>
|
||||
</o:OfficeDocumentSettings>
|
||||
</xml>
|
||||
<![endif]-->
|
||||
<!--[if lte mso 11]>
|
||||
<style type="text/css">
|
||||
.mj-outlook-group-fix { width:100% !important; }
|
||||
</style>
|
||||
<![endif]-->
|
||||
|
||||
<!--[if !mso]><!-->
|
||||
<link href="https://fonts.googleapis.com/css?family=Ubuntu:300,400,500,700" rel="stylesheet" type="text/css">
|
||||
<style type="text/css">
|
||||
@import url(https://fonts.googleapis.com/css?family=Ubuntu:300,400,500,700);
|
||||
</style>
|
||||
<!--<![endif]-->
|
||||
|
||||
|
||||
|
||||
<style type="text/css">
|
||||
@media only screen and (min-width:480px) {
|
||||
.mj-column-per-100 { width:100% !important; max-width: 100%; }
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
<style type="text/css">
|
||||
|
||||
|
||||
</style>
|
||||
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
<div
|
||||
style=""
|
||||
>
|
||||
|
||||
|
||||
<!--[if mso | IE]>
|
||||
<table
|
||||
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
|
||||
>
|
||||
<tr>
|
||||
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
|
||||
<![endif]-->
|
||||
|
||||
|
||||
<div style="margin:0px auto;max-width:600px;">
|
||||
|
||||
<table
|
||||
align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;"
|
||||
>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td
|
||||
style="direction:ltr;font-size:0px;padding:20px 0;text-align:center;"
|
||||
>
|
||||
<!--[if mso | IE]>
|
||||
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
|
||||
|
||||
<tr>
|
||||
|
||||
<td
|
||||
class="" style="vertical-align:top;width:600px;"
|
||||
>
|
||||
<![endif]-->
|
||||
|
||||
<div
|
||||
class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;"
|
||||
>
|
||||
|
||||
<table
|
||||
border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%"
|
||||
>
|
||||
|
||||
<tr>
|
||||
<td
|
||||
align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;"
|
||||
>
|
||||
|
||||
<div
|
||||
style="font-family:Ubuntu, Helvetica, Arial, sans-serif;font-size:13px;line-height:1;text-align:left;color:#000000;"
|
||||
>Hello world</div>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
<!--[if mso | IE]>
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
<![endif]-->
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<!--[if mso | IE]>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<![endif]-->
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
51
vendor/qferr/mjml-php/tests/Resources/hello_world.min.html
vendored
Normal file
51
vendor/qferr/mjml-php/tests/Resources/hello_world.min.html
vendored
Normal file
|
@ -0,0 +1,51 @@
|
|||
<!-- FILE: undefined -->
|
||||
<!doctype html><html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office"><head><title></title><!--[if !mso]><!--><meta http-equiv="X-UA-Compatible" content="IE=edge"><!--<![endif]--><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1"><style type="text/css">#outlook a {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-ms-text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
table,
|
||||
td {
|
||||
border-collapse: collapse;
|
||||
mso-table-lspace: 0pt;
|
||||
mso-table-rspace: 0pt;
|
||||
}
|
||||
|
||||
img {
|
||||
border: 0;
|
||||
height: auto;
|
||||
line-height: 100%;
|
||||
outline: none;
|
||||
text-decoration: none;
|
||||
-ms-interpolation-mode: bicubic;
|
||||
}
|
||||
|
||||
p {
|
||||
display: block;
|
||||
margin: 13px 0;
|
||||
}</style><!--[if mso]>
|
||||
<xml>
|
||||
<o:OfficeDocumentSettings>
|
||||
<o:AllowPNG/>
|
||||
<o:PixelsPerInch>96</o:PixelsPerInch>
|
||||
</o:OfficeDocumentSettings>
|
||||
</xml>
|
||||
<![endif]--><!--[if lte mso 11]>
|
||||
<style type="text/css">
|
||||
.mj-outlook-group-fix { width:100% !important; }
|
||||
</style>
|
||||
<![endif]--><!--[if !mso]><!--><link href="https://fonts.googleapis.com/css?family=Ubuntu:300,400,500,700" rel="stylesheet" type="text/css"><style type="text/css">@import url(https://fonts.googleapis.com/css?family=Ubuntu:300,400,500,700);</style><!--<![endif]--><style type="text/css">@media only screen and (min-width:480px) {
|
||||
.mj-column-per-100 {
|
||||
width: 100% !important;
|
||||
max-width: 100%;
|
||||
}
|
||||
}</style><style media="screen and (min-width:480px)">.moz-text-html .mj-column-per-100 {
|
||||
width: 100% !important;
|
||||
max-width: 100%;
|
||||
}</style><style type="text/css"></style></head><body style="word-spacing:normal;"><div><!--[if mso | IE]><table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]--><div style="margin:0px auto;max-width:600px;"><table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;"><tbody><tr><td style="direction:ltr;font-size:0px;padding:20px 0;text-align:center;"><!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td class="" style="vertical-align:top;width:600px;" ><![endif]--><div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;"><table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%"><tbody><tr><td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;"><div style="font-family:Ubuntu, Helvetica, Arial, sans-serif;font-size:13px;line-height:1;text-align:left;color:#000000;">Hello world</div></td></tr></tbody></table></div><!--[if mso | IE]></td></tr></table><![endif]--></td></tr></tbody></table></div><!--[if mso | IE]></td></tr></table><![endif]--></div></body></html>
|
9
vendor/qferr/mjml-php/tests/Resources/hello_world.mjml
vendored
Normal file
9
vendor/qferr/mjml-php/tests/Resources/hello_world.mjml
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
<mjml>
|
||||
<mj-body>
|
||||
<mj-section>
|
||||
<mj-column>
|
||||
<mj-text>Hello world</mj-text>
|
||||
</mj-column>
|
||||
</mj-section>
|
||||
</mj-body>
|
||||
</mjml>
|
11
vendor/qferr/mjml-php/tests/ResourcesTrait.php
vendored
Normal file
11
vendor/qferr/mjml-php/tests/ResourcesTrait.php
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
namespace Qferrer\Tests;
|
||||
|
||||
trait ResourcesTrait
|
||||
{
|
||||
private function loadResource($filename)
|
||||
{
|
||||
return file_get_contents(__DIR__ . '/Resources/' . $filename);
|
||||
}
|
||||
}
|
116
vendor/symfony/process/CHANGELOG.md
vendored
Normal file
116
vendor/symfony/process/CHANGELOG.md
vendored
Normal file
|
@ -0,0 +1,116 @@
|
|||
CHANGELOG
|
||||
=========
|
||||
|
||||
5.2.0
|
||||
-----
|
||||
|
||||
* added `Process::setOptions()` to set `Process` specific options
|
||||
* added option `create_new_console` to allow a subprocess to continue
|
||||
to run after the main script exited, both on Linux and on Windows
|
||||
|
||||
5.1.0
|
||||
-----
|
||||
|
||||
* added `Process::getStartTime()` to retrieve the start time of the process as float
|
||||
|
||||
5.0.0
|
||||
-----
|
||||
|
||||
* removed `Process::inheritEnvironmentVariables()`
|
||||
* removed `PhpProcess::setPhpBinary()`
|
||||
* `Process` must be instantiated with a command array, use `Process::fromShellCommandline()` when the command should be parsed by the shell
|
||||
* removed `Process::setCommandLine()`
|
||||
|
||||
4.4.0
|
||||
-----
|
||||
|
||||
* deprecated `Process::inheritEnvironmentVariables()`: env variables are always inherited.
|
||||
* added `Process::getLastOutputTime()` method
|
||||
|
||||
4.2.0
|
||||
-----
|
||||
|
||||
* added the `Process::fromShellCommandline()` to run commands in a shell wrapper
|
||||
* deprecated passing a command as string when creating a `Process` instance
|
||||
* deprecated the `Process::setCommandline()` and the `PhpProcess::setPhpBinary()` methods
|
||||
* added the `Process::waitUntil()` method to wait for the process only for a
|
||||
specific output, then continue the normal execution of your application
|
||||
|
||||
4.1.0
|
||||
-----
|
||||
|
||||
* added the `Process::isTtySupported()` method that allows to check for TTY support
|
||||
* made `PhpExecutableFinder` look for the `PHP_BINARY` env var when searching the php binary
|
||||
* added the `ProcessSignaledException` class to properly catch signaled process errors
|
||||
|
||||
4.0.0
|
||||
-----
|
||||
|
||||
* environment variables will always be inherited
|
||||
* added a second `array $env = []` argument to the `start()`, `run()`,
|
||||
`mustRun()`, and `restart()` methods of the `Process` class
|
||||
* added a second `array $env = []` argument to the `start()` method of the
|
||||
`PhpProcess` class
|
||||
* the `ProcessUtils::escapeArgument()` method has been removed
|
||||
* the `areEnvironmentVariablesInherited()`, `getOptions()`, and `setOptions()`
|
||||
methods of the `Process` class have been removed
|
||||
* support for passing `proc_open()` options has been removed
|
||||
* removed the `ProcessBuilder` class, use the `Process` class instead
|
||||
* removed the `getEnhanceWindowsCompatibility()` and `setEnhanceWindowsCompatibility()` methods of the `Process` class
|
||||
* passing a not existing working directory to the constructor of the `Symfony\Component\Process\Process` class is not
|
||||
supported anymore
|
||||
|
||||
3.4.0
|
||||
-----
|
||||
|
||||
* deprecated the ProcessBuilder class
|
||||
* deprecated calling `Process::start()` without setting a valid working directory beforehand (via `setWorkingDirectory()` or constructor)
|
||||
|
||||
3.3.0
|
||||
-----
|
||||
|
||||
* added command line arrays in the `Process` class
|
||||
* added `$env` argument to `Process::start()`, `run()`, `mustRun()` and `restart()` methods
|
||||
* deprecated the `ProcessUtils::escapeArgument()` method
|
||||
* deprecated not inheriting environment variables
|
||||
* deprecated configuring `proc_open()` options
|
||||
* deprecated configuring enhanced Windows compatibility
|
||||
* deprecated configuring enhanced sigchild compatibility
|
||||
|
||||
2.5.0
|
||||
-----
|
||||
|
||||
* added support for PTY mode
|
||||
* added the convenience method "mustRun"
|
||||
* deprecation: Process::setStdin() is deprecated in favor of Process::setInput()
|
||||
* deprecation: Process::getStdin() is deprecated in favor of Process::getInput()
|
||||
* deprecation: Process::setInput() and ProcessBuilder::setInput() do not accept non-scalar types
|
||||
|
||||
2.4.0
|
||||
-----
|
||||
|
||||
* added the ability to define an idle timeout
|
||||
|
||||
2.3.0
|
||||
-----
|
||||
|
||||
* added ProcessUtils::escapeArgument() to fix the bug in escapeshellarg() function on Windows
|
||||
* added Process::signal()
|
||||
* added Process::getPid()
|
||||
* added support for a TTY mode
|
||||
|
||||
2.2.0
|
||||
-----
|
||||
|
||||
* added ProcessBuilder::setArguments() to reset the arguments on a builder
|
||||
* added a way to retrieve the standard and error output incrementally
|
||||
* added Process:restart()
|
||||
|
||||
2.1.0
|
||||
-----
|
||||
|
||||
* added support for non-blocking processes (start(), wait(), isRunning(), stop())
|
||||
* enhanced Windows compatibility
|
||||
* added Process::getExitCodeText() that returns a string representation for
|
||||
the exit code returned by the process
|
||||
* added ProcessBuilder
|
21
vendor/symfony/process/Exception/ExceptionInterface.php
vendored
Normal file
21
vendor/symfony/process/Exception/ExceptionInterface.php
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Process\Exception;
|
||||
|
||||
/**
|
||||
* Marker Interface for the Process Component.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
interface ExceptionInterface extends \Throwable
|
||||
{
|
||||
}
|
21
vendor/symfony/process/Exception/InvalidArgumentException.php
vendored
Normal file
21
vendor/symfony/process/Exception/InvalidArgumentException.php
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Process\Exception;
|
||||
|
||||
/**
|
||||
* InvalidArgumentException for the Process Component.
|
||||
*
|
||||
* @author Romain Neutron <imprec@gmail.com>
|
||||
*/
|
||||
class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
|
||||
{
|
||||
}
|
21
vendor/symfony/process/Exception/LogicException.php
vendored
Normal file
21
vendor/symfony/process/Exception/LogicException.php
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Process\Exception;
|
||||
|
||||
/**
|
||||
* LogicException for the Process Component.
|
||||
*
|
||||
* @author Romain Neutron <imprec@gmail.com>
|
||||
*/
|
||||
class LogicException extends \LogicException implements ExceptionInterface
|
||||
{
|
||||
}
|
54
vendor/symfony/process/Exception/ProcessFailedException.php
vendored
Normal file
54
vendor/symfony/process/Exception/ProcessFailedException.php
vendored
Normal file
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Process\Exception;
|
||||
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
/**
|
||||
* Exception for failed processes.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class ProcessFailedException extends RuntimeException
|
||||
{
|
||||
private $process;
|
||||
|
||||
public function __construct(Process $process)
|
||||
{
|
||||
if ($process->isSuccessful()) {
|
||||
throw new InvalidArgumentException('Expected a failed process, but the given process was successful.');
|
||||
}
|
||||
|
||||
$error = sprintf('The command "%s" failed.'."\n\nExit Code: %s(%s)\n\nWorking directory: %s",
|
||||
$process->getCommandLine(),
|
||||
$process->getExitCode(),
|
||||
$process->getExitCodeText(),
|
||||
$process->getWorkingDirectory()
|
||||
);
|
||||
|
||||
if (!$process->isOutputDisabled()) {
|
||||
$error .= sprintf("\n\nOutput:\n================\n%s\n\nError Output:\n================\n%s",
|
||||
$process->getOutput(),
|
||||
$process->getErrorOutput()
|
||||
);
|
||||
}
|
||||
|
||||
parent::__construct($error);
|
||||
|
||||
$this->process = $process;
|
||||
}
|
||||
|
||||
public function getProcess()
|
||||
{
|
||||
return $this->process;
|
||||
}
|
||||
}
|
41
vendor/symfony/process/Exception/ProcessSignaledException.php
vendored
Normal file
41
vendor/symfony/process/Exception/ProcessSignaledException.php
vendored
Normal file
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Process\Exception;
|
||||
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
/**
|
||||
* Exception that is thrown when a process has been signaled.
|
||||
*
|
||||
* @author Sullivan Senechal <soullivaneuh@gmail.com>
|
||||
*/
|
||||
final class ProcessSignaledException extends RuntimeException
|
||||
{
|
||||
private $process;
|
||||
|
||||
public function __construct(Process $process)
|
||||
{
|
||||
$this->process = $process;
|
||||
|
||||
parent::__construct(sprintf('The process has been signaled with signal "%s".', $process->getTermSignal()));
|
||||
}
|
||||
|
||||
public function getProcess(): Process
|
||||
{
|
||||
return $this->process;
|
||||
}
|
||||
|
||||
public function getSignal(): int
|
||||
{
|
||||
return $this->getProcess()->getTermSignal();
|
||||
}
|
||||
}
|
69
vendor/symfony/process/Exception/ProcessTimedOutException.php
vendored
Normal file
69
vendor/symfony/process/Exception/ProcessTimedOutException.php
vendored
Normal file
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Process\Exception;
|
||||
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
/**
|
||||
* Exception that is thrown when a process times out.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class ProcessTimedOutException extends RuntimeException
|
||||
{
|
||||
public const TYPE_GENERAL = 1;
|
||||
public const TYPE_IDLE = 2;
|
||||
|
||||
private $process;
|
||||
private $timeoutType;
|
||||
|
||||
public function __construct(Process $process, int $timeoutType)
|
||||
{
|
||||
$this->process = $process;
|
||||
$this->timeoutType = $timeoutType;
|
||||
|
||||
parent::__construct(sprintf(
|
||||
'The process "%s" exceeded the timeout of %s seconds.',
|
||||
$process->getCommandLine(),
|
||||
$this->getExceededTimeout()
|
||||
));
|
||||
}
|
||||
|
||||
public function getProcess()
|
||||
{
|
||||
return $this->process;
|
||||
}
|
||||
|
||||
public function isGeneralTimeout()
|
||||
{
|
||||
return self::TYPE_GENERAL === $this->timeoutType;
|
||||
}
|
||||
|
||||
public function isIdleTimeout()
|
||||
{
|
||||
return self::TYPE_IDLE === $this->timeoutType;
|
||||
}
|
||||
|
||||
public function getExceededTimeout()
|
||||
{
|
||||
switch ($this->timeoutType) {
|
||||
case self::TYPE_GENERAL:
|
||||
return $this->process->getTimeout();
|
||||
|
||||
case self::TYPE_IDLE:
|
||||
return $this->process->getIdleTimeout();
|
||||
|
||||
default:
|
||||
throw new \LogicException(sprintf('Unknown timeout type "%d".', $this->timeoutType));
|
||||
}
|
||||
}
|
||||
}
|
21
vendor/symfony/process/Exception/RuntimeException.php
vendored
Normal file
21
vendor/symfony/process/Exception/RuntimeException.php
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Process\Exception;
|
||||
|
||||
/**
|
||||
* RuntimeException for the Process Component.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class RuntimeException extends \RuntimeException implements ExceptionInterface
|
||||
{
|
||||
}
|
86
vendor/symfony/process/ExecutableFinder.php
vendored
Normal file
86
vendor/symfony/process/ExecutableFinder.php
vendored
Normal file
|
@ -0,0 +1,86 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Process;
|
||||
|
||||
/**
|
||||
* Generic executable finder.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class ExecutableFinder
|
||||
{
|
||||
private $suffixes = ['.exe', '.bat', '.cmd', '.com'];
|
||||
|
||||
/**
|
||||
* Replaces default suffixes of executable.
|
||||
*/
|
||||
public function setSuffixes(array $suffixes)
|
||||
{
|
||||
$this->suffixes = $suffixes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds new possible suffix to check for executable.
|
||||
*/
|
||||
public function addSuffix(string $suffix)
|
||||
{
|
||||
$this->suffixes[] = $suffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds an executable by name.
|
||||
*
|
||||
* @param string $name The executable name (without the extension)
|
||||
* @param string|null $default The default to return if no executable is found
|
||||
* @param array $extraDirs Additional dirs to check into
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function find(string $name, string $default = null, array $extraDirs = [])
|
||||
{
|
||||
if (ini_get('open_basedir')) {
|
||||
$searchPath = array_merge(explode(\PATH_SEPARATOR, ini_get('open_basedir')), $extraDirs);
|
||||
$dirs = [];
|
||||
foreach ($searchPath as $path) {
|
||||
// Silencing against https://bugs.php.net/69240
|
||||
if (@is_dir($path)) {
|
||||
$dirs[] = $path;
|
||||
} else {
|
||||
if (basename($path) == $name && @is_executable($path)) {
|
||||
return $path;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$dirs = array_merge(
|
||||
explode(\PATH_SEPARATOR, getenv('PATH') ?: getenv('Path')),
|
||||
$extraDirs
|
||||
);
|
||||
}
|
||||
|
||||
$suffixes = [''];
|
||||
if ('\\' === \DIRECTORY_SEPARATOR) {
|
||||
$pathExt = getenv('PATHEXT');
|
||||
$suffixes = array_merge($pathExt ? explode(\PATH_SEPARATOR, $pathExt) : $this->suffixes, $suffixes);
|
||||
}
|
||||
foreach ($suffixes as $suffix) {
|
||||
foreach ($dirs as $dir) {
|
||||
if (@is_file($file = $dir.\DIRECTORY_SEPARATOR.$name.$suffix) && ('\\' === \DIRECTORY_SEPARATOR || @is_executable($file))) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $default;
|
||||
}
|
||||
}
|
96
vendor/symfony/process/InputStream.php
vendored
Normal file
96
vendor/symfony/process/InputStream.php
vendored
Normal file
|
@ -0,0 +1,96 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Process;
|
||||
|
||||
use Symfony\Component\Process\Exception\RuntimeException;
|
||||
|
||||
/**
|
||||
* Provides a way to continuously write to the input of a Process until the InputStream is closed.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*
|
||||
* @implements \IteratorAggregate<int, string>
|
||||
*/
|
||||
class InputStream implements \IteratorAggregate
|
||||
{
|
||||
/** @var callable|null */
|
||||
private $onEmpty = null;
|
||||
private $input = [];
|
||||
private $open = true;
|
||||
|
||||
/**
|
||||
* Sets a callback that is called when the write buffer becomes empty.
|
||||
*/
|
||||
public function onEmpty(callable $onEmpty = null)
|
||||
{
|
||||
$this->onEmpty = $onEmpty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends an input to the write buffer.
|
||||
*
|
||||
* @param resource|string|int|float|bool|\Traversable|null $input The input to append as scalar,
|
||||
* stream resource or \Traversable
|
||||
*/
|
||||
public function write($input)
|
||||
{
|
||||
if (null === $input) {
|
||||
return;
|
||||
}
|
||||
if ($this->isClosed()) {
|
||||
throw new RuntimeException(sprintf('"%s" is closed.', static::class));
|
||||
}
|
||||
$this->input[] = ProcessUtils::validateInput(__METHOD__, $input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the write buffer.
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
$this->open = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether the write buffer is closed or not.
|
||||
*/
|
||||
public function isClosed()
|
||||
{
|
||||
return !$this->open;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Traversable<int, string>
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function getIterator()
|
||||
{
|
||||
$this->open = true;
|
||||
|
||||
while ($this->open || $this->input) {
|
||||
if (!$this->input) {
|
||||
yield '';
|
||||
continue;
|
||||
}
|
||||
$current = array_shift($this->input);
|
||||
|
||||
if ($current instanceof \Iterator) {
|
||||
yield from $current;
|
||||
} else {
|
||||
yield $current;
|
||||
}
|
||||
if (!$this->input && $this->open && null !== $onEmpty = $this->onEmpty) {
|
||||
$this->write($onEmpty($this));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
19
vendor/symfony/process/LICENSE
vendored
Normal file
19
vendor/symfony/process/LICENSE
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
Copyright (c) 2004-2022 Fabien Potencier
|
||||
|
||||
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.
|
99
vendor/symfony/process/PhpExecutableFinder.php
vendored
Normal file
99
vendor/symfony/process/PhpExecutableFinder.php
vendored
Normal file
|
@ -0,0 +1,99 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Process;
|
||||
|
||||
/**
|
||||
* An executable finder specifically designed for the PHP executable.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class PhpExecutableFinder
|
||||
{
|
||||
private $executableFinder;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->executableFinder = new ExecutableFinder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds The PHP executable.
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
public function find(bool $includeArgs = true)
|
||||
{
|
||||
if ($php = getenv('PHP_BINARY')) {
|
||||
if (!is_executable($php)) {
|
||||
$command = '\\' === \DIRECTORY_SEPARATOR ? 'where' : 'command -v';
|
||||
if ($php = strtok(exec($command.' '.escapeshellarg($php)), \PHP_EOL)) {
|
||||
if (!is_executable($php)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return $php;
|
||||
}
|
||||
|
||||
$args = $this->findArguments();
|
||||
$args = $includeArgs && $args ? ' '.implode(' ', $args) : '';
|
||||
|
||||
// PHP_BINARY return the current sapi executable
|
||||
if (\PHP_BINARY && \in_array(\PHP_SAPI, ['cgi-fcgi', 'cli', 'cli-server', 'phpdbg'], true)) {
|
||||
return \PHP_BINARY.$args;
|
||||
}
|
||||
|
||||
if ($php = getenv('PHP_PATH')) {
|
||||
if (!@is_executable($php)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $php;
|
||||
}
|
||||
|
||||
if ($php = getenv('PHP_PEAR_PHP_BIN')) {
|
||||
if (@is_executable($php)) {
|
||||
return $php;
|
||||
}
|
||||
}
|
||||
|
||||
if (@is_executable($php = \PHP_BINDIR.('\\' === \DIRECTORY_SEPARATOR ? '\\php.exe' : '/php'))) {
|
||||
return $php;
|
||||
}
|
||||
|
||||
$dirs = [\PHP_BINDIR];
|
||||
if ('\\' === \DIRECTORY_SEPARATOR) {
|
||||
$dirs[] = 'C:\xampp\php\\';
|
||||
}
|
||||
|
||||
return $this->executableFinder->find('php', false, $dirs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the PHP executable arguments.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function findArguments()
|
||||
{
|
||||
$arguments = [];
|
||||
if ('phpdbg' === \PHP_SAPI) {
|
||||
$arguments[] = '-qrr';
|
||||
}
|
||||
|
||||
return $arguments;
|
||||
}
|
||||
}
|
72
vendor/symfony/process/PhpProcess.php
vendored
Normal file
72
vendor/symfony/process/PhpProcess.php
vendored
Normal file
|
@ -0,0 +1,72 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Process;
|
||||
|
||||
use Symfony\Component\Process\Exception\LogicException;
|
||||
use Symfony\Component\Process\Exception\RuntimeException;
|
||||
|
||||
/**
|
||||
* PhpProcess runs a PHP script in an independent process.
|
||||
*
|
||||
* $p = new PhpProcess('<?php echo "foo"; ?>');
|
||||
* $p->run();
|
||||
* print $p->getOutput()."\n";
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class PhpProcess extends Process
|
||||
{
|
||||
/**
|
||||
* @param string $script The PHP script to run (as a string)
|
||||
* @param string|null $cwd The working directory or null to use the working dir of the current PHP process
|
||||
* @param array|null $env The environment variables or null to use the same environment as the current PHP process
|
||||
* @param int $timeout The timeout in seconds
|
||||
* @param array|null $php Path to the PHP binary to use with any additional arguments
|
||||
*/
|
||||
public function __construct(string $script, string $cwd = null, array $env = null, int $timeout = 60, array $php = null)
|
||||
{
|
||||
if (null === $php) {
|
||||
$executableFinder = new PhpExecutableFinder();
|
||||
$php = $executableFinder->find(false);
|
||||
$php = false === $php ? null : array_merge([$php], $executableFinder->findArguments());
|
||||
}
|
||||
if ('phpdbg' === \PHP_SAPI) {
|
||||
$file = tempnam(sys_get_temp_dir(), 'dbg');
|
||||
file_put_contents($file, $script);
|
||||
register_shutdown_function('unlink', $file);
|
||||
$php[] = $file;
|
||||
$script = null;
|
||||
}
|
||||
|
||||
parent::__construct($php, $cwd, $env, $script, $timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function fromShellCommandline(string $command, string $cwd = null, array $env = null, $input = null, ?float $timeout = 60)
|
||||
{
|
||||
throw new LogicException(sprintf('The "%s()" method cannot be called when using "%s".', __METHOD__, self::class));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function start(callable $callback = null, array $env = [])
|
||||
{
|
||||
if (null === $this->getCommandLine()) {
|
||||
throw new RuntimeException('Unable to find the PHP executable.');
|
||||
}
|
||||
|
||||
parent::start($callback, $env);
|
||||
}
|
||||
}
|
180
vendor/symfony/process/Pipes/AbstractPipes.php
vendored
Normal file
180
vendor/symfony/process/Pipes/AbstractPipes.php
vendored
Normal file
|
@ -0,0 +1,180 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Process\Pipes;
|
||||
|
||||
use Symfony\Component\Process\Exception\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* @author Romain Neutron <imprec@gmail.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
abstract class AbstractPipes implements PipesInterface
|
||||
{
|
||||
public $pipes = [];
|
||||
|
||||
private $inputBuffer = '';
|
||||
private $input;
|
||||
private $blocked = true;
|
||||
private $lastError;
|
||||
|
||||
/**
|
||||
* @param resource|string|int|float|bool|\Iterator|null $input
|
||||
*/
|
||||
public function __construct($input)
|
||||
{
|
||||
if (\is_resource($input) || $input instanceof \Iterator) {
|
||||
$this->input = $input;
|
||||
} elseif (\is_string($input)) {
|
||||
$this->inputBuffer = $input;
|
||||
} else {
|
||||
$this->inputBuffer = (string) $input;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
foreach ($this->pipes as $pipe) {
|
||||
if (\is_resource($pipe)) {
|
||||
fclose($pipe);
|
||||
}
|
||||
}
|
||||
$this->pipes = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a system call has been interrupted.
|
||||
*/
|
||||
protected function hasSystemCallBeenInterrupted(): bool
|
||||
{
|
||||
$lastError = $this->lastError;
|
||||
$this->lastError = null;
|
||||
|
||||
// stream_select returns false when the `select` system call is interrupted by an incoming signal
|
||||
return null !== $lastError && false !== stripos($lastError, 'interrupted system call');
|
||||
}
|
||||
|
||||
/**
|
||||
* Unblocks streams.
|
||||
*/
|
||||
protected function unblock()
|
||||
{
|
||||
if (!$this->blocked) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($this->pipes as $pipe) {
|
||||
stream_set_blocking($pipe, 0);
|
||||
}
|
||||
if (\is_resource($this->input)) {
|
||||
stream_set_blocking($this->input, 0);
|
||||
}
|
||||
|
||||
$this->blocked = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes input to stdin.
|
||||
*
|
||||
* @throws InvalidArgumentException When an input iterator yields a non supported value
|
||||
*/
|
||||
protected function write(): ?array
|
||||
{
|
||||
if (!isset($this->pipes[0])) {
|
||||
return null;
|
||||
}
|
||||
$input = $this->input;
|
||||
|
||||
if ($input instanceof \Iterator) {
|
||||
if (!$input->valid()) {
|
||||
$input = null;
|
||||
} elseif (\is_resource($input = $input->current())) {
|
||||
stream_set_blocking($input, 0);
|
||||
} elseif (!isset($this->inputBuffer[0])) {
|
||||
if (!\is_string($input)) {
|
||||
if (!is_scalar($input)) {
|
||||
throw new InvalidArgumentException(sprintf('"%s" yielded a value of type "%s", but only scalars and stream resources are supported.', get_debug_type($this->input), get_debug_type($input)));
|
||||
}
|
||||
$input = (string) $input;
|
||||
}
|
||||
$this->inputBuffer = $input;
|
||||
$this->input->next();
|
||||
$input = null;
|
||||
} else {
|
||||
$input = null;
|
||||
}
|
||||
}
|
||||
|
||||
$r = $e = [];
|
||||
$w = [$this->pipes[0]];
|
||||
|
||||
// let's have a look if something changed in streams
|
||||
if (false === @stream_select($r, $w, $e, 0, 0)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
foreach ($w as $stdin) {
|
||||
if (isset($this->inputBuffer[0])) {
|
||||
$written = fwrite($stdin, $this->inputBuffer);
|
||||
$this->inputBuffer = substr($this->inputBuffer, $written);
|
||||
if (isset($this->inputBuffer[0])) {
|
||||
return [$this->pipes[0]];
|
||||
}
|
||||
}
|
||||
|
||||
if ($input) {
|
||||
while (true) {
|
||||
$data = fread($input, self::CHUNK_SIZE);
|
||||
if (!isset($data[0])) {
|
||||
break;
|
||||
}
|
||||
$written = fwrite($stdin, $data);
|
||||
$data = substr($data, $written);
|
||||
if (isset($data[0])) {
|
||||
$this->inputBuffer = $data;
|
||||
|
||||
return [$this->pipes[0]];
|
||||
}
|
||||
}
|
||||
if (feof($input)) {
|
||||
if ($this->input instanceof \Iterator) {
|
||||
$this->input->next();
|
||||
} else {
|
||||
$this->input = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no input to read on resource, buffer is empty
|
||||
if (!isset($this->inputBuffer[0]) && !($this->input instanceof \Iterator ? $this->input->valid() : $this->input)) {
|
||||
$this->input = null;
|
||||
fclose($this->pipes[0]);
|
||||
unset($this->pipes[0]);
|
||||
} elseif (!$w) {
|
||||
return [$this->pipes[0]];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function handleError(int $type, string $msg)
|
||||
{
|
||||
$this->lastError = $msg;
|
||||
}
|
||||
}
|
61
vendor/symfony/process/Pipes/PipesInterface.php
vendored
Normal file
61
vendor/symfony/process/Pipes/PipesInterface.php
vendored
Normal file
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Process\Pipes;
|
||||
|
||||
/**
|
||||
* PipesInterface manages descriptors and pipes for the use of proc_open.
|
||||
*
|
||||
* @author Romain Neutron <imprec@gmail.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
interface PipesInterface
|
||||
{
|
||||
public const CHUNK_SIZE = 16384;
|
||||
|
||||
/**
|
||||
* Returns an array of descriptors for the use of proc_open.
|
||||
*/
|
||||
public function getDescriptors(): array;
|
||||
|
||||
/**
|
||||
* Returns an array of filenames indexed by their related stream in case these pipes use temporary files.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function getFiles(): array;
|
||||
|
||||
/**
|
||||
* Reads data in file handles and pipes.
|
||||
*
|
||||
* @param bool $blocking Whether to use blocking calls or not
|
||||
* @param bool $close Whether to close pipes if they've reached EOF
|
||||
*
|
||||
* @return string[] An array of read data indexed by their fd
|
||||
*/
|
||||
public function readAndWrite(bool $blocking, bool $close = false): array;
|
||||
|
||||
/**
|
||||
* Returns if the current state has open file handles or pipes.
|
||||
*/
|
||||
public function areOpen(): bool;
|
||||
|
||||
/**
|
||||
* Returns if pipes are able to read output.
|
||||
*/
|
||||
public function haveReadSupport(): bool;
|
||||
|
||||
/**
|
||||
* Closes file handles and pipes.
|
||||
*/
|
||||
public function close();
|
||||
}
|
163
vendor/symfony/process/Pipes/UnixPipes.php
vendored
Normal file
163
vendor/symfony/process/Pipes/UnixPipes.php
vendored
Normal file
|
@ -0,0 +1,163 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Process\Pipes;
|
||||
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
/**
|
||||
* UnixPipes implementation uses unix pipes as handles.
|
||||
*
|
||||
* @author Romain Neutron <imprec@gmail.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class UnixPipes extends AbstractPipes
|
||||
{
|
||||
private $ttyMode;
|
||||
private $ptyMode;
|
||||
private $haveReadSupport;
|
||||
|
||||
public function __construct(?bool $ttyMode, bool $ptyMode, $input, bool $haveReadSupport)
|
||||
{
|
||||
$this->ttyMode = $ttyMode;
|
||||
$this->ptyMode = $ptyMode;
|
||||
$this->haveReadSupport = $haveReadSupport;
|
||||
|
||||
parent::__construct($input);
|
||||
}
|
||||
|
||||
public function __sleep(): array
|
||||
{
|
||||
throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
|
||||
}
|
||||
|
||||
public function __wakeup()
|
||||
{
|
||||
throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
$this->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDescriptors(): array
|
||||
{
|
||||
if (!$this->haveReadSupport) {
|
||||
$nullstream = fopen('/dev/null', 'c');
|
||||
|
||||
return [
|
||||
['pipe', 'r'],
|
||||
$nullstream,
|
||||
$nullstream,
|
||||
];
|
||||
}
|
||||
|
||||
if ($this->ttyMode) {
|
||||
return [
|
||||
['file', '/dev/tty', 'r'],
|
||||
['file', '/dev/tty', 'w'],
|
||||
['file', '/dev/tty', 'w'],
|
||||
];
|
||||
}
|
||||
|
||||
if ($this->ptyMode && Process::isPtySupported()) {
|
||||
return [
|
||||
['pty'],
|
||||
['pty'],
|
||||
['pty'],
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
['pipe', 'r'],
|
||||
['pipe', 'w'], // stdout
|
||||
['pipe', 'w'], // stderr
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFiles(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function readAndWrite(bool $blocking, bool $close = false): array
|
||||
{
|
||||
$this->unblock();
|
||||
$w = $this->write();
|
||||
|
||||
$read = $e = [];
|
||||
$r = $this->pipes;
|
||||
unset($r[0]);
|
||||
|
||||
// let's have a look if something changed in streams
|
||||
set_error_handler([$this, 'handleError']);
|
||||
if (($r || $w) && false === stream_select($r, $w, $e, 0, $blocking ? Process::TIMEOUT_PRECISION * 1E6 : 0)) {
|
||||
restore_error_handler();
|
||||
// if a system call has been interrupted, forget about it, let's try again
|
||||
// otherwise, an error occurred, let's reset pipes
|
||||
if (!$this->hasSystemCallBeenInterrupted()) {
|
||||
$this->pipes = [];
|
||||
}
|
||||
|
||||
return $read;
|
||||
}
|
||||
restore_error_handler();
|
||||
|
||||
foreach ($r as $pipe) {
|
||||
// prior PHP 5.4 the array passed to stream_select is modified and
|
||||
// lose key association, we have to find back the key
|
||||
$read[$type = array_search($pipe, $this->pipes, true)] = '';
|
||||
|
||||
do {
|
||||
$data = @fread($pipe, self::CHUNK_SIZE);
|
||||
$read[$type] .= $data;
|
||||
} while (isset($data[0]) && ($close || isset($data[self::CHUNK_SIZE - 1])));
|
||||
|
||||
if (!isset($read[$type][0])) {
|
||||
unset($read[$type]);
|
||||
}
|
||||
|
||||
if ($close && feof($pipe)) {
|
||||
fclose($pipe);
|
||||
unset($this->pipes[$type]);
|
||||
}
|
||||
}
|
||||
|
||||
return $read;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function haveReadSupport(): bool
|
||||
{
|
||||
return $this->haveReadSupport;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function areOpen(): bool
|
||||
{
|
||||
return (bool) $this->pipes;
|
||||
}
|
||||
}
|
204
vendor/symfony/process/Pipes/WindowsPipes.php
vendored
Normal file
204
vendor/symfony/process/Pipes/WindowsPipes.php
vendored
Normal file
|
@ -0,0 +1,204 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Process\Pipes;
|
||||
|
||||
use Symfony\Component\Process\Exception\RuntimeException;
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
/**
|
||||
* WindowsPipes implementation uses temporary files as handles.
|
||||
*
|
||||
* @see https://bugs.php.net/51800
|
||||
* @see https://bugs.php.net/65650
|
||||
*
|
||||
* @author Romain Neutron <imprec@gmail.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class WindowsPipes extends AbstractPipes
|
||||
{
|
||||
private $files = [];
|
||||
private $fileHandles = [];
|
||||
private $lockHandles = [];
|
||||
private $readBytes = [
|
||||
Process::STDOUT => 0,
|
||||
Process::STDERR => 0,
|
||||
];
|
||||
private $haveReadSupport;
|
||||
|
||||
public function __construct($input, bool $haveReadSupport)
|
||||
{
|
||||
$this->haveReadSupport = $haveReadSupport;
|
||||
|
||||
if ($this->haveReadSupport) {
|
||||
// Fix for PHP bug #51800: reading from STDOUT pipe hangs forever on Windows if the output is too big.
|
||||
// Workaround for this problem is to use temporary files instead of pipes on Windows platform.
|
||||
//
|
||||
// @see https://bugs.php.net/51800
|
||||
$pipes = [
|
||||
Process::STDOUT => Process::OUT,
|
||||
Process::STDERR => Process::ERR,
|
||||
];
|
||||
$tmpDir = sys_get_temp_dir();
|
||||
$lastError = 'unknown reason';
|
||||
set_error_handler(function ($type, $msg) use (&$lastError) { $lastError = $msg; });
|
||||
for ($i = 0;; ++$i) {
|
||||
foreach ($pipes as $pipe => $name) {
|
||||
$file = sprintf('%s\\sf_proc_%02X.%s', $tmpDir, $i, $name);
|
||||
|
||||
if (!$h = fopen($file.'.lock', 'w')) {
|
||||
if (file_exists($file.'.lock')) {
|
||||
continue 2;
|
||||
}
|
||||
restore_error_handler();
|
||||
throw new RuntimeException('A temporary file could not be opened to write the process output: '.$lastError);
|
||||
}
|
||||
if (!flock($h, \LOCK_EX | \LOCK_NB)) {
|
||||
continue 2;
|
||||
}
|
||||
if (isset($this->lockHandles[$pipe])) {
|
||||
flock($this->lockHandles[$pipe], \LOCK_UN);
|
||||
fclose($this->lockHandles[$pipe]);
|
||||
}
|
||||
$this->lockHandles[$pipe] = $h;
|
||||
|
||||
if (!($h = fopen($file, 'w')) || !fclose($h) || !$h = fopen($file, 'r')) {
|
||||
flock($this->lockHandles[$pipe], \LOCK_UN);
|
||||
fclose($this->lockHandles[$pipe]);
|
||||
unset($this->lockHandles[$pipe]);
|
||||
continue 2;
|
||||
}
|
||||
$this->fileHandles[$pipe] = $h;
|
||||
$this->files[$pipe] = $file;
|
||||
}
|
||||
break;
|
||||
}
|
||||
restore_error_handler();
|
||||
}
|
||||
|
||||
parent::__construct($input);
|
||||
}
|
||||
|
||||
public function __sleep(): array
|
||||
{
|
||||
throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
|
||||
}
|
||||
|
||||
public function __wakeup()
|
||||
{
|
||||
throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
$this->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDescriptors(): array
|
||||
{
|
||||
if (!$this->haveReadSupport) {
|
||||
$nullstream = fopen('NUL', 'c');
|
||||
|
||||
return [
|
||||
['pipe', 'r'],
|
||||
$nullstream,
|
||||
$nullstream,
|
||||
];
|
||||
}
|
||||
|
||||
// We're not using pipe on Windows platform as it hangs (https://bugs.php.net/51800)
|
||||
// We're not using file handles as it can produce corrupted output https://bugs.php.net/65650
|
||||
// So we redirect output within the commandline and pass the nul device to the process
|
||||
return [
|
||||
['pipe', 'r'],
|
||||
['file', 'NUL', 'w'],
|
||||
['file', 'NUL', 'w'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFiles(): array
|
||||
{
|
||||
return $this->files;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function readAndWrite(bool $blocking, bool $close = false): array
|
||||
{
|
||||
$this->unblock();
|
||||
$w = $this->write();
|
||||
$read = $r = $e = [];
|
||||
|
||||
if ($blocking) {
|
||||
if ($w) {
|
||||
@stream_select($r, $w, $e, 0, Process::TIMEOUT_PRECISION * 1E6);
|
||||
} elseif ($this->fileHandles) {
|
||||
usleep(Process::TIMEOUT_PRECISION * 1E6);
|
||||
}
|
||||
}
|
||||
foreach ($this->fileHandles as $type => $fileHandle) {
|
||||
$data = stream_get_contents($fileHandle, -1, $this->readBytes[$type]);
|
||||
|
||||
if (isset($data[0])) {
|
||||
$this->readBytes[$type] += \strlen($data);
|
||||
$read[$type] = $data;
|
||||
}
|
||||
if ($close) {
|
||||
ftruncate($fileHandle, 0);
|
||||
fclose($fileHandle);
|
||||
flock($this->lockHandles[$type], \LOCK_UN);
|
||||
fclose($this->lockHandles[$type]);
|
||||
unset($this->fileHandles[$type], $this->lockHandles[$type]);
|
||||
}
|
||||
}
|
||||
|
||||
return $read;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function haveReadSupport(): bool
|
||||
{
|
||||
return $this->haveReadSupport;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function areOpen(): bool
|
||||
{
|
||||
return $this->pipes && $this->fileHandles;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
parent::close();
|
||||
foreach ($this->fileHandles as $type => $handle) {
|
||||
ftruncate($handle, 0);
|
||||
fclose($handle);
|
||||
flock($this->lockHandles[$type], \LOCK_UN);
|
||||
fclose($this->lockHandles[$type]);
|
||||
}
|
||||
$this->fileHandles = $this->lockHandles = [];
|
||||
}
|
||||
}
|
1652
vendor/symfony/process/Process.php
vendored
Normal file
1652
vendor/symfony/process/Process.php
vendored
Normal file
File diff suppressed because it is too large
Load diff
69
vendor/symfony/process/ProcessUtils.php
vendored
Normal file
69
vendor/symfony/process/ProcessUtils.php
vendored
Normal file
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Process;
|
||||
|
||||
use Symfony\Component\Process\Exception\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* ProcessUtils is a bunch of utility methods.
|
||||
*
|
||||
* This class contains static methods only and is not meant to be instantiated.
|
||||
*
|
||||
* @author Martin Hasoň <martin.hason@gmail.com>
|
||||
*/
|
||||
class ProcessUtils
|
||||
{
|
||||
/**
|
||||
* This class should not be instantiated.
|
||||
*/
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates and normalizes a Process input.
|
||||
*
|
||||
* @param string $caller The name of method call that validates the input
|
||||
* @param mixed $input The input to validate
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws InvalidArgumentException In case the input is not valid
|
||||
*/
|
||||
public static function validateInput(string $caller, $input)
|
||||
{
|
||||
if (null !== $input) {
|
||||
if (\is_resource($input)) {
|
||||
return $input;
|
||||
}
|
||||
if (\is_string($input)) {
|
||||
return $input;
|
||||
}
|
||||
if (is_scalar($input)) {
|
||||
return (string) $input;
|
||||
}
|
||||
if ($input instanceof Process) {
|
||||
return $input->getIterator($input::ITER_SKIP_ERR);
|
||||
}
|
||||
if ($input instanceof \Iterator) {
|
||||
return $input;
|
||||
}
|
||||
if ($input instanceof \Traversable) {
|
||||
return new \IteratorIterator($input);
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException(sprintf('"%s" only accepts strings, Traversable objects or stream resources.', $caller));
|
||||
}
|
||||
|
||||
return $input;
|
||||
}
|
||||
}
|
28
vendor/symfony/process/README.md
vendored
Normal file
28
vendor/symfony/process/README.md
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
Process Component
|
||||
=================
|
||||
|
||||
The Process component executes commands in sub-processes.
|
||||
|
||||
Sponsor
|
||||
-------
|
||||
|
||||
The Process component for Symfony 5.4/6.0 is [backed][1] by [SensioLabs][2].
|
||||
|
||||
As the creator of Symfony, SensioLabs supports companies using Symfony, with an
|
||||
offering encompassing consultancy, expertise, services, training, and technical
|
||||
assistance to ensure the success of web application development projects.
|
||||
|
||||
Help Symfony by [sponsoring][3] its development!
|
||||
|
||||
Resources
|
||||
---------
|
||||
|
||||
* [Documentation](https://symfony.com/doc/current/components/process.html)
|
||||
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
|
||||
* [Report issues](https://github.com/symfony/symfony/issues) and
|
||||
[send Pull Requests](https://github.com/symfony/symfony/pulls)
|
||||
in the [main Symfony repository](https://github.com/symfony/symfony)
|
||||
|
||||
[1]: https://symfony.com/backers
|
||||
[2]: https://sensiolabs.com
|
||||
[3]: https://symfony.com/sponsor
|
29
vendor/symfony/process/composer.json
vendored
Normal file
29
vendor/symfony/process/composer.json
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"name": "symfony/process",
|
||||
"type": "library",
|
||||
"description": "Executes commands in sub-processes",
|
||||
"keywords": [],
|
||||
"homepage": "https://symfony.com",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=7.2.5",
|
||||
"symfony/polyfill-php80": "^1.16"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": { "Symfony\\Component\\Process\\": "" },
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"minimum-stability": "dev"
|
||||
}
|
Loading…
Reference in a new issue