diff --git a/composer.json b/composer.json index 7158ebdf..abac4455 100644 --- a/composer.json +++ b/composer.json @@ -19,7 +19,8 @@ "pguardiario/phpuri": "^1.0", "symfony/lock": "^4.1", "ezyang/htmlpurifier": "^4.10", - "xemlock/htmlpurifier-html5": "^0.1.7" + "xemlock/htmlpurifier-html5": "^0.1.7", + "catfan/medoo": "^1.5" }, "autoload": { "psr-4": { diff --git a/composer.lock b/composer.lock index 3c556fb3..38688521 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "43da7d5e9d8441faa4311f32b16ee1c0", + "content-hash": "3fceaf3c2925068c7e757ab12036e29e", "packages": [ { "name": "brandonwamboldt/utilphp", @@ -52,6 +52,65 @@ ], "time": "2015-02-02T17:56:14+00:00" }, + { + "name": "catfan/medoo", + "version": "v1.5.7", + "source": { + "type": "git", + "url": "https://github.com/catfan/Medoo.git", + "reference": "8d90cba0e8ff176028847527d0ea76fe41a06ecf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/catfan/Medoo/zipball/8d90cba0e8ff176028847527d0ea76fe41a06ecf", + "reference": "8d90cba0e8ff176028847527d0ea76fe41a06ecf", + "shasum": "" + }, + "require": { + "ext-pdo": "*", + "php": ">=5.4" + }, + "suggest": { + "ext-pdo_dblib": "For MSSQL or Sybase database on Linux/UNIX platform", + "ext-pdo_mysql": "For MySQL or MariaDB database", + "ext-pdo_oci": "For Oracle database", + "ext-pdo_oci8": "For Oracle version 8 database", + "ext-pdo_pqsql": "For PostgreSQL database", + "ext-pdo_sqlite": "For SQLite database", + "ext-pdo_sqlsrv": "For MSSQL database" + }, + "type": "framework", + "autoload": { + "psr-4": { + "Medoo\\": "/src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Angel Lai", + "email": "angel@catfan.me" + } + ], + "description": "The lightest PHP database framework to accelerate development", + "homepage": "https://medoo.in", + "keywords": [ + "database", + "lightweight", + "mariadb", + "mssql", + "mysql", + "oracle", + "php framework", + "postgresql", + "sql", + "sqlite" + ], + "time": "2018-06-14T18:59:08+00:00" + }, { "name": "ezyang/htmlpurifier", "version": "v4.10.0", @@ -318,16 +377,16 @@ }, { "name": "leafo/scssphp", - "version": "v0.7.6", + "version": "v0.7.7", "source": { "type": "git", "url": "https://github.com/leafo/scssphp.git", - "reference": "585f6ae84de62ffecf69c23805f25d78d7e4b794" + "reference": "1d656f8c02a3a69404bba6b28ec4e06edddf0f49" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/leafo/scssphp/zipball/585f6ae84de62ffecf69c23805f25d78d7e4b794", - "reference": "585f6ae84de62ffecf69c23805f25d78d7e4b794", + "url": "https://api.github.com/repos/leafo/scssphp/zipball/1d656f8c02a3a69404bba6b28ec4e06edddf0f49", + "reference": "1d656f8c02a3a69404bba6b28ec4e06edddf0f49", "shasum": "" }, "require": { @@ -366,7 +425,7 @@ "scss", "stylesheet" ], - "time": "2018-05-24T02:18:53+00:00" + "time": "2018-07-22T01:22:08+00:00" }, { "name": "league/plates", @@ -751,16 +810,16 @@ }, { "name": "symfony/lock", - "version": "v4.1.0", + "version": "v4.1.1", "source": { "type": "git", "url": "https://github.com/symfony/lock.git", - "reference": "a1df50492e927ad00ca271f29adb2949a14f2a5a" + "reference": "d508b5dd92272cb74300396ecaadde969d0f7976" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/lock/zipball/a1df50492e927ad00ca271f29adb2949a14f2a5a", - "reference": "a1df50492e927ad00ca271f29adb2949a14f2a5a", + "url": "https://api.github.com/repos/symfony/lock/zipball/d508b5dd92272cb74300396ecaadde969d0f7976", + "reference": "d508b5dd92272cb74300396ecaadde969d0f7976", "shasum": "" }, "require": { @@ -808,7 +867,7 @@ "redlock", "semaphore" ], - "time": "2018-05-30T07:26:09+00:00" + "time": "2018-06-21T11:15:46+00:00" }, { "name": "vlucas/valitron", diff --git a/vendor/catfan/medoo/.gitattributes b/vendor/catfan/medoo/.gitattributes new file mode 100644 index 00000000..8079ae23 --- /dev/null +++ b/vendor/catfan/medoo/.gitattributes @@ -0,0 +1,22 @@ +# Auto detect text files and perform LF normalization +* text=auto + +# Custom for Visual Studio +*.cs diff=csharp +*.sln merge=union +*.csproj merge=union +*.vbproj merge=union +*.fsproj merge=union +*.dbproj merge=union + +# Standard to msysgit +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain \ No newline at end of file diff --git a/vendor/catfan/medoo/.gitignore b/vendor/catfan/medoo/.gitignore new file mode 100644 index 00000000..0c814575 --- /dev/null +++ b/vendor/catfan/medoo/.gitignore @@ -0,0 +1,216 @@ +################# +## Eclipse +################# + +*.pydevproject +.project +.metadata +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.classpath +.settings/ +.loadpath + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# CDT-specific +.cproject + +# PDT-specific +.buildpath + + +################# +## Visual Studio +################# + +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +build/ +[Bb]in/ +[Oo]bj/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.Publish.xml +*.pubxml +*.publishproj + +# NuGet Packages Directory +## TODO: If you have NuGet Package Restore enabled, uncomment the next line +#packages/ + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.[Pp]ublish.xml +*.pfx +*.publishsettings + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file to a newer +# Visual Studio version. Backup files are not needed, because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +############# +## Windows detritus +############# + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac crap +.DS_Store + + +############# +## Python +############# + +*.py[cod] + +# Packages +*.egg +*.egg-info +dist/ +build/ +eggs/ +parts/ +var/ +sdist/ +develop-eggs/ +.installed.cfg + +# Installer logs +pip-log.txt + +# Unit test / coverage reports +.coverage +.tox + +#Translations +*.mo + +#Mr Developer +.mr.developer.cfg \ No newline at end of file diff --git a/vendor/catfan/medoo/LICENSE.md b/vendor/catfan/medoo/LICENSE.md new file mode 100644 index 00000000..a681c880 --- /dev/null +++ b/vendor/catfan/medoo/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Angel Lai + +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. diff --git a/vendor/catfan/medoo/README.md b/vendor/catfan/medoo/README.md new file mode 100644 index 00000000..f31e1d06 --- /dev/null +++ b/vendor/catfan/medoo/README.md @@ -0,0 +1,100 @@ +

+ +

+ +

+ Total Downloads + Latest Stable Version + License +

+ +> The Lightest PHP database framework to accelerate development + +## Features + +* **Lightweight** - Less than 100 KB, portable with only one file + +* **Easy** - Extremely easy to learn and use, friendly construction + +* **Powerful** - Supports various common and complex SQL queries, data mapping, and prevent SQL injection + +* **Compatible** - Supports all SQL databases, including MySQL, MSSQL, SQLite, MariaDB, PostgreSQL, Sybase, Oracle and more + +* **Friendly** - Works well with every PHP frameworks, like Laravel, Codeigniter, Yii, Slim, and framework which supports singleton extension or composer + +* **Free** - Under MIT license, you can use it anywhere whatever you want + +## Requirement + +PHP 5.4+ and PDO extension installed + +## Get Started + +### Install via composer + +Add Medoo to composer.json configuration file. +``` +$ composer require catfan/Medoo +``` + +And update the composer +``` +$ composer update +``` + +```php +// If you installed via composer, just use this code to requrie autoloader on the top of your projects. +require 'vendor/autoload.php'; + +// Using Medoo namespace +use Medoo\Medoo; + +// Initialize +$database = new Medoo([ + 'database_type' => 'mysql', + 'database_name' => 'name', + 'server' => 'localhost', + 'username' => 'your_username', + 'password' => 'your_password' +]); + +// Enjoy +$database->insert('account', [ + 'user_name' => 'foo', + 'email' => 'foo@bar.com' +]); + +$data = $database->select('account', [ + 'user_name', + 'email' +], [ + 'user_id' => 50 +]); + +echo json_encode($data); + +// [ +// { +// "user_name" : "foo", +// "email" : "foo@bar.com", +// } +// ] +``` + +## Contribution Guides + +For most of time, Medoo is using develop branch for adding feature and fixing bug, and the branch will be merged into master branch while releasing a public version. For contribution, submit your code to the develop branch, and start a pull request into it. + +On develop branch, each commits are started with `[fix]`, `[feature]` or `[update]` tag to indicate the change. + +Keep it simple and keep it clear. + +## License + +Medoo is under the MIT license. + +## Links + +* Official website: [https://medoo.in](https://medoo.in) + +* Documentation: [https://medoo.in/doc](https://medoo.in/doc) \ No newline at end of file diff --git a/vendor/catfan/medoo/composer.json b/vendor/catfan/medoo/composer.json new file mode 100644 index 00000000..39c1a9de --- /dev/null +++ b/vendor/catfan/medoo/composer.json @@ -0,0 +1,33 @@ +{ + "name": "catfan/medoo", + "type": "framework", + "description": "The lightest PHP database framework to accelerate development", + "keywords": ["database", "lightweight", "PHP framework", "SQL", "MySQL", "MSSQL", "SQLite", "PostgreSQL", "MariaDB", "Oracle"], + "homepage": "https://medoo.in", + "license": "MIT", + "support": { + "issues": "https://github.com/catfan/Medoo/issues", + "source": "https://github.com/catfan/Medoo" + }, + "authors": [ + {"name": "Angel Lai", "email": "angel@catfan.me"} + ], + "require": { + "php": ">=5.4", + "ext-pdo": "*" + }, + "suggest": { + "ext-pdo_mysql": "For MySQL or MariaDB database", + "ext-pdo_sqlsrv": "For MSSQL database", + "ext-pdo_dblib": "For MSSQL or Sybase database on Linux/UNIX platform", + "ext-pdo_oci": "For Oracle database", + "ext-pdo_oci8": "For Oracle version 8 database", + "ext-pdo_pqsql": "For PostgreSQL database", + "ext-pdo_sqlite": "For SQLite database" + }, + "autoload": { + "psr-4": { + "Medoo\\": "/src" + } + } +} \ No newline at end of file diff --git a/vendor/catfan/medoo/src/Medoo.php b/vendor/catfan/medoo/src/Medoo.php new file mode 100644 index 00000000..b97b8b8c --- /dev/null +++ b/vendor/catfan/medoo/src/Medoo.php @@ -0,0 +1,1553 @@ +type = strtolower($options[ 'database_type' ]); + } + + if (isset($options[ 'prefix' ])) + { + $this->prefix = $options[ 'prefix' ]; + } + + if (isset($options[ 'option' ])) + { + $this->option = $options[ 'option' ]; + } + + if (isset($options[ 'logging' ]) && is_bool($options[ 'logging' ])) + { + $this->logging = $options[ 'logging' ]; + } + + if (isset($options[ 'command' ]) && is_array($options[ 'command' ])) + { + $commands = $options[ 'command' ]; + } + else + { + $commands = []; + } + + if (isset($options[ 'dsn' ])) + { + if (is_array($options[ 'dsn' ]) && isset($options[ 'dsn' ][ 'driver' ])) + { + $attr = $options[ 'dsn' ]; + } + else + { + return false; + } + } + else + { + if ( + isset($options[ 'port' ]) && + is_int($options[ 'port' ] * 1) + ) + { + $port = $options[ 'port' ]; + } + + $is_port = isset($port); + + switch ($this->type) + { + case 'mariadb': + case 'mysql': + $attr = [ + 'driver' => 'mysql', + 'dbname' => $options[ 'database_name' ] + ]; + + if (isset($options[ 'socket' ])) + { + $attr[ 'unix_socket' ] = $options[ 'socket' ]; + } + else + { + $attr[ 'host' ] = $options[ 'server' ]; + + if ($is_port) + { + $attr[ 'port' ] = $port; + } + } + + // Make MySQL using standard quoted identifier + $commands[] = 'SET SQL_MODE=ANSI_QUOTES'; + break; + + case 'pgsql': + $attr = [ + 'driver' => 'pgsql', + 'host' => $options[ 'server' ], + 'dbname' => $options[ 'database_name' ] + ]; + + if ($is_port) + { + $attr[ 'port' ] = $port; + } + + break; + + case 'sybase': + $attr = [ + 'driver' => 'dblib', + 'host' => $options[ 'server' ], + 'dbname' => $options[ 'database_name' ] + ]; + + if ($is_port) + { + $attr[ 'port' ] = $port; + } + + break; + + case 'oracle': + $attr = [ + 'driver' => 'oci', + 'dbname' => $options[ 'server' ] ? + '//' . $options[ 'server' ] . ($is_port ? ':' . $port : ':1521') . '/' . $options[ 'database_name' ] : + $options[ 'database_name' ] + ]; + + if (isset($options[ 'charset' ])) + { + $attr[ 'charset' ] = $options[ 'charset' ]; + } + + break; + + case 'mssql': + if (isset($options[ 'driver' ]) && $options[ 'driver' ] === 'dblib') + { + $attr = [ + 'driver' => 'dblib', + 'host' => $options[ 'server' ] . ($is_port ? ':' . $port : ''), + 'dbname' => $options[ 'database_name' ] + ]; + } + else + { + $attr = [ + 'driver' => 'sqlsrv', + 'Server' => $options[ 'server' ] . ($is_port ? ',' . $port : ''), + 'Database' => $options[ 'database_name' ] + ]; + } + + // Keep MSSQL QUOTED_IDENTIFIER is ON for standard quoting + $commands[] = 'SET QUOTED_IDENTIFIER ON'; + + // Make ANSI_NULLS is ON for NULL value + $commands[] = 'SET ANSI_NULLS ON'; + break; + + case 'sqlite': + $attr = [ + 'driver' => 'sqlite', + $options[ 'database_file' ] + ]; + + break; + } + } + + $driver = $attr[ 'driver' ]; + + unset($attr[ 'driver' ]); + + $stack = []; + + foreach ($attr as $key => $value) + { + $stack[] = is_int($key) ? $value : $key . '=' . $value; + } + + $dsn = $driver . ':' . implode($stack, ';'); + + if ( + in_array($this->type, ['mariadb', 'mysql', 'pgsql', 'sybase', 'mssql']) && + isset($options[ 'charset' ]) + ) + { + $commands[] = "SET NAMES '" . $options[ 'charset' ] . "'"; + } + + try { + $this->pdo = new PDO( + $dsn, + isset($options[ 'username' ]) ? $options[ 'username' ] : null, + isset($options[ 'password' ]) ? $options[ 'password' ] : null, + $this->option + ); + + foreach ($commands as $value) + { + $this->pdo->exec($value); + } + } + catch (PDOException $e) { + throw new PDOException($e->getMessage()); + } + } + + public function __call($name, $arguments) + { + $aggregation = ['avg', 'count', 'max', 'min', 'sum']; + + if (in_array($name, $aggregation)) + { + array_unshift($arguments, $name); + + return call_user_func_array([$this, 'aggregate'], $arguments); + } + } + + public function query($query, $map = []) + { + $raw = $this->raw($query, $map); + + $query = $this->buildRaw($raw, $map); + + return $this->exec($query, $map); + } + + public function exec($query, $map = []) + { + if ($this->debug_mode) + { + echo $this->generate($query, $map); + + $this->debug_mode = false; + + return false; + } + + if ($this->logging) + { + $this->logs[] = [$query, $map]; + } + else + { + $this->logs = [[$query, $map]]; + } + + $statement = $this->pdo->prepare($query); + + if ($statement) + { + foreach ($map as $key => $value) + { + $statement->bindValue($key, $value[ 0 ], $value[ 1 ]); + } + + $statement->execute(); + + $this->statement = $statement; + + return $statement; + } + + return false; + } + + protected function generate($query, $map) + { + $identifier = [ + 'mysql' => '`$1`', + 'mariadb' => '`$1`', + 'mssql' => '[$1]' + ]; + + $query = preg_replace( + '/"([a-zA-Z0-9_]+)"/i', + isset($identifier[ $this->type ]) ? $identifier[ $this->type ] : '"$1"', + $query + ); + + foreach ($map as $key => $value) + { + if ($value[ 1 ] === PDO::PARAM_STR) + { + $replace = $this->quote($value[ 0 ]); + } + elseif ($value[ 1 ] === PDO::PARAM_NULL) + { + $replace = 'NULL'; + } + elseif ($value[ 1 ] === PDO::PARAM_LOB) + { + $replace = '{LOB_DATA}'; + } + else + { + $replace = $value[ 0 ]; + } + + $query = str_replace($key, $replace, $query); + } + + return $query; + } + + public static function raw($string, $map = []) + { + $raw = new Raw(); + + $raw->map = $map; + $raw->value = $string; + + return $raw; + } + + protected function isRaw($object) + { + return $object instanceof Raw; + } + + protected function buildRaw($raw, &$map) + { + if (!$this->isRaw($raw)) + { + return false; + } + + $query = preg_replace_callback( + '/((FROM|TABLE|INTO|UPDATE)\s*)?\<([a-zA-Z0-9_\.]+)\>/i', + function ($matches) + { + if (!empty($matches[ 2 ])) + { + return $matches[ 2 ] . ' ' . $this->tableQuote($matches[ 3 ]); + } + + return $this->columnQuote($matches[ 3 ]); + }, + $raw->value); + + $raw_map = $raw->map; + + if (!empty($raw_map)) + { + foreach ($raw_map as $key => $value) + { + $map[ $key ] = $this->typeMap($value, gettype($value)); + } + } + + return $query; + } + + public function quote($string) + { + return $this->pdo->quote($string); + } + + protected function tableQuote($table) + { + return '"' . $this->prefix . $table . '"'; + } + + protected function mapKey() + { + return ':MeDoO_' . $this->guid++ . '_mEdOo'; + } + + protected function typeMap($value, $type) + { + $map = [ + 'NULL' => PDO::PARAM_NULL, + 'integer' => PDO::PARAM_INT, + 'double' => PDO::PARAM_STR, + 'boolean' => PDO::PARAM_BOOL, + 'string' => PDO::PARAM_STR, + 'object' => PDO::PARAM_STR, + 'resource' => PDO::PARAM_LOB + ]; + + if ($type === 'boolean') + { + $value = ($value ? '1' : '0'); + } + elseif ($type === 'NULL') + { + $value = null; + } + + return [$value, $map[ $type ]]; + } + + protected function columnQuote($string) + { + if (strpos($string, '.') !== false) + { + return '"' . $this->prefix . str_replace('.', '"."', $string) . '"'; + } + + return '"' . $string . '"'; + } + + protected function columnPush(&$columns, &$map) + { + if ($columns === '*') + { + return $columns; + } + + $stack = []; + + if (is_string($columns)) + { + $columns = [$columns]; + } + + foreach ($columns as $key => $value) + { + if (is_array($value)) + { + $stack[] = $this->columnPush($value, $map); + } + elseif (!is_int($key) && $raw = $this->buildRaw($value, $map)) + { + preg_match('/(?[a-zA-Z0-9_\.]+)(\s*\[(?(String|Bool|Int|Number))\])?/i', $key, $match); + + $stack[] = $raw . ' AS ' . $this->columnQuote( $match[ 'column' ] ); + } + elseif (is_int($key) && is_string($value)) + { + preg_match('/(?[a-zA-Z0-9_\.]+)(?:\s*\((?[a-zA-Z0-9_]+)\))?(?:\s*\[(?(?:String|Bool|Int|Number|Object|JSON))\])?/i', $value, $match); + + if (!empty($match[ 'alias' ])) + { + $stack[] = $this->columnQuote( $match[ 'column' ] ) . ' AS ' . $this->columnQuote( $match[ 'alias' ] ); + + $columns[ $key ] = $match[ 'alias' ]; + + if (!empty($match[ 'type' ])) + { + $columns[ $key ] .= ' [' . $match[ 'type' ] . ']'; + } + } + else + { + $stack[] = $this->columnQuote( $match[ 'column' ] ); + } + } + } + + return implode($stack, ','); + } + + protected function arrayQuote($array) + { + $stack = []; + + foreach ($array as $value) + { + $stack[] = is_int($value) ? $value : $this->pdo->quote($value); + } + + return implode($stack, ','); + } + + protected function innerConjunct($data, $map, $conjunctor, $outer_conjunctor) + { + $stack = []; + + foreach ($data as $value) + { + $stack[] = '(' . $this->dataImplode($value, $map, $conjunctor) . ')'; + } + + return implode($outer_conjunctor . ' ', $stack); + } + + protected function dataImplode($data, &$map, $conjunctor) + { + $stack = []; + + foreach ($data as $key => $value) + { + $type = gettype($value); + + if ( + $type === 'array' && + preg_match("/^(AND|OR)(\s+#.*)?$/", $key, $relation_match) + ) + { + $relationship = $relation_match[ 1 ]; + + $stack[] = $value !== array_keys(array_keys($value)) ? + '(' . $this->dataImplode($value, $map, ' ' . $relationship) . ')' : + '(' . $this->innerConjunct($value, $map, ' ' . $relationship, $conjunctor) . ')'; + + continue; + } + + $map_key = $this->mapKey(); + + if ( + is_int($key) && + preg_match('/([a-zA-Z0-9_\.]+)\[(?\>\=?|\<\=?|\!?\=)\]([a-zA-Z0-9_\.]+)/i', $value, $match) + ) + { + $stack[] = $this->columnQuote($match[ 1 ]) . ' ' . $match[ 'operator' ] . ' ' . $this->columnQuote($match[ 3 ]); + } + else + { + preg_match('/([a-zA-Z0-9_\.]+)(\[(?\>\=?|\<\=?|\!|\<\>|\>\<|\!?~|REGEXP)\])?/i', $key, $match); + $column = $this->columnQuote($match[ 1 ]); + + if (isset($match[ 'operator' ])) + { + $operator = $match[ 'operator' ]; + + if (in_array($operator, ['>', '>=', '<', '<='])) + { + $condition = $column . ' ' . $operator . ' '; + + if (is_numeric($value)) + { + $condition .= $map_key; + $map[ $map_key ] = [$value, PDO::PARAM_INT]; + } + elseif ($raw = $this->buildRaw($value, $map)) + { + $condition .= $raw; + } + else + { + $condition .= $map_key; + $map[ $map_key ] = [$value, PDO::PARAM_STR]; + } + + $stack[] = $condition; + } + elseif ($operator === '!') + { + switch ($type) + { + case 'NULL': + $stack[] = $column . ' IS NOT NULL'; + break; + + case 'array': + $placeholders = []; + + foreach ($value as $index => $item) + { + $placeholders[] = $map_key . $index . '_i'; + $map[ $map_key . $index . '_i' ] = $this->typeMap($item, gettype($item)); + } + + $stack[] = $column . ' NOT IN (' . implode(', ', $placeholders) . ')'; + break; + + case 'object': + if ($raw = $this->buildRaw($value, $map)) + { + $stack[] = $column . ' != ' . $raw; + } + break; + + case 'integer': + case 'double': + case 'boolean': + case 'string': + $stack[] = $column . ' != ' . $map_key; + $map[ $map_key ] = $this->typeMap($value, $type); + break; + } + } + elseif ($operator === '~' || $operator === '!~') + { + if ($type !== 'array') + { + $value = [ $value ]; + } + + $connector = ' OR '; + $data = array_values($value); + + if (is_array($data[ 0 ])) + { + if (isset($value[ 'AND' ]) || isset($value[ 'OR' ])) + { + $connector = ' ' . array_keys($value)[ 0 ] . ' '; + $value = $data[ 0 ]; + } + } + + $like_clauses = []; + + foreach ($value as $index => $item) + { + $item = strval($item); + + if (!preg_match('/(\[.+\]|_|%.+|.+%)/', $item)) + { + $item = '%' . $item . '%'; + } + + $like_clauses[] = $column . ($operator === '!~' ? ' NOT' : '') . ' LIKE ' . $map_key . 'L' . $index; + $map[ $map_key . 'L' . $index ] = [$item, PDO::PARAM_STR]; + } + + $stack[] = '(' . implode($connector, $like_clauses) . ')'; + } + elseif ($operator === '<>' || $operator === '><') + { + if ($type === 'array') + { + if ($operator === '><') + { + $column .= ' NOT'; + } + + $stack[] = '(' . $column . ' BETWEEN ' . $map_key . 'a AND ' . $map_key . 'b)'; + + $data_type = (is_numeric($value[ 0 ]) && is_numeric($value[ 1 ])) ? PDO::PARAM_INT : PDO::PARAM_STR; + + $map[ $map_key . 'a' ] = [$value[ 0 ], $data_type]; + $map[ $map_key . 'b' ] = [$value[ 1 ], $data_type]; + } + } + elseif ($operator === 'REGEXP') + { + $stack[] = $column . ' REGEXP ' . $map_key; + $map[ $map_key ] = [$value, PDO::PARAM_STR]; + } + } + else + { + switch ($type) + { + case 'NULL': + $stack[] = $column . ' IS NULL'; + break; + + case 'array': + $placeholders = []; + + foreach ($value as $index => $item) + { + $placeholders[] = $map_key . $index . '_i'; + $map[ $map_key . $index . '_i' ] = $this->typeMap($item, gettype($item)); + } + + $stack[] = $column . ' IN (' . implode(', ', $placeholders) . ')'; + break; + + case 'object': + if ($raw = $this->buildRaw($value, $map)) + { + $stack[] = $column . ' = ' . $raw; + } + break; + + case 'integer': + case 'double': + case 'boolean': + case 'string': + $stack[] = $column . ' = ' . $map_key; + $map[ $map_key ] = $this->typeMap($value, $type); + break; + } + } + } + } + + return implode($conjunctor . ' ', $stack); + } + + protected function whereClause($where, &$map) + { + $where_clause = ''; + + if (is_array($where)) + { + $where_keys = array_keys($where); + + $conditions = array_diff_key($where, array_flip( + ['GROUP', 'ORDER', 'HAVING', 'LIMIT', 'LIKE', 'MATCH'] + )); + + if (!empty($conditions)) + { + $where_clause = ' WHERE ' . $this->dataImplode($conditions, $map, ' AND'); + } + + if (isset($where[ 'MATCH' ])) + { + $MATCH = $where[ 'MATCH' ]; + + if (is_array($MATCH) && isset($MATCH[ 'columns' ], $MATCH[ 'keyword' ])) + { + $mode = ''; + + $mode_array = [ + 'natural' => 'IN NATURAL LANGUAGE MODE', + 'natural+query' => 'IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION', + 'boolean' => 'IN BOOLEAN MODE', + 'query' => 'WITH QUERY EXPANSION' + ]; + + if (isset($MATCH[ 'mode' ], $mode_array[ $MATCH[ 'mode' ] ])) + { + $mode = ' ' . $mode_array[ $MATCH[ 'mode' ] ]; + } + + $columns = implode(array_map([$this, 'columnQuote'], $MATCH[ 'columns' ]), ', '); + $map_key = $this->mapKey(); + $map[ $map_key ] = [$MATCH[ 'keyword' ], PDO::PARAM_STR]; + + $where_clause .= ($where_clause !== '' ? ' AND ' : ' WHERE') . ' MATCH (' . $columns . ') AGAINST (' . $map_key . $mode . ')'; + } + } + + if (isset($where[ 'GROUP' ])) + { + $GROUP = $where[ 'GROUP' ]; + + if (is_array($GROUP)) + { + $stack = []; + + foreach ($GROUP as $column => $value) + { + $stack[] = $this->columnQuote($value); + } + + $where_clause .= ' GROUP BY ' . implode($stack, ','); + } + elseif ($raw = $this->buildRaw($GROUP, $map)) + { + $where_clause .= ' GROUP BY ' . $raw; + } + else + { + $where_clause .= ' GROUP BY ' . $this->columnQuote($GROUP); + } + + if (isset($where[ 'HAVING' ])) + { + if ($raw = $this->buildRaw($where[ 'HAVING' ], $map)) + { + $where_clause .= ' HAVING ' . $raw; + } + else + { + $where_clause .= ' HAVING ' . $this->dataImplode($where[ 'HAVING' ], $map, ' AND'); + } + } + } + + if (isset($where[ 'ORDER' ])) + { + $ORDER = $where[ 'ORDER' ]; + + if (is_array($ORDER)) + { + $stack = []; + + foreach ($ORDER as $column => $value) + { + if (is_array($value)) + { + $stack[] = 'FIELD(' . $this->columnQuote($column) . ', ' . $this->arrayQuote($value) . ')'; + } + elseif ($value === 'ASC' || $value === 'DESC') + { + $stack[] = $this->columnQuote($column) . ' ' . $value; + } + elseif (is_int($column)) + { + $stack[] = $this->columnQuote($value); + } + } + + $where_clause .= ' ORDER BY ' . implode($stack, ','); + } + elseif ($raw = $this->buildRaw($ORDER, $map)) + { + $where_clause .= ' ORDER BY ' . $raw; + } + else + { + $where_clause .= ' ORDER BY ' . $this->columnQuote($ORDER); + } + + if ( + isset($where[ 'LIMIT' ]) && + in_array($this->type, ['oracle', 'mssql']) + ) + { + $LIMIT = $where[ 'LIMIT' ]; + + if (is_numeric($LIMIT)) + { + $LIMIT = [0, $LIMIT]; + } + + if ( + is_array($LIMIT) && + is_numeric($LIMIT[ 0 ]) && + is_numeric($LIMIT[ 1 ]) + ) + { + $where_clause .= ' OFFSET ' . $LIMIT[ 0 ] . ' ROWS FETCH NEXT ' . $LIMIT[ 1 ] . ' ROWS ONLY'; + } + } + } + + if (isset($where[ 'LIMIT' ]) && !in_array($this->type, ['oracle', 'mssql'])) + { + $LIMIT = $where[ 'LIMIT' ]; + + if (is_numeric($LIMIT)) + { + $where_clause .= ' LIMIT ' . $LIMIT; + } + elseif ( + is_array($LIMIT) && + is_numeric($LIMIT[ 0 ]) && + is_numeric($LIMIT[ 1 ]) + ) + { + $where_clause .= ' LIMIT ' . $LIMIT[ 1 ] . ' OFFSET ' . $LIMIT[ 0 ]; + } + } + } + elseif ($raw = $this->buildRaw($where, $map)) + { + $where_clause .= ' ' . $raw; + } + + return $where_clause; + } + + protected function selectContext($table, &$map, $join, &$columns = null, $where = null, $column_fn = null) + { + preg_match('/(?[a-zA-Z0-9_]+)\s*\((?[a-zA-Z0-9_]+)\)/i', $table, $table_match); + + if (isset($table_match[ 'table' ], $table_match[ 'alias' ])) + { + $table = $this->tableQuote($table_match[ 'table' ]); + + $table_query = $table . ' AS ' . $this->tableQuote($table_match[ 'alias' ]); + } + else + { + $table = $this->tableQuote($table); + + $table_query = $table; + } + + $join_key = is_array($join) ? array_keys($join) : null; + + if ( + isset($join_key[ 0 ]) && + strpos($join_key[ 0 ], '[') === 0 + ) + { + $table_join = []; + + $join_array = [ + '>' => 'LEFT', + '<' => 'RIGHT', + '<>' => 'FULL', + '><' => 'INNER' + ]; + + foreach($join as $sub_table => $relation) + { + preg_match('/(\[(?\<\>?|\>\[a-zA-Z0-9_]+)\s?(\((?[a-zA-Z0-9_]+)\))?/', $sub_table, $match); + + if ($match[ 'join' ] !== '' && $match[ 'table' ] !== '') + { + if (is_string($relation)) + { + $relation = 'USING ("' . $relation . '")'; + } + + if (is_array($relation)) + { + // For ['column1', 'column2'] + if (isset($relation[ 0 ])) + { + $relation = 'USING ("' . implode($relation, '", "') . '")'; + } + else + { + $joins = []; + + foreach ($relation as $key => $value) + { + $joins[] = ( + strpos($key, '.') > 0 ? + // For ['tableB.column' => 'column'] + $this->columnQuote($key) : + + // For ['column1' => 'column2'] + $table . '."' . $key . '"' + ) . + ' = ' . + $this->tableQuote(isset($match[ 'alias' ]) ? $match[ 'alias' ] : $match[ 'table' ]) . '."' . $value . '"'; + } + + $relation = 'ON ' . implode($joins, ' AND '); + } + } + + $table_name = $this->tableQuote($match[ 'table' ]) . ' '; + + if (isset($match[ 'alias' ])) + { + $table_name .= 'AS ' . $this->tableQuote($match[ 'alias' ]) . ' '; + } + + $table_join[] = $join_array[ $match[ 'join' ] ] . ' JOIN ' . $table_name . $relation; + } + } + + $table_query .= ' ' . implode($table_join, ' '); + } + else + { + if (is_null($columns)) + { + if ( + !is_null($where) || + (is_array($join) && isset($column_fn)) + ) + { + $where = $join; + $columns = null; + } + else + { + $where = null; + $columns = $join; + } + } + else + { + $where = $columns; + $columns = $join; + } + } + + if (isset($column_fn)) + { + if ($column_fn === 1) + { + $column = '1'; + + if (is_null($where)) + { + $where = $columns; + } + } + else + { + if (empty($columns) || $this->isRaw($columns)) + { + $columns = '*'; + $where = $join; + } + + $column = $column_fn . '(' . $this->columnPush($columns, $map) . ')'; + } + } + else + { + $column = $this->columnPush($columns, $map); + } + + return 'SELECT ' . $column . ' FROM ' . $table_query . $this->whereClause($where, $map); + } + + protected function columnMap($columns, &$stack) + { + if ($columns === '*') + { + return $stack; + } + + foreach ($columns as $key => $value) + { + if (is_int($key)) + { + preg_match('/([a-zA-Z0-9_]+\.)?(?[a-zA-Z0-9_]+)(?:\s*\((?[a-zA-Z0-9_]+)\))?(?:\s*\[(?(?:String|Bool|Int|Number|Object|JSON))\])?/i', $value, $key_match); + + $column_key = !empty($key_match[ 'alias' ]) ? + $key_match[ 'alias' ] : + $key_match[ 'column' ]; + + if (isset($key_match[ 'type' ])) + { + $stack[ $value ] = [$column_key, $key_match[ 'type' ]]; + } + else + { + $stack[ $value ] = [$column_key, 'String']; + } + } + elseif ($this->isRaw($value)) + { + preg_match('/([a-zA-Z0-9_]+\.)?(?[a-zA-Z0-9_]+)(\s*\[(?(String|Bool|Int|Number))\])?/i', $key, $key_match); + + $column_key = $key_match[ 'column' ]; + + if (isset($key_match[ 'type' ])) + { + $stack[ $key ] = [$column_key, $key_match[ 'type' ]]; + } + else + { + $stack[ $key ] = [$column_key, 'String']; + } + } + elseif (!is_int($key) && is_array($value)) + { + $this->columnMap($value, $stack); + } + } + + return $stack; + } + + protected function dataMap($data, $columns, $column_map, &$stack) + { + foreach ($columns as $key => $value) + { + $isRaw = $this->isRaw($value); + + if (is_int($key) || $isRaw) + { + $map = $column_map[ $isRaw ? $key : $value ]; + + $column_key = $map[ 0 ]; + + $result = $data[ $column_key ]; + + if (isset($map[ 1 ])) + { + if ($isRaw && in_array($map[ 1 ], ['Object', 'JSON'])) + { + continue; + } + + if (is_null($result)) + { + $stack[ $column_key ] = null; + continue; + } + + switch ($map[ 1 ]) + { + case 'Number': + $stack[ $column_key ] = (double) $result; + break; + + case 'Int': + $stack[ $column_key ] = (int) $result; + break; + + case 'Bool': + $stack[ $column_key ] = (bool) $result; + break; + + case 'Object': + $stack[ $column_key ] = unserialize($result); + break; + + case 'JSON': + $stack[ $column_key ] = json_decode($result, true); + break; + + case 'String': + $stack[ $column_key ] = $result; + break; + } + } + else + { + $stack[ $column_key ] = $result; + } + } + else + { + $current_stack = []; + + $this->dataMap($data, $value, $column_map, $current_stack); + + $stack[ $key ] = $current_stack; + } + } + } + + public function select($table, $join, $columns = null, $where = null) + { + $map = []; + $stack = []; + $column_map = []; + + $index = 0; + + $column = $where === null ? $join : $columns; + + $is_single = (is_string($column) && $column !== '*'); + + $query = $this->exec($this->selectContext($table, $map, $join, $columns, $where), $map); + + $this->columnMap($columns, $column_map); + + if (!$query) + { + return false; + } + + if ($columns === '*') + { + return $query->fetchAll(PDO::FETCH_ASSOC); + } + + if ($is_single) + { + return $query->fetchAll(PDO::FETCH_COLUMN); + } + + while ($data = $query->fetch(PDO::FETCH_ASSOC)) + { + $current_stack = []; + + $this->dataMap($data, $columns, $column_map, $current_stack); + + $stack[ $index ] = $current_stack; + + $index++; + } + + return $stack; + } + + public function insert($table, $datas) + { + $stack = []; + $columns = []; + $fields = []; + $map = []; + + if (!isset($datas[ 0 ])) + { + $datas = [$datas]; + } + + foreach ($datas as $data) + { + foreach ($data as $key => $value) + { + $columns[] = $key; + } + } + + $columns = array_unique($columns); + + foreach ($datas as $data) + { + $values = []; + + foreach ($columns as $key) + { + if ($raw = $this->buildRaw($data[ $key ], $map)) + { + $values[] = $raw; + continue; + } + + $map_key =$this->mapKey(); + + $values[] = $map_key; + + if (!isset($data[ $key ])) + { + $map[ $map_key ] = [null, PDO::PARAM_NULL]; + } + else + { + $value = $data[ $key ]; + + $type = gettype($value); + + switch ($type) + { + case 'array': + $map[ $map_key ] = [ + strpos($key, '[JSON]') === strlen($key) - 6 ? + json_encode($value) : + serialize($value), + PDO::PARAM_STR + ]; + break; + + case 'object': + $value = serialize($value); + + case 'NULL': + case 'resource': + case 'boolean': + case 'integer': + case 'double': + case 'string': + $map[ $map_key ] = $this->typeMap($value, $type); + break; + } + } + } + + $stack[] = '(' . implode($values, ', ') . ')'; + } + + foreach ($columns as $key) + { + $fields[] = $this->columnQuote(preg_replace("/(\s*\[JSON\]$)/i", '', $key)); + } + + return $this->exec('INSERT INTO ' . $this->tableQuote($table) . ' (' . implode(', ', $fields) . ') VALUES ' . implode(', ', $stack), $map); + } + + public function update($table, $data, $where = null) + { + $fields = []; + $map = []; + + foreach ($data as $key => $value) + { + $column = $this->columnQuote(preg_replace("/(\s*\[(JSON|\+|\-|\*|\/)\]$)/i", '', $key)); + + if ($raw = $this->buildRaw($value, $map)) + { + $fields[] = $column . ' = ' . $raw; + continue; + } + + $map_key = $this->mapKey(); + + preg_match('/(?[a-zA-Z0-9_]+)(\[(?\+|\-|\*|\/)\])?/i', $key, $match); + + if (isset($match[ 'operator' ])) + { + if (is_numeric($value)) + { + $fields[] = $column . ' = ' . $column . ' ' . $match[ 'operator' ] . ' ' . $value; + } + } + else + { + $fields[] = $column . ' = ' . $map_key; + + $type = gettype($value); + + switch ($type) + { + case 'array': + $map[ $map_key ] = [ + strpos($key, '[JSON]') === strlen($key) - 6 ? + json_encode($value) : + serialize($value), + PDO::PARAM_STR + ]; + break; + + case 'object': + $value = serialize($value); + + case 'NULL': + case 'resource': + case 'boolean': + case 'integer': + case 'double': + case 'string': + $map[ $map_key ] = $this->typeMap($value, $type); + break; + } + } + } + + return $this->exec('UPDATE ' . $this->tableQuote($table) . ' SET ' . implode(', ', $fields) . $this->whereClause($where, $map), $map); + } + + public function delete($table, $where) + { + $map = []; + + return $this->exec('DELETE FROM ' . $this->tableQuote($table) . $this->whereClause($where, $map), $map); + } + + public function replace($table, $columns, $where = null) + { + if (!is_array($columns) || empty($columns)) + { + return false; + } + + $map = []; + $stack = []; + + foreach ($columns as $column => $replacements) + { + if (is_array($replacements)) + { + foreach ($replacements as $old => $new) + { + $map_key = $this->mapKey(); + + $stack[] = $this->columnQuote($column) . ' = REPLACE(' . $this->columnQuote($column) . ', ' . $map_key . 'a, ' . $map_key . 'b)'; + + $map[ $map_key . 'a' ] = [$old, PDO::PARAM_STR]; + $map[ $map_key . 'b' ] = [$new, PDO::PARAM_STR]; + } + } + } + + if (!empty($stack)) + { + return $this->exec('UPDATE ' . $this->tableQuote($table) . ' SET ' . implode(', ', $stack) . $this->whereClause($where, $map), $map); + } + + return false; + } + + public function get($table, $join = null, $columns = null, $where = null) + { + $map = []; + $stack = []; + $column_map = []; + + if ($where === null) + { + $column = $join; + unset($columns[ 'LIMIT' ]); + } + else + { + $column = $columns; + unset($where[ 'LIMIT' ]); + } + + $is_single = (is_string($column) && $column !== '*'); + + $query = $this->exec($this->selectContext($table, $map, $join, $columns, $where) . ' LIMIT 1', $map); + + if ($query) + { + $data = $query->fetchAll(PDO::FETCH_ASSOC); + + if (isset($data[ 0 ])) + { + if ($column === '*') + { + return $data[ 0 ]; + } + + $this->columnMap($columns, $column_map); + + $this->dataMap($data[ 0 ], $columns, $column_map, $stack); + + if ($is_single) + { + return $stack[ $column_map[ $column ][ 0 ] ]; + } + + return $stack; + } + + return false; + } + + return false; + } + + public function has($table, $join, $where = null) + { + $map = []; + $column = null; + + $query = $this->exec('SELECT EXISTS(' . $this->selectContext($table, $map, $join, $column, $where, 1) . ')', $map); + + if ($query) + { + $result = $query->fetchColumn(); + + return $result === '1' || $result === true; + } + + return false; + } + + private function aggregate($type, $table, $join = null, $column = null, $where = null) + { + $map = []; + + $query = $this->exec($this->selectContext($table, $map, $join, $column, $where, strtoupper($type)), $map); + + if ($query) + { + $number = $query->fetchColumn(); + + return is_numeric($number) ? $number + 0 : $number; + } + + return false; + } + + public function action($actions) + { + if (is_callable($actions)) + { + $this->pdo->beginTransaction(); + + try { + $result = $actions($this); + + if ($result === false) + { + $this->pdo->rollBack(); + } + else + { + $this->pdo->commit(); + } + } + catch (Exception $e) { + $this->pdo->rollBack(); + + throw $e; + } + + return $result; + } + + return false; + } + + public function id() + { + $type = $this->type; + + if ($type === 'oracle') + { + return 0; + } + elseif ($type === 'mssql') + { + return $this->pdo->query('SELECT SCOPE_IDENTITY()')->fetchColumn(); + } + elseif ($type === 'pgsql') + { + return $this->pdo->query('SELECT LASTVAL()')->fetchColumn(); + } + + return $this->pdo->lastInsertId(); + } + + public function debug() + { + $this->debug_mode = true; + + return $this; + } + + public function error() + { + return $this->statement ? $this->statement->errorInfo() : null; + } + + public function last() + { + $log = end($this->logs); + + return $this->generate($log[ 0 ], $log[ 1 ]); + } + + public function log() + { + return array_map(function ($log) + { + return $this->generate($log[ 0 ], $log[ 1 ]); + }, + $this->logs + ); + } + + public function info() + { + $output = [ + 'server' => 'SERVER_INFO', + 'driver' => 'DRIVER_NAME', + 'client' => 'CLIENT_VERSION', + 'version' => 'SERVER_VERSION', + 'connection' => 'CONNECTION_STATUS' + ]; + + foreach ($output as $key => $value) + { + $output[ $key ] = @$this->pdo->getAttribute(constant('PDO::ATTR_' . $value)); + } + + return $output; + } +} +?> \ No newline at end of file diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php index 720e426f..9bd88669 100644 --- a/vendor/composer/autoload_psr4.php +++ b/vendor/composer/autoload_psr4.php @@ -15,6 +15,7 @@ return array( 'PhpExtended\\Tail\\' => array($vendorDir . '/php-extended/php-tail/src'), 'PhpExtended\\System\\' => array($vendorDir . '/php-extended/php-system/src'), 'Monolog\\' => array($vendorDir . '/monolog/monolog/src/Monolog'), + 'Medoo\\' => array($vendorDir . '/catfan/medoo/src'), 'League\\Plates\\' => array($vendorDir . '/league/plates/src'), 'Leafo\\ScssPhp\\' => array($vendorDir . '/leafo/scssphp/src'), 'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'), diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index 1762a4fd..85e66636 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -42,6 +42,7 @@ class ComposerStaticInit67b09c83b85c3bc0027caefe5bba171a 'M' => array ( 'Monolog\\' => 8, + 'Medoo\\' => 6, ), 'L' => array ( @@ -93,6 +94,10 @@ class ComposerStaticInit67b09c83b85c3bc0027caefe5bba171a array ( 0 => __DIR__ . '/..' . '/monolog/monolog/src/Monolog', ), + 'Medoo\\' => + array ( + 0 => __DIR__ . '/..' . '/catfan/medoo/src', + ), 'League\\Plates\\' => array ( 0 => __DIR__ . '/..' . '/league/plates/src', diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index 1829b0a3..7b29a9ee 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -47,6 +47,67 @@ "utility" ] }, + { + "name": "catfan/medoo", + "version": "v1.5.7", + "version_normalized": "1.5.7.0", + "source": { + "type": "git", + "url": "https://github.com/catfan/Medoo.git", + "reference": "8d90cba0e8ff176028847527d0ea76fe41a06ecf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/catfan/Medoo/zipball/8d90cba0e8ff176028847527d0ea76fe41a06ecf", + "reference": "8d90cba0e8ff176028847527d0ea76fe41a06ecf", + "shasum": "" + }, + "require": { + "ext-pdo": "*", + "php": ">=5.4" + }, + "suggest": { + "ext-pdo_dblib": "For MSSQL or Sybase database on Linux/UNIX platform", + "ext-pdo_mysql": "For MySQL or MariaDB database", + "ext-pdo_oci": "For Oracle database", + "ext-pdo_oci8": "For Oracle version 8 database", + "ext-pdo_pqsql": "For PostgreSQL database", + "ext-pdo_sqlite": "For SQLite database", + "ext-pdo_sqlsrv": "For MSSQL database" + }, + "time": "2018-06-14T18:59:08+00:00", + "type": "framework", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Medoo\\": "/src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Angel Lai", + "email": "angel@catfan.me" + } + ], + "description": "The lightest PHP database framework to accelerate development", + "homepage": "https://medoo.in", + "keywords": [ + "database", + "lightweight", + "mariadb", + "mssql", + "mysql", + "oracle", + "php framework", + "postgresql", + "sql", + "sqlite" + ] + }, { "name": "ezyang/htmlpurifier", "version": "v4.10.0", @@ -323,17 +384,17 @@ }, { "name": "leafo/scssphp", - "version": "v0.7.6", - "version_normalized": "0.7.6.0", + "version": "v0.7.7", + "version_normalized": "0.7.7.0", "source": { "type": "git", "url": "https://github.com/leafo/scssphp.git", - "reference": "585f6ae84de62ffecf69c23805f25d78d7e4b794" + "reference": "1d656f8c02a3a69404bba6b28ec4e06edddf0f49" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/leafo/scssphp/zipball/585f6ae84de62ffecf69c23805f25d78d7e4b794", - "reference": "585f6ae84de62ffecf69c23805f25d78d7e4b794", + "url": "https://api.github.com/repos/leafo/scssphp/zipball/1d656f8c02a3a69404bba6b28ec4e06edddf0f49", + "reference": "1d656f8c02a3a69404bba6b28ec4e06edddf0f49", "shasum": "" }, "require": { @@ -343,7 +404,7 @@ "phpunit/phpunit": "~4.6", "squizlabs/php_codesniffer": "~2.5" }, - "time": "2018-05-24T02:18:53+00:00", + "time": "2018-07-22T01:22:08+00:00", "bin": [ "bin/pscss" ], @@ -774,17 +835,17 @@ }, { "name": "symfony/lock", - "version": "v4.1.0", - "version_normalized": "4.1.0.0", + "version": "v4.1.1", + "version_normalized": "4.1.1.0", "source": { "type": "git", "url": "https://github.com/symfony/lock.git", - "reference": "a1df50492e927ad00ca271f29adb2949a14f2a5a" + "reference": "d508b5dd92272cb74300396ecaadde969d0f7976" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/lock/zipball/a1df50492e927ad00ca271f29adb2949a14f2a5a", - "reference": "a1df50492e927ad00ca271f29adb2949a14f2a5a", + "url": "https://api.github.com/repos/symfony/lock/zipball/d508b5dd92272cb74300396ecaadde969d0f7976", + "reference": "d508b5dd92272cb74300396ecaadde969d0f7976", "shasum": "" }, "require": { @@ -794,7 +855,7 @@ "require-dev": { "predis/predis": "~1.0" }, - "time": "2018-05-30T07:26:09+00:00", + "time": "2018-06-21T11:15:46+00:00", "type": "library", "extra": { "branch-alias": { diff --git a/vendor/leafo/scssphp/src/Compiler.php b/vendor/leafo/scssphp/src/Compiler.php index 72df991e..637f1c1c 100644 --- a/vendor/leafo/scssphp/src/Compiler.php +++ b/vendor/leafo/scssphp/src/Compiler.php @@ -3655,7 +3655,7 @@ class Compiler return false; } - list($sorted, $kwargs) = $this->sortArgs($prototype, $args); + @list($sorted, $kwargs) = $this->sortArgs($prototype, $args); if ($name !== 'if' && $name !== 'call') { foreach ($sorted as &$val) { @@ -3714,7 +3714,7 @@ class Compiler $key = $key[1]; if (empty($key)) { - $posArgs[] = $value; + $posArgs[] = empty($arg[2]) ? $value : $arg; } else { $keyArgs[$key] = $value; } @@ -4266,20 +4266,38 @@ class Compiler { $name = $this->compileStringContent($this->coerceString($this->reduce(array_shift($args), true))); - $args = array_map( - function ($a) { - return [null, $a, false]; - }, - $args - ); + $posArgs = []; + + foreach ($args as $arg) { + if (empty($arg[0])) { + if ($arg[2] === true) { + $tmp = $this->reduce($arg[1]); + + if ($tmp[0] === Type::T_LIST) { + foreach ($tmp[2] as $item) { + $posArgs[] = [null, $item, false]; + } + } else { + $posArgs[] = [null, $tmp, true]; + } + + continue; + } + + $posArgs[] = [null, $this->reduce($arg), false]; + continue; + } + + $posArgs[] = [null, $arg, false]; + } if (count($kwargs)) { foreach ($kwargs as $key => $value) { - $args[] = [[Type::T_VARIABLE, $key], $value, false]; + $posArgs[] = [[Type::T_VARIABLE, $key], $value, false]; } } - return $this->reduce([Type::T_FUNCTION_CALL, $name, $args]); + return $this->reduce([Type::T_FUNCTION_CALL, $name, $posArgs]); } protected static $libIf = ['condition', 'if-true', 'if-false']; @@ -4838,7 +4856,7 @@ class Compiler if (null === $unit) { $unit = $number[2]; $originalUnit = $item->unitStr(); - } elseif ($unit !== $number[2]) { + } elseif ($number[1] && $unit !== $number[2]) { $this->throwError('Incompatible units: "%s" and "%s".', $originalUnit, $item->unitStr()); break; } @@ -4985,7 +5003,21 @@ class Compiler $map1 = $this->assertMap($args[0]); $map2 = $this->assertMap($args[1]); - return [Type::T_MAP, array_merge($map1[1], $map2[1]), array_merge($map1[2], $map2[2])]; + foreach ($map2[1] as $i2 => $key2) { + $key = $this->compileStringContent($this->coerceString($key2)); + + foreach ($map1[1] as $i1 => $key1) { + if ($key === $this->compileStringContent($this->coerceString($key1))) { + $map1[2][$i1] = $map2[2][$i2]; + continue 2; + } + } + + $map1[1][] = $map2[1][$i2]; + $map1[2][] = $map2[2][$i2]; + } + + return $map1; } protected static $libKeywords = ['args']; diff --git a/vendor/symfony/lock/Store/FlockStore.php b/vendor/symfony/lock/Store/FlockStore.php index bf72eaef..1ef9ec84 100644 --- a/vendor/symfony/lock/Store/FlockStore.php +++ b/vendor/symfony/lock/Store/FlockStore.php @@ -79,12 +79,12 @@ class FlockStore implements StoreInterface // Silence error reporting set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; }); - if (!$handle = fopen($fileName, 'r')) { + if (!$handle = fopen($fileName, 'r+') ?: fopen($fileName, 'r')) { if ($handle = fopen($fileName, 'x')) { chmod($fileName, 0444); - } elseif (!$handle = fopen($fileName, 'r')) { + } elseif (!$handle = fopen($fileName, 'r+') ?: fopen($fileName, 'r')) { usleep(100); // Give some time for chmod() to complete - $handle = fopen($fileName, 'r'); + $handle = fopen($fileName, 'r+') ?: fopen($fileName, 'r'); } } restore_error_handler(); diff --git a/vendor/symfony/lock/Store/SemaphoreStore.php b/vendor/symfony/lock/Store/SemaphoreStore.php index 8913e391..6a32a303 100644 --- a/vendor/symfony/lock/Store/SemaphoreStore.php +++ b/vendor/symfony/lock/Store/SemaphoreStore.php @@ -64,8 +64,14 @@ class SemaphoreStore implements StoreInterface return; } - $resource = sem_get(crc32($key)); - $acquired = sem_acquire($resource, !$blocking); + $keyId = crc32($key); + $resource = sem_get($keyId); + $acquired = @sem_acquire($resource, !$blocking); + + while ($blocking && !$acquired) { + $resource = sem_get($keyId); + $acquired = @sem_acquire($resource); + } if (!$acquired) { throw new LockConflictedException(); @@ -86,7 +92,7 @@ class SemaphoreStore implements StoreInterface $resource = $key->getState(__CLASS__); - sem_release($resource); + sem_remove($resource); $key->removeState(__CLASS__); } diff --git a/vendor/symfony/lock/Tests/Store/SemaphoreStoreTest.php b/vendor/symfony/lock/Tests/Store/SemaphoreStoreTest.php index eeb95d58..97c93c78 100644 --- a/vendor/symfony/lock/Tests/Store/SemaphoreStoreTest.php +++ b/vendor/symfony/lock/Tests/Store/SemaphoreStoreTest.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Lock\Tests\Store; +use Symfony\Component\Lock\Key; use Symfony\Component\Lock\Store\SemaphoreStore; /** @@ -29,4 +30,31 @@ class SemaphoreStoreTest extends AbstractStoreTest { return new SemaphoreStore(); } + + public function testResourceRemoval() + { + $initialCount = $this->getOpenedSemaphores(); + $store = new SemaphoreStore(); + $key = new Key(uniqid(__METHOD__, true)); + $store->waitAndSave($key); + + $this->assertGreaterThan($initialCount, $this->getOpenedSemaphores(), 'Semaphores should have been created'); + + $store->delete($key); + $this->assertEquals($initialCount, $this->getOpenedSemaphores(), 'All semaphores should be removed'); + } + + private function getOpenedSemaphores() + { + $lines = explode(PHP_EOL, trim(`ipcs -su`)); + if ('------ Semaphore Status --------' !== $lines[0]) { + throw new \Exception('Failed to extract list of opend semaphores. Expect a Semaphore status, got '.implode(PHP_EOL, $lines)); + } + list($key, $value) = explode(' = ', $lines[1]); + if ('used arrays' !== $key) { + throw new \Exception('Failed to extract list of opend semaphores. Expect a used arrays key, got '.implode(PHP_EOL, $lines)); + } + + return (int) $value; + } }