Subiendo proyecto completo sin restricciones de git ignore

This commit is contained in:
Jose Sanchez
2023-08-17 11:44:02 -04:00
parent a0d4f5ba3b
commit 20f1c60600
19921 changed files with 2509159 additions and 45 deletions

21
vendor/spatie/db-dumper/LICENSE.md vendored Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) Spatie bvba <info@spatie.be>
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.

323
vendor/spatie/db-dumper/README.md vendored Normal file
View File

@@ -0,0 +1,323 @@
# Dump the contents of a database
[![Latest Version on Packagist](https://img.shields.io/packagist/v/spatie/db-dumper.svg?style=flat-square)](https://packagist.org/packages/spatie/db-dumper)
![run-tests](https://github.com/spatie/db-dumper/workflows/run-tests/badge.svg)
[![MIT Licensed](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md)
[![Total Downloads](https://img.shields.io/packagist/dt/spatie/db-dumper.svg?style=flat-square)](https://packagist.org/packages/spatie/db-dumper)
This repo contains an easy to use class to dump a database using PHP. Currently MySQL, PostgreSQL, SQLite and MongoDB are supported. Behind the scenes `mysqldump`, `pg_dump`, `sqlite3` and `mongodump` are used.
Here are simple examples of how to create a database dump with different drivers:
**MySQL**
```php
Spatie\DbDumper\Databases\MySql::create()
->setDbName($databaseName)
->setUserName($userName)
->setPassword($password)
->dumpToFile('dump.sql');
```
**PostgreSQL**
```php
Spatie\DbDumper\Databases\PostgreSql::create()
->setDbName($databaseName)
->setUserName($userName)
->setPassword($password)
->dumpToFile('dump.sql');
```
**SQLite**
```php
Spatie\DbDumper\Databases\Sqlite::create()
->setDbName($pathToDatabaseFile)
->dumpToFile('dump.sql');
```
⚠️ Sqlite version 3.32.0 is required when using the `includeTables` option.
**MongoDB**
```php
Spatie\DbDumper\Databases\MongoDb::create()
->setDbName($databaseName)
->setUserName($userName)
->setPassword($password)
->dumpToFile('dump.gz');
```
## Support us
[<img src="https://github-ads.s3.eu-central-1.amazonaws.com/db-dumper.jpg?t=1" width="419px" />](https://spatie.be/github-ad-click/db-dumper)
We invest a lot of resources into creating [best in class open source packages](https://spatie.be/open-source). You can support us by [buying one of our paid products](https://spatie.be/open-source/support-us).
We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on [our contact page](https://spatie.be/about-us). We publish all received postcards on [our virtual postcard wall](https://spatie.be/open-source/postcards).
## Requirements
For dumping MySQL-db's `mysqldump` should be installed.
For dumping PostgreSQL-db's `pg_dump` should be installed.
For dumping SQLite-db's `sqlite3` should be installed.
For dumping MongoDB-db's `mongodump` should be installed.
For compressing dump files, `gzip` and/or `bzip2` should be installed.
## Installation
You can install the package via composer:
``` bash
composer require spatie/db-dumper
```
## Usage
This is the simplest way to create a dump of a MySql db:
```php
Spatie\DbDumper\Databases\MySql::create()
->setDbName($databaseName)
->setUserName($userName)
->setPassword($password)
->dumpToFile('dump.sql');
```
If you're working with PostgreSQL just use that dumper, most methods are available on both the MySql. and PostgreSql-dumper.
```php
Spatie\DbDumper\Databases\PostgreSql::create()
->setDbName($databaseName)
->setUserName($userName)
->setPassword($password)
->dumpToFile('dump.sql');
```
If the `mysqldump` (or `pg_dump`) binary is installed in a non default location you can let the package know by using the`setDumpBinaryPath()`-function:
```php
Spatie\DbDumper\Databases\MySql::create()
->setDumpBinaryPath('/custom/location')
->setDbName($databaseName)
->setUserName($userName)
->setPassword($password)
->dumpToFile('dump.sql');
```
If your application is deployed and you need to change the host (default is 127.0.0.1), you can add the `setHost()`-function:
```php
Spatie\DbDumper\Databases\MySql::create()
->setDbName($databaseName)
->setUserName($userName)
->setPassword($password)
->setHost($host)
->dumpToFile('dump.sql');
```
### Use a Database URL
In some applications or environments, database credentials are provided as URLs instead of individual components. In this case, you can use the `setDatabaseUrl` method instead of the individual methods.
```php
Spatie\DbDumper\Databases\MySql::create()
->setDatabaseUrl($databaseUrl)
->dumpToFile('dump.sql');
```
When providing a URL, the package will automatically parse it and provide the individual components to the applicable dumper.
For example, if you provide the URL `mysql://username:password@hostname:3306/dbname`, the dumper will use the `hostname` host, running on port `3306`, and will connect to `dbname` with `username` and `password`.
### Dump specific tables
Using an array:
```php
Spatie\DbDumper\Databases\MySql::create()
->setDbName($databaseName)
->setUserName($userName)
->setPassword($password)
->includeTables(['table1', 'table2', 'table3'])
->dumpToFile('dump.sql');
```
Using a string:
```php
Spatie\DbDumper\Databases\MySql::create()
->setDbName($databaseName)
->setUserName($userName)
->setPassword($password)
->includeTables('table1, table2, table3')
->dumpToFile('dump.sql');
```
### Don't use column_statics table with some old version of MySql service.
In order to use "_--column-statistics=0_" as option in mysqldump command you can use _doNotUseColumnStatistics()_ method.
If you have installed _mysqldump 8_, it queries by default _column_statics_ table in _information_schema_ database.
In some old version of MySql (service) like 5.7, this table doesn't exist. So you could have an exception during the execution of mysqldump. To avoid this, you could use _doNotUseColumnStatistics()_ method.
```php
Spatie\DbDumper\Databases\MySql::create()
->setDbName($databaseName)
->setUserName($userName)
->setPassword($password)
->doNotUseColumnStatistics()
->dumpToFile('dump.sql');
```
### Excluding tables from the dump
Using an array:
```php
Spatie\DbDumper\Databases\MySql::create()
->setDbName($databaseName)
->setUserName($userName)
->setPassword($password)
->excludeTables(['table1', 'table2', 'table3'])
->dumpToFile('dump.sql');
```
Using a string:
```php
Spatie\DbDumper\Databases\MySql::create()
->setDbName($databaseName)
->setUserName($userName)
->setPassword($password)
->excludeTables('table1, table2, table3')
->dumpToFile('dump.sql');
```
### Do not write CREATE TABLE statements that create each dumped table.
```php
$dumpCommand = MySql::create()
->setDbName('dbname')
->setUserName('username')
->setPassword('password')
->doNotCreateTables()
->getDumpCommand('dump.sql', 'credentials.txt');
```
### Adding extra options
If you want to add an arbitrary option to the dump command you can use `addExtraOption`
```php
$dumpCommand = MySql::create()
->setDbName('dbname')
->setUserName('username')
->setPassword('password')
->addExtraOption('--xml')
->getDumpCommand('dump.sql', 'credentials.txt');
```
If you're working with MySql you can set the database name using `--databases` as an extra option. This is particularly useful when used in conjunction with the `--add-drop-database` `mysqldump` option (see the [mysqldump docs](https://dev.mysql.com/doc/refman/5.7/en/mysqldump.html#option_mysqldump_add-drop-database)).
```php
$dumpCommand = MySql::create()
->setUserName('username')
->setPassword('password')
->addExtraOption('--databases dbname')
->addExtraOption('--add-drop-database')
->getDumpCommand('dump.sql', 'credentials.txt');
```
With MySql, you also have the option to use the `--all-databases` extra option. This is useful when you want to run a full backup of all the databases in the specified MySQL connection.
```php
$dumpCommand = MySql::create()
->setUserName('username')
->setPassword('password')
->addExtraOption('--all-databases')
->getDumpCommand('dump.sql', 'credentials.txt');
```
Please note that using the `->addExtraOption('--databases dbname')` or `->addExtraOption('--all-databases')` will override the database name set on a previous `->setDbName()` call.
### Using compression
If you want the output file to be compressed, you can use a compressor class.
There are two compressors that come out of the box:
- `GzipCompressor` - This will compress your db dump with `gzip`. Make sure `gzip` is installed on your system before using this.
- `Bzip2Compressor` - This will compress your db dump with `bzip2`. Make sure `bzip2` is installed on your system before using this.
```php
$dumpCommand = MySql::create()
->setDbName('dbname')
->setUserName('username')
->setPassword('password')
->useCompressor(new GzipCompressor()) // or `new Bzip2Compressor()`
->dumpToFile('dump.sql.gz');
```
### Creating your own compressor
You can create you own compressor implementing the `Compressor` interface. Here's how that interface looks like:
```php
namespace Spatie\DbDumper\Compressors;
interface Compressor
{
public function useCommand(): string;
public function useExtension(): string;
}
```
The `useCommand` should simply return the compression command the db dump will get pumped to. Here's the implementation of `GzipCompression`.
```php
namespace Spatie\DbDumper\Compressors;
class GzipCompressor implements Compressor
{
public function useCommand(): string
{
return 'gzip';
}
public function useExtension(): string
{
return 'gz';
}
}
```
## Testing
``` bash
$ composer test
```
## Changelog
Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.
## Contributing
Please see [CONTRIBUTING](https://github.com/spatie/.github/blob/main/CONTRIBUTING.md) for details.
## Security Vulnerabilities
Please review [our security policy](../../security/policy) on how to report security vulnerabilities.
## Credits
- [Freek Van der Herten](https://github.com/freekmurze)
- [All Contributors](../../contributors)
Initial PostgreSQL support was contributed by [Adriano Machado](https://github.com/ammachado). SQlite support was contributed by [Peter Matseykanets](https://twitter.com/pmatseykanets).
## License
The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

46
vendor/spatie/db-dumper/composer.json vendored Normal file
View File

@@ -0,0 +1,46 @@
{
"name": "spatie/db-dumper",
"description": "Dump databases",
"keywords": [
"spatie",
"dump",
"database",
"mysqldump",
"db-dumper"
],
"homepage": "https://github.com/spatie/db-dumper",
"license": "MIT",
"authors": [
{
"name": "Freek Van der Herten",
"email": "freek@spatie.be",
"homepage": "https://spatie.be",
"role": "Developer"
}
],
"require": {
"php": "^8.0",
"symfony/process": "^5.0|^6.0"
},
"require-dev": {
"pestphp/pest": "^1.22"
},
"autoload": {
"psr-4": {
"Spatie\\DbDumper\\": "src"
}
},
"autoload-dev": {
"psr-4": {
"Spatie\\DbDumper\\Test\\": "tests"
}
},
"scripts": {
"test": "vendor/bin/pest"
},
"config": {
"allow-plugins": {
"pestphp/pest-plugin": true
}
}
}

View File

@@ -0,0 +1,16 @@
<?php
namespace Spatie\DbDumper\Compressors;
class Bzip2Compressor implements Compressor
{
public function useCommand(): string
{
return 'bzip2';
}
public function useExtension(): string
{
return 'bz2';
}
}

View File

@@ -0,0 +1,10 @@
<?php
namespace Spatie\DbDumper\Compressors;
interface Compressor
{
public function useCommand(): string;
public function useExtension(): string;
}

View File

@@ -0,0 +1,16 @@
<?php
namespace Spatie\DbDumper\Compressors;
class GzipCompressor implements Compressor
{
public function useCommand(): string
{
return 'gzip';
}
public function useExtension(): string
{
return 'gz';
}
}

View File

@@ -0,0 +1,101 @@
<?php
namespace Spatie\DbDumper\Databases;
use Spatie\DbDumper\DbDumper;
use Spatie\DbDumper\Exceptions\CannotStartDump;
use Symfony\Component\Process\Process;
class MongoDb extends DbDumper
{
protected int $port = 27017;
protected ?string $collection = null;
protected ?string $authenticationDatabase = null;
public function dumpToFile(string $dumpFile): void
{
$this->guardAgainstIncompleteCredentials();
$process = $this->getProcess($dumpFile);
$process->run();
$this->checkIfDumpWasSuccessFul($process, $dumpFile);
}
/**
* Verifies if the dbname and host options are set.
*
* @throws \Spatie\DbDumper\Exceptions\CannotStartDump
*
* @return void
*/
public function guardAgainstIncompleteCredentials(): void
{
foreach (['dbName', 'host'] as $requiredProperty) {
if (strlen($this->$requiredProperty) === 0) {
throw CannotStartDump::emptyParameter($requiredProperty);
}
}
}
public function setCollection(string $collection): self
{
$this->collection = $collection;
return $this;
}
public function setAuthenticationDatabase(string $authenticationDatabase): self
{
$this->authenticationDatabase = $authenticationDatabase;
return $this;
}
public function getDumpCommand(string $filename): string
{
$quote = $this->determineQuote();
$command = [
"{$quote}{$this->dumpBinaryPath}mongodump{$quote}",
"--db {$this->dbName}",
'--archive',
];
if ($this->userName) {
$command[] = "--username {$quote}{$this->userName}{$quote}";
}
if ($this->password) {
$command[] = "--password {$quote}{$this->password}{$quote}";
}
if (isset($this->host)) {
$command[] = "--host {$this->host}";
}
if (isset($this->port)) {
$command[] = "--port {$this->port}";
}
if (isset($this->collection)) {
$command[] = "--collection {$this->collection}";
}
if ($this->authenticationDatabase) {
$command[] = "--authenticationDatabase {$this->authenticationDatabase}";
}
return $this->echoToFile(implode(' ', $command), $filename);
}
public function getProcess(string $dumpFile): Process
{
$command = $this->getDumpCommand($dumpFile);
return Process::fromShellCommandline($command, null, null, null, $this->timeout);
}
}

View File

@@ -0,0 +1,297 @@
<?php
namespace Spatie\DbDumper\Databases;
use Spatie\DbDumper\DbDumper;
use Spatie\DbDumper\Exceptions\CannotStartDump;
use Symfony\Component\Process\Process;
class MySql extends DbDumper
{
protected bool $skipComments = true;
protected bool $useExtendedInserts = true;
protected bool $useSingleTransaction = false;
protected bool $skipLockTables = false;
protected bool $doNotUseColumnStatistics = false;
protected bool $useQuick = false;
protected string $defaultCharacterSet = '';
protected bool $dbNameWasSetAsExtraOption = false;
protected bool $allDatabasesWasSetAsExtraOption = false;
protected string $setGtidPurged = 'AUTO';
protected bool $createTables = true;
/** @var false|resource */
private $tempFileHandle;
public function __construct()
{
$this->port = 3306;
}
public function skipComments(): self
{
$this->skipComments = true;
return $this;
}
public function dontSkipComments(): self
{
$this->skipComments = false;
return $this;
}
public function useExtendedInserts(): self
{
$this->useExtendedInserts = true;
return $this;
}
public function dontUseExtendedInserts(): self
{
$this->useExtendedInserts = false;
return $this;
}
public function useSingleTransaction(): self
{
$this->useSingleTransaction = true;
return $this;
}
public function dontUseSingleTransaction(): self
{
$this->useSingleTransaction = false;
return $this;
}
public function skipLockTables(): self
{
$this->skipLockTables = true;
return $this;
}
public function doNotUseColumnStatistics(): self
{
$this->doNotUseColumnStatistics = true;
return $this;
}
public function dontSkipLockTables(): self
{
$this->skipLockTables = false;
return $this;
}
public function useQuick(): self
{
$this->useQuick = true;
return $this;
}
public function dontUseQuick(): self
{
$this->useQuick = false;
return $this;
}
public function setDefaultCharacterSet(string $characterSet): self
{
$this->defaultCharacterSet = $characterSet;
return $this;
}
public function setGtidPurged(string $setGtidPurged): self
{
$this->setGtidPurged = $setGtidPurged;
return $this;
}
public function dumpToFile(string $dumpFile): void
{
$this->guardAgainstIncompleteCredentials();
$tempFileHandle = tmpfile();
$this->setTempFileHandle($tempFileHandle);
$process = $this->getProcess($dumpFile);
$process->run();
$this->checkIfDumpWasSuccessFul($process, $dumpFile);
}
public function addExtraOption(string $extraOption): self
{
if (str_contains($extraOption, '--all-databases')) {
$this->dbNameWasSetAsExtraOption = true;
$this->allDatabasesWasSetAsExtraOption = true;
}
if (preg_match('/^--databases (\S+)/', $extraOption, $matches) === 1) {
$this->setDbName($matches[1]);
$this->dbNameWasSetAsExtraOption = true;
}
return parent::addExtraOption($extraOption);
}
public function doNotCreateTables(): self
{
$this->createTables = false;
return $this;
}
public function getDumpCommand(string $dumpFile, string $temporaryCredentialsFile): string
{
$quote = $this->determineQuote();
$command = [
"{$quote}{$this->dumpBinaryPath}mysqldump{$quote}",
"--defaults-extra-file=\"{$temporaryCredentialsFile}\"",
];
if (! $this->createTables) {
$command[] = '--no-create-info';
}
if ($this->skipComments) {
$command[] = '--skip-comments';
}
$command[] = $this->useExtendedInserts ? '--extended-insert' : '--skip-extended-insert';
if ($this->useSingleTransaction) {
$command[] = '--single-transaction';
}
if ($this->skipLockTables) {
$command[] = '--skip-lock-tables';
}
if ($this->doNotUseColumnStatistics) {
$command[] = '--column-statistics=0';
}
if ($this->useQuick) {
$command[] = '--quick';
}
if ($this->socket !== '') {
$command[] = "--socket={$this->socket}";
}
foreach ($this->excludeTables as $tableName) {
$command[] = "--ignore-table={$this->dbName}.{$tableName}";
}
if (! empty($this->defaultCharacterSet)) {
$command[] = '--default-character-set='.$this->defaultCharacterSet;
}
foreach ($this->extraOptions as $extraOption) {
$command[] = $extraOption;
}
if ($this->setGtidPurged !== 'AUTO') {
$command[] = '--set-gtid-purged='.$this->setGtidPurged;
}
if (! $this->dbNameWasSetAsExtraOption) {
$command[] = $this->dbName;
}
if (! empty($this->includeTables)) {
$includeTables = implode(' ', $this->includeTables);
$command[] = "--tables {$includeTables}";
}
foreach ($this->extraOptionsAfterDbName as $extraOptionAfterDbName) {
$command[] = $extraOptionAfterDbName;
}
return $this->echoToFile(implode(' ', $command), $dumpFile);
}
public function getContentsOfCredentialsFile(): string
{
$contents = [
'[client]',
"user = '{$this->userName}'",
"password = '{$this->password}'",
"port = '{$this->port}'",
];
if ($this->socket === '') {
$contents[] = "host = '{$this->host}'";
}
return implode(PHP_EOL, $contents);
}
public function guardAgainstIncompleteCredentials(): void
{
foreach (['userName', 'host'] as $requiredProperty) {
if (strlen($this->$requiredProperty) === 0) {
throw CannotStartDump::emptyParameter($requiredProperty);
}
}
if (strlen($this->dbName) === 0 && ! $this->allDatabasesWasSetAsExtraOption) {
throw CannotStartDump::emptyParameter('dbName');
}
}
/**
* @param string $dumpFile
* @return Process
*/
public function getProcess(string $dumpFile): Process
{
fwrite($this->getTempFileHandle(), $this->getContentsOfCredentialsFile());
$temporaryCredentialsFile = stream_get_meta_data($this->getTempFileHandle())['uri'];
$command = $this->getDumpCommand($dumpFile, $temporaryCredentialsFile);
return Process::fromShellCommandline($command, null, null, null, $this->timeout);
}
/**
* @return false|resource
*/
public function getTempFileHandle(): mixed
{
return $this->tempFileHandle;
}
/**
* @param false|resource $tempFileHandle
*/
public function setTempFileHandle($tempFileHandle)
{
$this->tempFileHandle = $tempFileHandle;
}
}

View File

@@ -0,0 +1,150 @@
<?php
namespace Spatie\DbDumper\Databases;
use Spatie\DbDumper\DbDumper;
use Spatie\DbDumper\Exceptions\CannotStartDump;
use Symfony\Component\Process\Process;
class PostgreSql extends DbDumper
{
protected bool $useInserts = false;
protected bool $createTables = true;
/** @var false|resource */
private $tempFileHandle;
public function __construct()
{
$this->port = 5432;
}
public function useInserts(): self
{
$this->useInserts = true;
return $this;
}
public function dumpToFile(string $dumpFile): void
{
$this->guardAgainstIncompleteCredentials();
$tempFileHandle = tmpfile();
$this->setTempFileHandle($tempFileHandle);
$process = $this->getProcess($dumpFile);
$process->run();
$this->checkIfDumpWasSuccessFul($process, $dumpFile);
}
public function getDumpCommand(string $dumpFile): string
{
$quote = $this->determineQuote();
$command = [
"{$quote}{$this->dumpBinaryPath}pg_dump{$quote}",
"-U \"{$this->userName}\"",
'-h '.($this->socket === '' ? $this->host : $this->socket),
"-p {$this->port}",
];
if ($this->useInserts) {
$command[] = '--inserts';
}
if (! $this->createTables) {
$command[] = '--data-only';
}
foreach ($this->extraOptions as $extraOption) {
$command[] = $extraOption;
}
if (! empty($this->includeTables)) {
$command[] = '-t '.implode(' -t ', $this->includeTables);
}
if (! empty($this->excludeTables)) {
$command[] = '-T '.implode(' -T ', $this->excludeTables);
}
return $this->echoToFile(implode(' ', $command), $dumpFile);
}
public function getContentsOfCredentialsFile(): string
{
$contents = [
$this->escapeCredentialEntry($this->host),
$this->escapeCredentialEntry($this->port),
$this->escapeCredentialEntry($this->dbName),
$this->escapeCredentialEntry($this->userName),
$this->escapeCredentialEntry($this->password),
];
return implode(':', $contents);
}
protected function escapeCredentialEntry($entry): string
{
$entry = str_replace('\\', '\\\\', $entry);
$entry = str_replace(':', '\\:', $entry);
return $entry;
}
public function guardAgainstIncompleteCredentials()
{
foreach (['userName', 'dbName', 'host'] as $requiredProperty) {
if (empty($this->$requiredProperty)) {
throw CannotStartDump::emptyParameter($requiredProperty);
}
}
}
protected function getEnvironmentVariablesForDumpCommand(string $temporaryCredentialsFile): array
{
return [
'PGPASSFILE' => $temporaryCredentialsFile,
'PGDATABASE' => $this->dbName,
];
}
public function doNotCreateTables(): self
{
$this->createTables = false;
return $this;
}
public function getProcess(string $dumpFile): Process
{
$command = $this->getDumpCommand($dumpFile);
fwrite($this->getTempFileHandle(), $this->getContentsOfCredentialsFile());
$temporaryCredentialsFile = stream_get_meta_data($this->getTempFileHandle())['uri'];
$envVars = $this->getEnvironmentVariablesForDumpCommand($temporaryCredentialsFile);
return Process::fromShellCommandline($command, null, $envVars, null, $this->timeout);
}
/**
* @return false|resource
*/
public function getTempFileHandle()
{
return $this->tempFileHandle;
}
/**
* @param false|resource $tempFileHandle
*/
public function setTempFileHandle($tempFileHandle): void
{
$this->tempFileHandle = $tempFileHandle;
}
}

View File

@@ -0,0 +1,61 @@
<?php
namespace Spatie\DbDumper\Databases;
use Spatie\DbDumper\DbDumper;
use SQLite3;
use Symfony\Component\Process\Process;
class Sqlite extends DbDumper
{
public function dumpToFile(string $dumpFile): void
{
$process = $this->getProcess($dumpFile);
$process->run();
$this->checkIfDumpWasSuccessFul($process, $dumpFile);
}
public function getDbTables(): array
{
$db = new SQLite3($this->dbName);
$query = $db->query("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%';");
$tables = [];
while ($table = $query->fetchArray(SQLITE3_ASSOC)) {
$tables[] = $table['name'];
}
$db->close();
return $tables;
}
public function getDumpCommand(string $dumpFile): string
{
$includeTables = rtrim(' ' . implode(' ', $this->includeTables));
if (empty($includeTables) && ! empty($this->excludeTables)) {
$tables = $this->getDbTables();
$includeTables = rtrim(' ' . implode(' ', array_diff($tables, $this->excludeTables)));
}
$dumpInSqlite = "echo 'BEGIN IMMEDIATE;\n.dump{$includeTables}'";
if ($this->isWindows()) {
$dumpInSqlite = "(echo BEGIN IMMEDIATE; & echo .dump{$includeTables})";
}
$quote = $this->determineQuote();
$command = sprintf(
"{$dumpInSqlite} | {$quote}%ssqlite3{$quote} --bail {$quote}%s{$quote}",
$this->dumpBinaryPath,
$this->dbName
);
return $this->echoToFile($command, $dumpFile);
}
public function getProcess(string $dumpFile): Process
{
$command = $this->getDumpCommand($dumpFile);
return Process::fromShellCommandline($command, null, null, null, $this->timeout);
}
}

262
vendor/spatie/db-dumper/src/DbDumper.php vendored Normal file
View File

@@ -0,0 +1,262 @@
<?php
namespace Spatie\DbDumper;
use Spatie\DbDumper\Compressors\Compressor;
use Spatie\DbDumper\Exceptions\CannotSetParameter;
use Spatie\DbDumper\Exceptions\DumpFailed;
use Symfony\Component\Process\Process;
abstract class DbDumper
{
protected string $databaseUrl = '';
protected string $dbName = '';
protected string $userName = '';
protected string $password = '';
protected string $host = 'localhost';
protected int $port = 5432;
protected string $socket = '';
protected int $timeout = 0;
protected string $dumpBinaryPath = '';
protected array $includeTables = [];
protected array $excludeTables = [];
protected array $extraOptions = [];
protected array $extraOptionsAfterDbName = [];
protected ?object $compressor = null;
public static function create(): static
{
return new static();
}
public function getDbName(): string
{
return $this->dbName;
}
public function setDbName(string $dbName): self
{
$this->dbName = $dbName;
return $this;
}
public function getDatabaseUrl(): string
{
return $this->databaseUrl;
}
public function setDatabaseUrl(string $databaseUrl): self
{
$this->databaseUrl = $databaseUrl;
$this->configureFromDatabaseUrl();
return $this;
}
public function setUserName(string $userName): self
{
$this->userName = $userName;
return $this;
}
public function setPassword(string $password): self
{
$this->password = $password;
return $this;
}
public function setHost(string $host): self
{
$this->host = $host;
return $this;
}
public function getHost(): string
{
return $this->host;
}
public function setPort(int $port): self
{
$this->port = $port;
return $this;
}
public function setSocket(string $socket): self
{
$this->socket = $socket;
return $this;
}
public function setTimeout(int $timeout): self
{
$this->timeout = $timeout;
return $this;
}
public function setDumpBinaryPath(string $dumpBinaryPath): self
{
if ($dumpBinaryPath !== '' && ! str_ends_with($dumpBinaryPath, '/')) {
$dumpBinaryPath .= '/';
}
$this->dumpBinaryPath = $dumpBinaryPath;
return $this;
}
public function getCompressorExtension(): string
{
return $this->compressor->useExtension();
}
public function useCompressor(Compressor $compressor): self
{
$this->compressor = $compressor;
return $this;
}
public function includeTables(string | array $includeTables): self
{
if (! empty($this->excludeTables)) {
throw CannotSetParameter::conflictingParameters('includeTables', 'excludeTables');
}
if (! is_array($includeTables)) {
$includeTables = explode(', ', $includeTables);
}
$this->includeTables = $includeTables;
return $this;
}
public function excludeTables(string | array $excludeTables): self
{
if (! empty($this->includeTables)) {
throw CannotSetParameter::conflictingParameters('excludeTables', 'includeTables');
}
if (! is_array($excludeTables)) {
$excludeTables = explode(', ', $excludeTables);
}
$this->excludeTables = $excludeTables;
return $this;
}
public function addExtraOption(string $extraOption): self
{
if (! empty($extraOption)) {
$this->extraOptions[] = $extraOption;
}
return $this;
}
public function addExtraOptionAfterDbName(string $extraOptionAfterDbName): self
{
if (! empty($extraOptionAfterDbName)) {
$this->extraOptionsAfterDbName[] = $extraOptionAfterDbName;
}
return $this;
}
abstract public function dumpToFile(string $dumpFile): void;
public function checkIfDumpWasSuccessFul(Process $process, string $outputFile): void
{
if (! $process->isSuccessful()) {
throw DumpFailed::processDidNotEndSuccessfully($process);
}
if (! file_exists($outputFile)) {
throw DumpFailed::dumpfileWasNotCreated($process);
}
if (filesize($outputFile) === 0) {
throw DumpFailed::dumpfileWasEmpty($process);
}
}
protected function configureFromDatabaseUrl(): void
{
$parsed = (new DsnParser($this->databaseUrl))->parse();
$componentMap = [
'host' => 'setHost',
'port' => 'setPort',
'database' => 'setDbName',
'username' => 'setUserName',
'password' => 'setPassword',
];
foreach ($parsed as $component => $value) {
if (isset($componentMap[$component])) {
$setterMethod = $componentMap[$component];
if (! $value || in_array($value, ['', 'null'])) {
continue;
}
$this->$setterMethod($value);
}
}
}
protected function getCompressCommand(string $command, string $dumpFile): string
{
$compressCommand = $this->compressor->useCommand();
if ($this->isWindows()) {
return "{$command} | {$compressCommand} > {$dumpFile}";
}
return "(((({$command}; echo \$? >&3) | {$compressCommand} > {$dumpFile}) 3>&1) | (read x; exit \$x))";
}
protected function echoToFile(string $command, string $dumpFile): string
{
$dumpFile = '"' . addcslashes($dumpFile, '\\"') . '"';
if ($this->compressor) {
return $this->getCompressCommand($command, $dumpFile);
}
return $command . ' > ' . $dumpFile;
}
protected function determineQuote(): string
{
return $this->isWindows() ? '"' : "'";
}
protected function isWindows(): bool
{
return str_starts_with(strtoupper(PHP_OS), 'WIN');
}
}

View File

@@ -0,0 +1,106 @@
<?php
namespace Spatie\DbDumper;
use Spatie\DbDumper\Exceptions\InvalidDatabaseUrl;
class DsnParser
{
protected string $dsn;
public function __construct(string $dsn)
{
$this->dsn = $dsn;
}
public function parse(): array
{
$rawComponents = $this->parseUrl($this->dsn);
$decodedComponents = $this->parseNativeTypes(
array_map('rawurldecode', $rawComponents)
);
return array_merge(
$this->getPrimaryOptions($decodedComponents),
$this->getQueryOptions($rawComponents)
);
}
protected function getPrimaryOptions($url): array
{
return array_filter([
'database' => $this->getDatabase($url),
'host' => $url['host'] ?? null,
'port' => $url['port'] ?? null,
'username' => $url['user'] ?? null,
'password' => $url['pass'] ?? null,
], static fn ($value) => ! is_null($value));
}
protected function getDatabase($url): ?string
{
$path = $url['path'] ?? null;
if (! $path) {
return null;
}
if ($path === '/') {
return null;
}
if (isset($url['scheme']) && str_contains($url['scheme'], 'sqlite')) {
return $path;
}
return trim($path, '/');
}
protected function getQueryOptions($url)
{
$queryString = $url['query'] ?? null;
if (! $queryString) {
return [];
}
$query = [];
parse_str($queryString, $query);
return $this->parseNativeTypes($query);
}
protected function parseUrl($url): array
{
$url = preg_replace('#^(sqlite3?):///#', '$1://null/', $url);
$parsedUrl = parse_url($url);
if ($parsedUrl === false) {
throw InvalidDatabaseUrl::invalidUrl($url);
}
return $parsedUrl;
}
protected function parseNativeTypes($value)
{
if (is_array($value)) {
return array_map([$this, 'parseNativeTypes'], $value);
}
if (! is_string($value)) {
return $value;
}
$parsedValue = json_decode($value, true);
if (json_last_error() === JSON_ERROR_NONE) {
return $parsedValue;
}
return $value;
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Spatie\DbDumper\Exceptions;
use Exception;
class CannotSetParameter extends Exception
{
public static function conflictingParameters(string $name, string $conflictName): static
{
return new static("Cannot set `{$name}` because it conflicts with parameter `{$conflictName}`.");
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Spatie\DbDumper\Exceptions;
use Exception;
class CannotStartDump extends Exception
{
public static function emptyParameter(string $name): static
{
return new static("Parameter `{$name}` cannot be empty.");
}
}

View File

@@ -0,0 +1,52 @@
<?php
namespace Spatie\DbDumper\Exceptions;
use Exception;
use Symfony\Component\Process\Process;
class DumpFailed extends Exception
{
public static function processDidNotEndSuccessfully(Process $process): static
{
$processOutput = static::formatProcessOutput($process);
return new static("The dump process failed with a none successful exitcode.{$processOutput}");
}
public static function dumpfileWasNotCreated(Process $process): static
{
$processOutput = static::formatProcessOutput($process);
return new static("The dumpfile could not be created.{$processOutput}");
}
public static function dumpfileWasEmpty(Process $process): static
{
$processOutput = static::formatProcessOutput($process);
return new static("The created dumpfile is empty.{$processOutput}");
}
protected static function formatProcessOutput(Process $process): string
{
$output = $process->getOutput() ?: '<no output>';
$errorOutput = $process->getErrorOutput() ?: '<no output>';
$exitCodeText = $process->getExitCodeText() ?: '<no exit text>';
return <<<CONSOLE
Exitcode
========
{$process->getExitCode()}: {$exitCodeText}
Output
======
{$output}
Error Output
============
{$errorOutput}
CONSOLE;
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Spatie\DbDumper\Exceptions;
use Exception;
class InvalidDatabaseUrl extends Exception
{
public static function invalidUrl(string $databaseUrl): static
{
return new static("Database URL `{$databaseUrl}` is invalid and cannot be parsed.");
}
}