From 7470eddf83c29f07e2455f3f74449e469f6afa9c Mon Sep 17 00:00:00 2001 From: patrick Date: Tue, 1 Dec 2020 00:21:04 +1100 Subject: [PATCH] initial license --- .buildpath | 5 + .index.php.swp | Bin 0 -> 12288 bytes .project | 22 + .settings/org.eclipse.php.core.prefs | 3 + README.md | 0 composer.json | 5 + composer.lock | 67 ++ config.php | 6 + fail.txt | 21 + index.php | 46 + success.txt | 19 + vendor/autoload.php | 7 + vendor/composer/ClassLoader.php | 445 ++++++++ vendor/composer/InstalledVersions.php | 218 ++++ vendor/composer/LICENSE | 21 + vendor/composer/autoload_classmap.php | 17 + vendor/composer/autoload_namespaces.php | 9 + vendor/composer/autoload_psr4.php | 9 + vendor/composer/autoload_real.php | 57 + vendor/composer/autoload_static.php | 27 + vendor/composer/installed.json | 57 + vendor/composer/installed.php | 33 + vendor/composer/platform_check.php | 26 + vendor/sergeytsalkov/meekrodb/.gitignore | 1 + vendor/sergeytsalkov/meekrodb/LICENSE | 165 +++ vendor/sergeytsalkov/meekrodb/README.md | 149 +++ vendor/sergeytsalkov/meekrodb/composer.json | 29 + vendor/sergeytsalkov/meekrodb/db.class.php | 1009 +++++++++++++++++ .../meekrodb/simpletest/BasicTest.php | 439 +++++++ .../meekrodb/simpletest/CallTest.php | 17 + .../meekrodb/simpletest/ErrorTest.php | 83 ++ .../meekrodb/simpletest/ErrorTest_53.php | 19 + .../meekrodb/simpletest/HelperTest.php | 51 + .../meekrodb/simpletest/ObjectTest.php | 312 +++++ .../meekrodb/simpletest/TransactionTest.php | 30 + .../simpletest/TransactionTest_55.php | 85 ++ .../meekrodb/simpletest/WhereClauseTest.php | 83 ++ .../meekrodb/simpletest/smile1.jpg | Bin 0 -> 48874 bytes .../meekrodb/simpletest/test.php | 87 ++ 39 files changed, 3679 insertions(+) create mode 100644 .buildpath create mode 100644 .index.php.swp create mode 100644 .project create mode 100644 .settings/org.eclipse.php.core.prefs create mode 100644 README.md create mode 100644 composer.json create mode 100644 composer.lock create mode 100644 config.php create mode 100644 fail.txt create mode 100644 index.php create mode 100644 success.txt create mode 100644 vendor/autoload.php create mode 100644 vendor/composer/ClassLoader.php create mode 100644 vendor/composer/InstalledVersions.php create mode 100644 vendor/composer/LICENSE create mode 100644 vendor/composer/autoload_classmap.php create mode 100644 vendor/composer/autoload_namespaces.php create mode 100644 vendor/composer/autoload_psr4.php create mode 100644 vendor/composer/autoload_real.php create mode 100644 vendor/composer/autoload_static.php create mode 100644 vendor/composer/installed.json create mode 100644 vendor/composer/installed.php create mode 100644 vendor/composer/platform_check.php create mode 100644 vendor/sergeytsalkov/meekrodb/.gitignore create mode 100644 vendor/sergeytsalkov/meekrodb/LICENSE create mode 100644 vendor/sergeytsalkov/meekrodb/README.md create mode 100644 vendor/sergeytsalkov/meekrodb/composer.json create mode 100644 vendor/sergeytsalkov/meekrodb/db.class.php create mode 100644 vendor/sergeytsalkov/meekrodb/simpletest/BasicTest.php create mode 100644 vendor/sergeytsalkov/meekrodb/simpletest/CallTest.php create mode 100644 vendor/sergeytsalkov/meekrodb/simpletest/ErrorTest.php create mode 100644 vendor/sergeytsalkov/meekrodb/simpletest/ErrorTest_53.php create mode 100644 vendor/sergeytsalkov/meekrodb/simpletest/HelperTest.php create mode 100644 vendor/sergeytsalkov/meekrodb/simpletest/ObjectTest.php create mode 100644 vendor/sergeytsalkov/meekrodb/simpletest/TransactionTest.php create mode 100644 vendor/sergeytsalkov/meekrodb/simpletest/TransactionTest_55.php create mode 100644 vendor/sergeytsalkov/meekrodb/simpletest/WhereClauseTest.php create mode 100644 vendor/sergeytsalkov/meekrodb/simpletest/smile1.jpg create mode 100755 vendor/sergeytsalkov/meekrodb/simpletest/test.php diff --git a/.buildpath b/.buildpath new file mode 100644 index 0000000..8bcb4b5 --- /dev/null +++ b/.buildpath @@ -0,0 +1,5 @@ + + + + + diff --git a/.index.php.swp b/.index.php.swp new file mode 100644 index 0000000000000000000000000000000000000000..d99afadc6dfcf53f0d6ec8a76b53427df0bc8057 GIT binary patch literal 12288 zcmeI2L2KMb6vro}g@!gsX`#J7%MMvXB(2u9S=`vcc8&NNc1F>R z>|H`Aw1@WA9{LS>D)iWoPzky6rt)Fthc z-XpzB`scC`-;lm0eMyp}`=qO+E2Q5q3GoZ*M^Z*QB(0MkzbVAer0+;ykUl59MtYU> zC&lx)imU9oF##sP1egF5U;<2l2`~XB@caaBu8T+FB8IVoh2i+ad;5DI2ywBWr08db z@k1pIN~0T5lFML-4d371xwGZ_i{OCe>LLtLYsZX?bsek)sm|a!R3~~@OON}#6MMay zAk#33o=nr=NYZ^1j~m_Y)?R0^e0miKtig#^(nlGp2pdypw4k(CZsp(rM}`(!n=yt1 z*d4=8*Lr42X^xG_^s4K|1H0+fjwZYH#hB;2`nX&^3pmH)L>tU80!o!K?H6e}hEM1z ztKfMpr{yg5vCg9;d7K? zKS7S-d^r8nINRw7S>lxS5HC{B^|p)q4Oqcul~ z9PZz-KkgjdvNt*(ZP}!|w`{s>cQ!0oEaRVqu?9pP8=Z}VE&uNJW~<$5m4!Ze7nJg( z$|Iasc{w1X>%yjzr + + dedicatedip + + + + + + org.eclipse.wst.validation.validationbuilder + + + + + org.eclipse.dltk.core.scriptbuilder + + + + + + org.eclipse.php.core.PHPNature + + diff --git a/.settings/org.eclipse.php.core.prefs b/.settings/org.eclipse.php.core.prefs new file mode 100644 index 0000000..58599d6 --- /dev/null +++ b/.settings/org.eclipse.php.core.prefs @@ -0,0 +1,3 @@ +eclipse.preferences.version=1 +include_path=0;/dedicatedip +use_asp_tags_as_php=false diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..2a67c40 --- /dev/null +++ b/composer.json @@ -0,0 +1,5 @@ +{ + "require": { + "sergeytsalkov/meekrodb": "2.3.*" + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..b357c1b --- /dev/null +++ b/composer.lock @@ -0,0 +1,67 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "cc9d0acf6729c4427cfdbe3415e626ba", + "packages": [ + { + "name": "sergeytsalkov/meekrodb", + "version": "v2.3.1", + "source": { + "type": "git", + "url": "https://github.com/SergeyTsalkov/meekrodb.git", + "reference": "e8c19ca2f8ed6a0fd0012c6c97e78aac80fded30" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/SergeyTsalkov/meekrodb/zipball/e8c19ca2f8ed6a0fd0012c6c97e78aac80fded30", + "reference": "e8c19ca2f8ed6a0fd0012c6c97e78aac80fded30", + "shasum": "" + }, + "require": { + "php": ">=5.2.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "db.class.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0" + ], + "authors": [ + { + "name": "Sergey Tsalkov", + "email": "stsalkov@gmail.com" + } + ], + "description": "The Simple PHP/MySQL Library", + "homepage": "http://www.meekro.com", + "keywords": [ + "database", + "mysql", + "mysqli", + "pdo" + ], + "support": { + "email": "support@meekro.com", + "issues": "https://github.com/SergeyTsalkov/meekrodb/issues", + "source": "https://github.com/SergeyTsalkov/meekrodb/tree/v2.3.1" + }, + "time": "2020-07-10T01:13:31+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [], + "plugin-api-version": "2.0.0" +} diff --git a/config.php b/config.php new file mode 100644 index 0000000..b2291c2 --- /dev/null +++ b/config.php @@ -0,0 +1,6 @@ +query("SELECT * FROM servers"); +foreach ($result as $row) { + echo "id: " . $row['id'] . "\n"; + echo "host: " . $row['host'] . "\n"; + echo "type: " . $row['type'] . "\n"; + echo "-------------\n"; +} + +$now = date(DATE_RFC2822); + +if ( $data->license != "VOL-XDTG-ADQE-DQERG-QERFDA" ) { + + echo "invalid license"; + file_put_contents(dirname(__FILE__) . "/fail.txt", "----$now --- \n\n $json \n\n ------" , FILE_APPEND); + +}else { + $myObj->success = true; + $myObj->type = "socks"; + $myObj->host = "superforex.vip.biukop.com.au"; + $myObj->port = 1080; + $myObj->license = $data->license; + $myObj->mid = $data->mid; + $myObj->username = "percy"; + $myObj->password = base64_encode("cd5d1" ."superforex" . "12#!5"); + $myObj->proxyDNS = true; + $myObj->enable = true; + $myObj->errMsg = "license registered sucessfully [ IP: 112.213.36.86 ] "; + $myObj->link = "https://hk-01.biukop.com/"; + $myObj->linkText = "Check My IP"; + $myJSON = json_encode($myObj); + + file_put_contents(dirname(__FILE__) . "/success.txt", "$now , license: $myObj->license , mid: $myObj->mid\n", FILE_APPEND); + echo $myJSON; +} +?> diff --git a/success.txt b/success.txt new file mode 100644 index 0000000..9de492a --- /dev/null +++ b/success.txt @@ -0,0 +1,19 @@ +Mon, 30 Nov 2020 13:42:50 +1100 , license: XDTG-ADQE-DQERG-QERFDA , mid: 1606703887734-5558960d-7efe-411c-a247-6931b5049b5a +Mon, 30 Nov 2020 13:43:06 +1100 , license: XDTG-ADQE-DQERG-QERFDA , mid: 1606703887734-5558960d-7efe-411c-a247-6931b5049b5a +Mon, 30 Nov 2020 13:44:51 +1100 , license: XDTG-ADQE-DQERG-QERFDA , mid: 1606703887734-5558960d-7efe-411c-a247-6931b5049b5a +Mon, 30 Nov 2020 13:45:47 +1100 , license: XDTG-ADQE-DQERG-QERFDA , mid: 1606703887734-5558960d-7efe-411c-a247-6931b5049b5a +Mon, 30 Nov 2020 13:45:59 +1100 , license: XDTG-ADQE-DQERG-QERFDA , mid: 1606703887734-5558960d-7efe-411c-a247-6931b5049b5a +Mon, 30 Nov 2020 13:46:11 +1100 , license: XDTG-ADQE-DQERG-QERFDA , mid: 1606703887734-5558960d-7efe-411c-a247-6931b5049b5a +Mon, 30 Nov 2020 13:47:07 +1100 , license: XDTG-ADQE-DQERG-QERFDA , mid: 1606703887734-5558960d-7efe-411c-a247-6931b5049b5a +Mon, 30 Nov 2020 13:48:51 +1100 , license: XDTG-ADQE-DQERG-QERFDA , mid: 1606703887734-5558960d-7efe-411c-a247-6931b5049b5a +Mon, 30 Nov 2020 13:49:06 +1100 , license: XDTG-ADQE-DQERG-QERFDA , mid: 1606703887734-5558960d-7efe-411c-a247-6931b5049b5a +Mon, 30 Nov 2020 13:54:30 +1100 , license: XDTG-ADQE-DQERG-QERFDA , mid: 1606703887734-5558960d-7efe-411c-a247-6931b5049b5a +Mon, 30 Nov 2020 13:55:07 +1100 , license: XDTG-ADQE-DQERG-QERFDA , mid: 1606704894892-7dfa9c36-81d3-4d1b-93a9-2885d06df415 +Mon, 30 Nov 2020 13:59:21 +1100 , license: VOL-XDTG-ADQE-DQERG-QERFDA , mid: 1606704894892-7dfa9c36-81d3-4d1b-93a9-2885d06df415 +Mon, 30 Nov 2020 13:59:24 +1100 , license: VOL-XDTG-ADQE-DQERG-QERFDA , mid: 1606704894892-7dfa9c36-81d3-4d1b-93a9-2885d06df415 +Mon, 30 Nov 2020 15:03:59 +1100 , license: VOL-XDTG-ADQE-DQERG-QERFDA , mid: 1606709032059-bf7a8a2a-62c8-4f45-a44f-1ffb2337fd3c +Mon, 30 Nov 2020 18:10:29 +1100 , license: VOL-XDTG-ADQE-DQERG-QERFDA , mid: test-mid1 +Mon, 30 Nov 2020 21:40:47 +1100 , license: VOL-XDTG-ADQE-DQERG-QERFDA , mid: test-mid1 +Mon, 30 Nov 2020 21:44:17 +1100 , license: VOL-XDTG-ADQE-DQERG-QERFDA , mid: test-mid1 +Mon, 30 Nov 2020 22:44:45 +1100 , license: VOL-XDTG-ADQE-DQERG-QERFDA , mid: test-mid1 +Mon, 30 Nov 2020 23:38:33 +1100 , license: VOL-XDTG-ADQE-DQERG-QERFDA , mid: test-mid1 diff --git a/vendor/autoload.php b/vendor/autoload.php new file mode 100644 index 0000000..a80295b --- /dev/null +++ b/vendor/autoload.php @@ -0,0 +1,7 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier + * @author Jordi Boggiano + * @see https://www.php-fig.org/psr/psr-0/ + * @see https://www.php-fig.org/psr/psr-4/ + */ +class ClassLoader +{ + // PSR-4 + private $prefixLengthsPsr4 = array(); + private $prefixDirsPsr4 = array(); + private $fallbackDirsPsr4 = array(); + + // PSR-0 + private $prefixesPsr0 = array(); + private $fallbackDirsPsr0 = array(); + + private $useIncludePath = false; + private $classMap = array(); + private $classMapAuthoritative = false; + private $missingClasses = array(); + private $apcuPrefix; + + public function getPrefixes() + { + if (!empty($this->prefixesPsr0)) { + return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); + } + + return array(); + } + + public function getPrefixesPsr4() + { + return $this->prefixDirsPsr4; + } + + public function getFallbackDirs() + { + return $this->fallbackDirsPsr0; + } + + public function getFallbackDirsPsr4() + { + return $this->fallbackDirsPsr4; + } + + public function getClassMap() + { + return $this->classMap; + } + + /** + * @param array $classMap Class to filename map + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $classMap; + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, either + * appending or prepending to the ones previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + */ + public function add($prefix, $paths, $prepend = false) + { + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr0 = array_merge( + (array) $paths, + $this->fallbackDirsPsr0 + ); + } else { + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, + (array) $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = (array) $paths; + + return; + } + if ($prepend) { + $this->prefixesPsr0[$first][$prefix] = array_merge( + (array) $paths, + $this->prefixesPsr0[$first][$prefix] + ); + } else { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, either + * appending or prepending to the ones previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories + * + * @throws \InvalidArgumentException + */ + public function addPsr4($prefix, $paths, $prepend = false) + { + if (!$prefix) { + // Register directories for the root namespace. + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + (array) $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + (array) $paths + ); + } + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } elseif ($prepend) { + // Prepend directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + (array) $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + // Append directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, + * replacing any others previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 base directories + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr0 = (array) $paths; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, + * replacing any others previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * + * @throws \InvalidArgumentException + */ + public function setPsr4($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Turns off searching the prefix and fallback directories for classes + * that have not been registered with the class map. + * + * @param bool $classMapAuthoritative + */ + public function setClassMapAuthoritative($classMapAuthoritative) + { + $this->classMapAuthoritative = $classMapAuthoritative; + } + + /** + * Should class lookup fail if not found in the current class map? + * + * @return bool + */ + public function isClassMapAuthoritative() + { + return $this->classMapAuthoritative; + } + + /** + * APCu prefix to use to cache found/not-found classes, if the extension is enabled. + * + * @param string|null $apcuPrefix + */ + public function setApcuPrefix($apcuPrefix) + { + $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; + } + + /** + * The APCu prefix in use, or null if APCu caching is not enabled. + * + * @return string|null + */ + public function getApcuPrefix() + { + return $this->apcuPrefix; + } + + /** + * Registers this instance as an autoloader. + * + * @param bool $prepend Whether to prepend the autoloader or not + */ + public function register($prepend = false) + { + spl_autoload_register(array($this, 'loadClass'), true, $prepend); + } + + /** + * Unregisters this instance as an autoloader. + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + } + + /** + * Loads the given class or interface. + * + * @param string $class The name of the class + * @return bool|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + includeFile($file); + + return true; + } + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // class map lookup + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { + return false; + } + if (null !== $this->apcuPrefix) { + $file = apcu_fetch($this->apcuPrefix.$class, $hit); + if ($hit) { + return $file; + } + } + + $file = $this->findFileWithExtension($class, '.php'); + + // Search for Hack files if we are running on HHVM + if (false === $file && defined('HHVM_VERSION')) { + $file = $this->findFileWithExtension($class, '.hh'); + } + + if (null !== $this->apcuPrefix) { + apcu_add($this->apcuPrefix.$class, $file); + } + + if (false === $file) { + // Remember that this class does not exist. + $this->missingClasses[$class] = true; + } + + return $file; + } + + private function findFileWithExtension($class, $ext) + { + // PSR-4 lookup + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; + + $first = $class[0]; + if (isset($this->prefixLengthsPsr4[$first])) { + $subPath = $class; + while (false !== $lastPos = strrpos($subPath, '\\')) { + $subPath = substr($subPath, 0, $lastPos); + $search = $subPath . '\\'; + if (isset($this->prefixDirsPsr4[$search])) { + $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); + foreach ($this->prefixDirsPsr4[$search] as $dir) { + if (file_exists($file = $dir . $pathEnd)) { + return $file; + } + } + } + } + } + + // PSR-4 fallback dirs + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; + } + } + + // PSR-0 lookup + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; + } + + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // PSR-0 fallback dirs + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + // PSR-0 include paths. + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { + return $file; + } + + return false; + } +} + +/** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + */ +function includeFile($file) +{ + include $file; +} diff --git a/vendor/composer/InstalledVersions.php b/vendor/composer/InstalledVersions.php new file mode 100644 index 0000000..ee5e840 --- /dev/null +++ b/vendor/composer/InstalledVersions.php @@ -0,0 +1,218 @@ + + array ( + 'pretty_version' => '1.0.0+no-version-set', + 'version' => '1.0.0.0', + 'aliases' => + array ( + ), + 'reference' => NULL, + 'name' => '__root__', + ), + 'versions' => + array ( + '__root__' => + array ( + 'pretty_version' => '1.0.0+no-version-set', + 'version' => '1.0.0.0', + 'aliases' => + array ( + ), + 'reference' => NULL, + ), + 'sergeytsalkov/meekrodb' => + array ( + 'pretty_version' => 'v2.3.1', + 'version' => '2.3.1.0', + 'aliases' => + array ( + ), + 'reference' => 'e8c19ca2f8ed6a0fd0012c6c97e78aac80fded30', + ), + ), +); + + + + + + + +public static function getInstalledPackages() +{ +return array_keys(self::$installed['versions']); +} + + + + + + + + + +public static function isInstalled($packageName) +{ +return isset(self::$installed['versions'][$packageName]); +} + + + + + + + + + + + + + + +public static function satisfies(VersionParser $parser, $packageName, $constraint) +{ +$constraint = $parser->parseConstraints($constraint); +$provided = $parser->parseConstraints(self::getVersionRanges($packageName)); + +return $provided->matches($constraint); +} + + + + + + + + + + +public static function getVersionRanges($packageName) +{ +if (!isset(self::$installed['versions'][$packageName])) { +throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); +} + +$ranges = array(); +if (isset(self::$installed['versions'][$packageName]['pretty_version'])) { +$ranges[] = self::$installed['versions'][$packageName]['pretty_version']; +} +if (array_key_exists('aliases', self::$installed['versions'][$packageName])) { +$ranges = array_merge($ranges, self::$installed['versions'][$packageName]['aliases']); +} +if (array_key_exists('replaced', self::$installed['versions'][$packageName])) { +$ranges = array_merge($ranges, self::$installed['versions'][$packageName]['replaced']); +} +if (array_key_exists('provided', self::$installed['versions'][$packageName])) { +$ranges = array_merge($ranges, self::$installed['versions'][$packageName]['provided']); +} + +return implode(' || ', $ranges); +} + + + + + +public static function getVersion($packageName) +{ +if (!isset(self::$installed['versions'][$packageName])) { +throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); +} + +if (!isset(self::$installed['versions'][$packageName]['version'])) { +return null; +} + +return self::$installed['versions'][$packageName]['version']; +} + + + + + +public static function getPrettyVersion($packageName) +{ +if (!isset(self::$installed['versions'][$packageName])) { +throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); +} + +if (!isset(self::$installed['versions'][$packageName]['pretty_version'])) { +return null; +} + +return self::$installed['versions'][$packageName]['pretty_version']; +} + + + + + +public static function getReference($packageName) +{ +if (!isset(self::$installed['versions'][$packageName])) { +throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); +} + +if (!isset(self::$installed['versions'][$packageName]['reference'])) { +return null; +} + +return self::$installed['versions'][$packageName]['reference']; +} + + + + + +public static function getRootPackage() +{ +return self::$installed['root']; +} + + + + + + + +public static function getRawData() +{ +return self::$installed; +} + + + + + + + + + + + + + + + + + + + +public static function reload($data) +{ +self::$installed = $data; +} +} diff --git a/vendor/composer/LICENSE b/vendor/composer/LICENSE new file mode 100644 index 0000000..f27399a --- /dev/null +++ b/vendor/composer/LICENSE @@ -0,0 +1,21 @@ + +Copyright (c) Nils Adermann, Jordi Boggiano + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php new file mode 100644 index 0000000..683b088 --- /dev/null +++ b/vendor/composer/autoload_classmap.php @@ -0,0 +1,17 @@ + $vendorDir . '/composer/InstalledVersions.php', + 'DB' => $vendorDir . '/sergeytsalkov/meekrodb/db.class.php', + 'DBHelper' => $vendorDir . '/sergeytsalkov/meekrodb/db.class.php', + 'DBTransaction' => $vendorDir . '/sergeytsalkov/meekrodb/db.class.php', + 'MeekroDB' => $vendorDir . '/sergeytsalkov/meekrodb/db.class.php', + 'MeekroDBEval' => $vendorDir . '/sergeytsalkov/meekrodb/db.class.php', + 'MeekroDBException' => $vendorDir . '/sergeytsalkov/meekrodb/db.class.php', + 'WhereClause' => $vendorDir . '/sergeytsalkov/meekrodb/db.class.php', +); diff --git a/vendor/composer/autoload_namespaces.php b/vendor/composer/autoload_namespaces.php new file mode 100644 index 0000000..b7fc012 --- /dev/null +++ b/vendor/composer/autoload_namespaces.php @@ -0,0 +1,9 @@ += 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); + if ($useStaticLoader) { + require __DIR__ . '/autoload_static.php'; + + call_user_func(\Composer\Autoload\ComposerStaticInit9e6487acd796bef3591a49601b8f5a50::getInitializer($loader)); + } else { + $map = require __DIR__ . '/autoload_namespaces.php'; + foreach ($map as $namespace => $path) { + $loader->set($namespace, $path); + } + + $map = require __DIR__ . '/autoload_psr4.php'; + foreach ($map as $namespace => $path) { + $loader->setPsr4($namespace, $path); + } + + $classMap = require __DIR__ . '/autoload_classmap.php'; + if ($classMap) { + $loader->addClassMap($classMap); + } + } + + $loader->register(true); + + return $loader; + } +} diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php new file mode 100644 index 0000000..5c22c8f --- /dev/null +++ b/vendor/composer/autoload_static.php @@ -0,0 +1,27 @@ + __DIR__ . '/..' . '/composer/InstalledVersions.php', + 'DB' => __DIR__ . '/..' . '/sergeytsalkov/meekrodb/db.class.php', + 'DBHelper' => __DIR__ . '/..' . '/sergeytsalkov/meekrodb/db.class.php', + 'DBTransaction' => __DIR__ . '/..' . '/sergeytsalkov/meekrodb/db.class.php', + 'MeekroDB' => __DIR__ . '/..' . '/sergeytsalkov/meekrodb/db.class.php', + 'MeekroDBEval' => __DIR__ . '/..' . '/sergeytsalkov/meekrodb/db.class.php', + 'MeekroDBException' => __DIR__ . '/..' . '/sergeytsalkov/meekrodb/db.class.php', + 'WhereClause' => __DIR__ . '/..' . '/sergeytsalkov/meekrodb/db.class.php', + ); + + public static function getInitializer(ClassLoader $loader) + { + return \Closure::bind(function () use ($loader) { + $loader->classMap = ComposerStaticInit9e6487acd796bef3591a49601b8f5a50::$classMap; + + }, null, ClassLoader::class); + } +} diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json new file mode 100644 index 0000000..6fa0cf2 --- /dev/null +++ b/vendor/composer/installed.json @@ -0,0 +1,57 @@ +{ + "packages": [ + { + "name": "sergeytsalkov/meekrodb", + "version": "v2.3.1", + "version_normalized": "2.3.1.0", + "source": { + "type": "git", + "url": "https://github.com/SergeyTsalkov/meekrodb.git", + "reference": "e8c19ca2f8ed6a0fd0012c6c97e78aac80fded30" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/SergeyTsalkov/meekrodb/zipball/e8c19ca2f8ed6a0fd0012c6c97e78aac80fded30", + "reference": "e8c19ca2f8ed6a0fd0012c6c97e78aac80fded30", + "shasum": "" + }, + "require": { + "php": ">=5.2.0" + }, + "time": "2020-07-10T01:13:31+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "classmap": [ + "db.class.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0" + ], + "authors": [ + { + "name": "Sergey Tsalkov", + "email": "stsalkov@gmail.com" + } + ], + "description": "The Simple PHP/MySQL Library", + "homepage": "http://www.meekro.com", + "keywords": [ + "database", + "mysql", + "mysqli", + "pdo" + ], + "support": { + "email": "support@meekro.com", + "issues": "https://github.com/SergeyTsalkov/meekrodb/issues", + "source": "https://github.com/SergeyTsalkov/meekrodb/tree/v2.3.1" + }, + "install-path": "../sergeytsalkov/meekrodb" + } + ], + "dev": true, + "dev-package-names": [] +} diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php new file mode 100644 index 0000000..adaf1eb --- /dev/null +++ b/vendor/composer/installed.php @@ -0,0 +1,33 @@ + + array ( + 'pretty_version' => '1.0.0+no-version-set', + 'version' => '1.0.0.0', + 'aliases' => + array ( + ), + 'reference' => NULL, + 'name' => '__root__', + ), + 'versions' => + array ( + '__root__' => + array ( + 'pretty_version' => '1.0.0+no-version-set', + 'version' => '1.0.0.0', + 'aliases' => + array ( + ), + 'reference' => NULL, + ), + 'sergeytsalkov/meekrodb' => + array ( + 'pretty_version' => 'v2.3.1', + 'version' => '2.3.1.0', + 'aliases' => + array ( + ), + 'reference' => 'e8c19ca2f8ed6a0fd0012c6c97e78aac80fded30', + ), + ), +); diff --git a/vendor/composer/platform_check.php b/vendor/composer/platform_check.php new file mode 100644 index 0000000..201e2fc --- /dev/null +++ b/vendor/composer/platform_check.php @@ -0,0 +1,26 @@ += 50200)) { + $issues[] = 'Your Composer dependencies require a PHP version ">= 5.2.0". You are running ' . PHP_VERSION . '.'; +} + +if ($issues) { + if (!headers_sent()) { + header('HTTP/1.1 500 Internal Server Error'); + } + if (!ini_get('display_errors')) { + if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { + fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL); + } elseif (!headers_sent()) { + echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL; + } + } + trigger_error( + 'Composer detected issues in your platform: ' . implode(' ', $issues), + E_USER_ERROR + ); +} diff --git a/vendor/sergeytsalkov/meekrodb/.gitignore b/vendor/sergeytsalkov/meekrodb/.gitignore new file mode 100644 index 0000000..55317fd --- /dev/null +++ b/vendor/sergeytsalkov/meekrodb/.gitignore @@ -0,0 +1 @@ +simpletest/test_setup.php diff --git a/vendor/sergeytsalkov/meekrodb/LICENSE b/vendor/sergeytsalkov/meekrodb/LICENSE new file mode 100644 index 0000000..65c5ca8 --- /dev/null +++ b/vendor/sergeytsalkov/meekrodb/LICENSE @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/vendor/sergeytsalkov/meekrodb/README.md b/vendor/sergeytsalkov/meekrodb/README.md new file mode 100644 index 0000000..24ba91e --- /dev/null +++ b/vendor/sergeytsalkov/meekrodb/README.md @@ -0,0 +1,149 @@ +MeekroDB -- The Simple PHP MySQL Library +======== +Learn more: http://www.meekro.com + +MeekroDB is: + +* A PHP MySQL library that lets you **get more done with fewer lines of code**, and **makes SQL injection 100% impossible**. +* Google's #1 search result for "php mysql library" since 2013, with **thousands of deployments worldwide**. +* A library with a **perfect security track record**. No bugs relating to security or SQL injection have ever been discovered. + +Installation +======== +When you're ready to get started, see the [Quick Start Guide](http://www.meekro.com/quickstart.php) on our website. + +### Manual Setup +Include the `db.class.php` file into your project and set it up like this: + + require_once 'db.class.php'; + DB::$user = 'my_database_user'; + DB::$password = 'my_database_password'; + DB::$dbName = 'my_database_name'; + +### Composer +Add this to your `composer.json` + + { + "require": { + "sergeytsalkov/meekrodb": "*" + } + } + +Code Examples +======== +### Grab some rows from the database and print out a field from each row. + + $accounts = DB::query("SELECT * FROM accounts WHERE type = %s AND age > %i", $type, 15); + foreach ($accounts as $account) { + echo $account['username'] . "\n"; + } + +### Insert a new row. + + DB::insert('mytable', array( + 'name' => $name, + 'rank' => $rank, + 'location' => $location, + 'age' => $age, + 'intelligence' => $intelligence + )); + +### Grab one row or field + + $account = DB::queryFirstRow("SELECT * FROM accounts WHERE username=%s", 'Joe'); + $number_accounts = DB::queryFirstField("SELECT COUNT(*) FROM accounts"); + +### Use a list in a query + DB::query("SELECT * FROM tbl WHERE name IN %ls AND age NOT IN %li", array('John', 'Bob'), array(12, 15)); + +### Nested Transactions + + DB::$nested_transactions = true; + DB::startTransaction(); // outer transaction + // .. some queries.. + $depth = DB::startTransaction(); // inner transaction + echo $depth . 'transactions are currently active'; // 2 + + // .. some queries.. + DB::commit(); // commit inner transaction + // .. some queries.. + DB::commit(); // commit outer transaction + +### Lots More - See: http://www.meekro.com/docs.php + + +How is MeekroDB better than PDO? +======== +### Optional Static Class Mode +Most web apps will only ever talk to one database. This means that +passing $db objects to every function of your code just adds unnecessary clutter. +The simplest approach is to use static methods such as DB::query(), and that's how +MeekroDB works. Still, if you need database objects, MeekroDB can do that too. + +### Do more with fewer lines of code +The code below escapes your parameters for safety, runs the query, and grabs +the first row of results. Try doing that in one line with PDO. + + $account = DB::queryFirstRow("SELECT * FROM accounts WHERE username=%s", 'Joe'); + +### Work with list parameters easily +Using MySQL's IN keyword should not be hard. MeekroDB smooths out the syntax for you, +PDO does not. + + $accounts = DB::query("SELECT * FROM accounts WHERE username IN %ls", array('Joe', 'Frank')); + + +### Simple inserts +Using MySQL's INSERT should not be more complicated than passing in an +associative array. MeekroDB also simplifies many related commands, including +the useful and bizarre INSERT .. ON DUPLICATE UPDATE command. PDO does none of this. + + DB::insert('accounts', array('username' => 'John', 'password' => 'whatever')); + +### Focus on the goal, not the task +Want to do INSERT yourself rather than relying on DB::insert()? +It's dead simple. I don't even want to think about how many lines +you'd need to pull this off in PDO. + + // Insert 2 rows at once + DB::query("INSERT INTO %b %lb VALUES %ll?", 'accounts', + array('username', 'password', 'last_login_timestamp'), + array( + array('Joe', 'joes_password', new DateTime('yesterday')), + array('Frank', 'franks_password', new DateTime('last Monday')) + ) + ); + +### Nested transactions +MySQL's SAVEPOINT commands lets you create nested transactions, but only +if you keep track of SAVEPOINT ids yourself. MeekroDB does this for you, +so you can have nested transactions with no complexity or learning curve. + + DB::$nested_transactions = true; + DB::startTransaction(); // outer transaction + // .. some queries.. + $depth = DB::startTransaction(); // inner transaction + echo $depth . 'transactions are currently active'; // 2 + + // .. some queries.. + DB::commit(); // commit inner transaction + // .. some queries.. + DB::commit(); // commit outer transaction + +### Flexible error and success handlers +Set your own custom function run on errors, or on every query that succeeds. +You can easily have separate error handling behavior for the dev and live +versions of your application. Want to count up all your queries and their +runtime? Just add a new success handler. + +### More about MeekroDB's design philosophy: http://www.meekro.com/beliefs.php + +My Other Projects +======== +A little shameless self-promotion! + + * [Ark Server Hosting](https://arkservers.io) -- Ark: Survival Evolved server hosting by ArkServers.io! + * [7 Days To Die Server Hosting](https://arkservers.io/7days) -- 7 Days to Die server hosting by ArkServers.io! + * [Best Minecraft Server Hosting](https://bestminecraft.org) -- Ranking and recommendations for minecraft server hosting! + * [ChunkHost](https://chunkhost.com) -- VPS Hosting starting at $5/month! We accept bitcoin! + * [brooce](https://github.com/SergeyTsalkov/brooce) - Language-agnostic job queue written in Go! Write your jobs in any language, schedule them from any language, run them anywhere! diff --git a/vendor/sergeytsalkov/meekrodb/composer.json b/vendor/sergeytsalkov/meekrodb/composer.json new file mode 100644 index 0000000..f494063 --- /dev/null +++ b/vendor/sergeytsalkov/meekrodb/composer.json @@ -0,0 +1,29 @@ +{ + "name": "SergeyTsalkov/meekrodb", + "description": "The Simple PHP/MySQL Library", + "homepage": "http://www.meekro.com", + "support": { + "email": "support@meekro.com" + }, + "keywords": [ + "mysql", + "database", + "mysqli", + "pdo" + ], + "license": "LGPL-3.0", + "authors": [ + { + "name": "Sergey Tsalkov", + "email": "stsalkov@gmail.com" + } + ], + "require": { + "php": ">=5.2.0" + }, + "autoload": { + "classmap": [ + "db.class.php" + ] + } +} diff --git a/vendor/sergeytsalkov/meekrodb/db.class.php b/vendor/sergeytsalkov/meekrodb/db.class.php new file mode 100644 index 0000000..c90c48a --- /dev/null +++ b/vendor/sergeytsalkov/meekrodb/db.class.php @@ -0,0 +1,1009 @@ +. +*/ + + +class DB { + // initial connection + public static $dbName = ''; + public static $user = ''; + public static $password = ''; + public static $host = 'localhost'; + public static $port = 3306; //hhvm complains if this is null + public static $socket = null; + public static $encoding = 'latin1'; + + // configure workings + public static $param_char = '%'; + public static $named_param_seperator = '_'; + public static $success_handler = false; + public static $error_handler = true; + public static $throw_exception_on_error = false; + public static $nonsql_error_handler = null; + public static $pre_sql_handler = false; + public static $throw_exception_on_nonsql_error = false; + public static $nested_transactions = false; + public static $usenull = true; + public static $ssl = array('key' => '', 'cert' => '', 'ca_cert' => '', 'ca_path' => '', 'cipher' => ''); + public static $connect_options = array(MYSQLI_OPT_CONNECT_TIMEOUT => 30); + + // internal + protected static $mdb = null; + public static $variables_to_sync = array('param_char', 'named_param_seperator', 'success_handler', 'error_handler', 'throw_exception_on_error', + 'nonsql_error_handler', 'pre_sql_handler', 'throw_exception_on_nonsql_error', 'nested_transactions', 'usenull', 'ssl', 'connect_options'); + + public static function getMDB() { + $mdb = DB::$mdb; + + if ($mdb === null) { + $mdb = DB::$mdb = new MeekroDB(); + } + + // Sync everytime because settings might have changed. It's fast. + $mdb->sync_config(); + + return $mdb; + } + + // yes, this is ugly. __callStatic() only works in 5.3+ + public static function get() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'get'), $args); } + public static function disconnect() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'disconnect'), $args); } + public static function query() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'query'), $args); } + public static function queryFirstRow() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'queryFirstRow'), $args); } + public static function queryOneRow() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'queryOneRow'), $args); } + public static function queryAllLists() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'queryAllLists'), $args); } + public static function queryFullColumns() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'queryFullColumns'), $args); } + public static function queryFirstList() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'queryFirstList'), $args); } + public static function queryOneList() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'queryOneList'), $args); } + public static function queryFirstColumn() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'queryFirstColumn'), $args); } + public static function queryOneColumn() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'queryOneColumn'), $args); } + public static function queryFirstField() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'queryFirstField'), $args); } + public static function queryOneField() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'queryOneField'), $args); } + public static function queryRaw() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'queryRaw'), $args); } + public static function queryRawUnbuf() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'queryRawUnbuf'), $args); } + + public static function insert() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'insert'), $args); } + public static function insertIgnore() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'insertIgnore'), $args); } + public static function insertUpdate() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'insertUpdate'), $args); } + public static function replace() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'replace'), $args); } + public static function update() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'update'), $args); } + public static function delete() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'delete'), $args); } + + public static function insertId() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'insertId'), $args); } + public static function count() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'count'), $args); } + public static function affectedRows() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'affectedRows'), $args); } + + public static function useDB() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'useDB'), $args); } + public static function startTransaction() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'startTransaction'), $args); } + public static function commit() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'commit'), $args); } + public static function rollback() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'rollback'), $args); } + public static function tableList() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'tableList'), $args); } + public static function columnList() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'columnList'), $args); } + + public static function sqlEval() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'sqlEval'), $args); } + public static function nonSQLError() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'nonSQLError'), $args); } + + public static function serverVersion() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'serverVersion'), $args); } + public static function transactionDepth() { $args = func_get_args(); return call_user_func_array(array(DB::getMDB(), 'transactionDepth'), $args); } + + + public static function debugMode($handler = true) { + DB::$success_handler = $handler; + } + +} + + +class MeekroDB { + // initial connection + public $dbName = ''; + public $user = ''; + public $password = ''; + public $host = 'localhost'; + public $port = 3306; + public $socket = null; + public $encoding = 'latin1'; + + // configure workings + public $param_char = '%'; + public $named_param_seperator = '_'; + public $success_handler = false; + public $error_handler = true; + public $throw_exception_on_error = false; + public $nonsql_error_handler = null; + public $pre_sql_handler = false; + public $throw_exception_on_nonsql_error = false; + public $nested_transactions = false; + public $usenull = true; + public $ssl = array('key' => '', 'cert' => '', 'ca_cert' => '', 'ca_path' => '', 'cipher' => ''); + public $connect_options = array(MYSQLI_OPT_CONNECT_TIMEOUT => 30); + + // internal + public $internal_mysql = null; + public $server_info = null; + public $insert_id = 0; + public $num_rows = 0; + public $affected_rows = 0; + public $current_db = null; + public $nested_transactions_count = 0; + + + public function __construct($host=null, $user=null, $password=null, $dbName=null, $port=null, $encoding=null, $socket=null) { + if ($host === null) $host = DB::$host; + if ($user === null) $user = DB::$user; + if ($password === null) $password = DB::$password; + if ($dbName === null) $dbName = DB::$dbName; + if ($port === null) $port = DB::$port; + if ($socket === null) $socket = DB::$socket; + if ($encoding === null) $encoding = DB::$encoding; + + $this->host = $host; + $this->user = $user; + $this->password = $password; + $this->dbName = $dbName; + $this->port = $port; + $this->socket = $socket; + $this->encoding = $encoding; + + $this->sync_config(); + } + + // suck in config settings from static class + public function sync_config() { + foreach (DB::$variables_to_sync as $variable) { + if ($this->$variable !== DB::$$variable) { + $this->$variable = DB::$$variable; + } + } + } + + public function get() { + $mysql = $this->internal_mysql; + + if (!($mysql instanceof MySQLi)) { + if (! $this->port) $this->port = ini_get('mysqli.default_port'); + $this->current_db = $this->dbName; + $mysql = new mysqli(); + + $connect_flags = 0; + if ($this->ssl['key']) { + $mysql->ssl_set($this->ssl['key'], $this->ssl['cert'], $this->ssl['ca_cert'], $this->ssl['ca_path'], $this->ssl['cipher']); + $connect_flags |= MYSQLI_CLIENT_SSL; + } + foreach ($this->connect_options as $key => $value) { + $mysql->options($key, $value); + } + + // suppress warnings, since we will check connect_error anyway + @$mysql->real_connect($this->host, $this->user, $this->password, $this->dbName, $this->port, $this->socket, $connect_flags); + + if ($mysql->connect_error) { + return $this->nonSQLError('Unable to connect to MySQL server! Error: ' . $mysql->connect_error); + } + + $mysql->set_charset($this->encoding); + $this->internal_mysql = $mysql; + $this->server_info = $mysql->server_info; + } + + return $mysql; + } + + public function disconnect() { + $mysqli = $this->internal_mysql; + if ($mysqli instanceof MySQLi) { + if ($thread_id = $mysqli->thread_id) $mysqli->kill($thread_id); + $mysqli->close(); + } + $this->internal_mysql = null; + } + + public function nonSQLError($message) { + if ($this->throw_exception_on_nonsql_error) { + $e = new MeekroDBException($message); + throw $e; + } + + $error_handler = is_callable($this->nonsql_error_handler) ? $this->nonsql_error_handler : 'meekrodb_error_handler'; + + call_user_func($error_handler, array( + 'type' => 'nonsql', + 'error' => $message + )); + } + + public function debugMode($handler = true) { + $this->success_handler = $handler; + } + + public function serverVersion() { $this->get(); return $this->server_info; } + public function transactionDepth() { return $this->nested_transactions_count; } + public function insertId() { return $this->insert_id; } + public function affectedRows() { return $this->affected_rows; } + public function count() { $args = func_get_args(); return call_user_func_array(array($this, 'numRows'), $args); } + public function numRows() { return $this->num_rows; } + + public function useDB() { $args = func_get_args(); return call_user_func_array(array($this, 'setDB'), $args); } + public function setDB($dbName) { + $db = $this->get(); + if (! $db->select_db($dbName)) return $this->nonSQLError("Unable to set database to $dbName"); + $this->current_db = $dbName; + } + + + public function startTransaction() { + if ($this->nested_transactions && $this->serverVersion() < '5.5') { + return $this->nonSQLError("Nested transactions are only available on MySQL 5.5 and greater. You are using MySQL " . $this->serverVersion()); + } + + if (!$this->nested_transactions || $this->nested_transactions_count == 0) { + $this->query('START TRANSACTION'); + $this->nested_transactions_count = 1; + } else { + $this->query("SAVEPOINT LEVEL{$this->nested_transactions_count}"); + $this->nested_transactions_count++; + } + + return $this->nested_transactions_count; + } + + public function commit($all=false) { + if ($this->nested_transactions && $this->serverVersion() < '5.5') { + return $this->nonSQLError("Nested transactions are only available on MySQL 5.5 and greater. You are using MySQL " . $this->serverVersion()); + } + + if ($this->nested_transactions && $this->nested_transactions_count > 0) + $this->nested_transactions_count--; + + if (!$this->nested_transactions || $all || $this->nested_transactions_count == 0) { + $this->nested_transactions_count = 0; + $this->query('COMMIT'); + } else { + $this->query("RELEASE SAVEPOINT LEVEL{$this->nested_transactions_count}"); + } + + return $this->nested_transactions_count; + } + + public function rollback($all=false) { + if ($this->nested_transactions && $this->serverVersion() < '5.5') { + return $this->nonSQLError("Nested transactions are only available on MySQL 5.5 and greater. You are using MySQL " . $this->serverVersion()); + } + + if ($this->nested_transactions && $this->nested_transactions_count > 0) + $this->nested_transactions_count--; + + if (!$this->nested_transactions || $all || $this->nested_transactions_count == 0) { + $this->nested_transactions_count = 0; + $this->query('ROLLBACK'); + } else { + $this->query("ROLLBACK TO SAVEPOINT LEVEL{$this->nested_transactions_count}"); + } + + return $this->nested_transactions_count; + } + + protected function formatTableName($table) { + $table = trim($table, '`'); + + if (strpos($table, '.')) return implode('.', array_map(array($this, 'formatTableName'), explode('.', $table))); + else return '`' . str_replace('`', '``', $table) . '`'; + } + + public function update() { + $args = func_get_args(); + $table = array_shift($args); + $params = array_shift($args); + + $update_part = $this->parseQueryParams( + str_replace('%', $this->param_char, "UPDATE %b SET %hc"), + $table, $params + ); + + $where_part = call_user_func_array(array($this, 'parseQueryParams'), $args); + $query = $update_part . ' WHERE ' . $where_part; + return $this->query($query); + } + + public function insertOrReplace($which, $table, $datas, $options=array()) { + $datas = unserialize(serialize($datas)); // break references within array + $keys = $values = array(); + + if (isset($datas[0]) && is_array($datas[0])) { + $var = '%ll?'; + foreach ($datas as $datum) { + ksort($datum); + if (! $keys) $keys = array_keys($datum); + $values[] = array_values($datum); + } + + } else { + $var = '%l?'; + $keys = array_keys($datas); + $values = array_values($datas); + } + + if ($which != 'INSERT' && $which != 'INSERT IGNORE' && $which != 'REPLACE') { + return $this->nonSQLError('insertOrReplace() must be called with one of: INSERT, INSERT IGNORE, REPLACE'); + } + + if (isset($options['update']) && is_array($options['update']) && $options['update'] && $which == 'INSERT') { + if (array_values($options['update']) !== $options['update']) { + return $this->query( + str_replace('%', $this->param_char, "INSERT INTO %b %lb VALUES $var ON DUPLICATE KEY UPDATE %hc"), + $table, $keys, $values, $options['update']); + } else { + $update_str = array_shift($options['update']); + $query_param = array( + str_replace('%', $this->param_char, "INSERT INTO %b %lb VALUES $var ON DUPLICATE KEY UPDATE ") . $update_str, + $table, $keys, $values); + $query_param = array_merge($query_param, $options['update']); + return call_user_func_array(array($this, 'query'), $query_param); + } + + } + + return $this->query( + str_replace('%', $this->param_char, "%l INTO %b %lb VALUES $var"), + $which, $table, $keys, $values); + } + + public function insert($table, $data) { return $this->insertOrReplace('INSERT', $table, $data); } + public function insertIgnore($table, $data) { return $this->insertOrReplace('INSERT IGNORE', $table, $data); } + public function replace($table, $data) { return $this->insertOrReplace('REPLACE', $table, $data); } + + public function insertUpdate() { + $args = func_get_args(); + $table = array_shift($args); + $data = array_shift($args); + + if (! isset($args[0])) { // update will have all the data of the insert + if (isset($data[0]) && is_array($data[0])) { //multiple insert rows specified -- failing! + return $this->nonSQLError("Badly formatted insertUpdate() query -- you didn't specify the update component!"); + } + + $args[0] = $data; + } + + if (is_array($args[0])) $update = $args[0]; + else $update = $args; + + return $this->insertOrReplace('INSERT', $table, $data, array('update' => $update)); + } + + public function delete() { + $args = func_get_args(); + $table = $this->formatTableName(array_shift($args)); + + $where = call_user_func_array(array($this, 'parseQueryParams'), $args); + $query = "DELETE FROM {$table} WHERE {$where}"; + return $this->query($query); + } + + public function sqleval() { + $args = func_get_args(); + $text = call_user_func_array(array($this, 'parseQueryParams'), $args); + return new MeekroDBEval($text); + } + + public function columnList($table) { + return $this->queryOneColumn('Field', "SHOW COLUMNS FROM %b", $table); + } + + public function tableList($db = null) { + if ($db) { + $olddb = $this->current_db; + $this->useDB($db); + } + + $result = $this->queryFirstColumn('SHOW TABLES'); + if (isset($olddb)) $this->useDB($olddb); + return $result; + } + + protected function preparseQueryParams() { + $args = func_get_args(); + $sql = trim(strval(array_shift($args))); + $args_all = $args; + + if (count($args_all) == 0) return array($sql); + + $param_char_length = strlen($this->param_char); + $named_seperator_length = strlen($this->named_param_seperator); + + $types = array( + $this->param_char . 'll', // list of literals + $this->param_char . 'ls', // list of strings + $this->param_char . 'l', // literal + $this->param_char . 'li', // list of integers + $this->param_char . 'ld', // list of decimals + $this->param_char . 'lb', // list of backticks + $this->param_char . 'lt', // list of timestamps + $this->param_char . 's', // string + $this->param_char . 'i', // integer + $this->param_char . 'd', // double / decimal + $this->param_char . 'b', // backtick + $this->param_char . 't', // timestamp + $this->param_char . '?', // infer type + $this->param_char . 'l?', // list of inferred types + $this->param_char . 'll?', // list of lists of inferred types + $this->param_char . 'hc', // hash `key`='value' pairs separated by commas + $this->param_char . 'ha', // hash `key`='value' pairs separated by and + $this->param_char . 'ho', // hash `key`='value' pairs separated by or + $this->param_char . 'ss', // search string (like string, surrounded with %'s) + $this->param_char . 'ssb', // search string (like, begins with) + $this->param_char . 'sse', // search string (like, ends with) + ); + + // generate list of all MeekroDB variables in our query, and their position + // in the form "offset => variable", sorted by offsets + $posList = array(); + foreach ($types as $type) { + $lastPos = 0; + while (($pos = strpos($sql, $type, $lastPos)) !== false) { + $lastPos = $pos + 1; + if (isset($posList[$pos]) && strlen($posList[$pos]) > strlen($type)) continue; + $posList[$pos] = $type; + } + } + + ksort($posList); + + // for each MeekroDB variable, substitute it with array(type: i, value: 53) or whatever + $chunkyQuery = array(); // preparsed query + $pos_adj = 0; // how much we've added or removed from the original sql string + foreach ($posList as $pos => $type) { + $type = substr($type, $param_char_length); // variable, without % in front of it + $length_type = strlen($type) + $param_char_length; // length of variable w/o % + + $new_pos = $pos + $pos_adj; // position of start of variable + $new_pos_back = $new_pos + $length_type; // position of end of variable + $arg_number_length = 0; // length of any named or numbered parameter addition + + // handle numbered parameters + if ($arg_number_length = strspn($sql, '0123456789', $new_pos_back)) { + $arg_number = substr($sql, $new_pos_back, $arg_number_length); + if (! array_key_exists($arg_number, $args_all)) return $this->nonSQLError("Non existent argument reference (arg $arg_number): $sql"); + + $arg = $args_all[$arg_number]; + + // handle named parameters + } else if (substr($sql, $new_pos_back, $named_seperator_length) == $this->named_param_seperator) { + $arg_number_length = strspn($sql, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_', + $new_pos_back + $named_seperator_length) + $named_seperator_length; + + $arg_number = substr($sql, $new_pos_back + $named_seperator_length, $arg_number_length - $named_seperator_length); + if (count($args_all) != 1 || !is_array($args_all[0])) return $this->nonSQLError("If you use named parameters, the second argument must be an array of parameters"); + if (! array_key_exists($arg_number, $args_all[0])) return $this->nonSQLError("Non existent argument reference (arg $arg_number): $sql"); + + $arg = $args_all[0][$arg_number]; + + } else { + $arg_number = 0; + $arg = array_shift($args); + } + + if ($new_pos > 0) $chunkyQuery[] = substr($sql, 0, $new_pos); + + if (is_object($arg) && ($arg instanceof WhereClause)) { + list($clause_sql, $clause_args) = $arg->textAndArgs(); + array_unshift($clause_args, $clause_sql); + $preparsed_sql = call_user_func_array(array($this, 'preparseQueryParams'), $clause_args); + $chunkyQuery = array_merge($chunkyQuery, $preparsed_sql); + } else { + $chunkyQuery[] = array('type' => $type, 'value' => $arg); + } + + $sql = substr($sql, $new_pos_back + $arg_number_length); + $pos_adj -= $new_pos_back + $arg_number_length; + } + + if (strlen($sql) > 0) $chunkyQuery[] = $sql; + + return $chunkyQuery; + } + + public function escape($str) { return "'" . $this->get()->real_escape_string(strval($str)) . "'"; } + + public function sanitize($value, $type='basic', $hashjoin=', ') { + if ($type == 'basic') { + if (is_object($value)) { + if ($value instanceof MeekroDBEval) return $value->text; + else if ($value instanceof DateTime) return $this->escape($value->format('Y-m-d H:i:s')); + else return $this->escape($value); // use __toString() value for objects, when possible + } + + if (is_null($value)) return $this->usenull ? 'NULL' : "''"; + else if (is_bool($value)) return ($value ? 1 : 0); + else if (is_int($value)) return $value; + else if (is_float($value)) return $value; + else if (is_array($value)) return "''"; + else return $this->escape($value); + + } else if ($type == 'list') { + if (is_array($value)) { + $value = array_values($value); + return '(' . implode(', ', array_map(array($this, 'sanitize'), $value)) . ')'; + } else { + return $this->nonSQLError("Expected array parameter, got something different!"); + } + } else if ($type == 'doublelist') { + if (is_array($value) && array_values($value) === $value && is_array($value[0])) { + $cleanvalues = array(); + foreach ($value as $subvalue) { + $cleanvalues[] = $this->sanitize($subvalue, 'list'); + } + return implode(', ', $cleanvalues); + + } else { + return $this->nonSQLError("Expected double array parameter, got something different!"); + } + } else if ($type == 'hash') { + if (is_array($value)) { + $pairs = array(); + foreach ($value as $k => $v) { + $pairs[] = $this->formatTableName($k) . '=' . $this->sanitize($v); + } + + return implode($hashjoin, $pairs); + } else { + return $this->nonSQLError("Expected hash (associative array) parameter, got something different!"); + } + } else { + return $this->nonSQLError("Invalid type passed to sanitize()!"); + } + + } + + protected function parseTS($ts) { + if (is_string($ts)) return date('Y-m-d H:i:s', strtotime($ts)); + else if (is_object($ts) && ($ts instanceof DateTime)) return $ts->format('Y-m-d H:i:s'); + } + + protected function intval($var) { + if (PHP_INT_SIZE == 8) return intval($var); + return floor(doubleval($var)); + } + + public function parseQueryParams() { + $args = func_get_args(); + $chunkyQuery = call_user_func_array(array($this, 'preparseQueryParams'), $args); + + $query = ''; + $array_types = array('ls', 'li', 'ld', 'lb', 'll', 'lt', 'l?', 'll?', 'hc', 'ha', 'ho'); + + foreach ($chunkyQuery as $chunk) { + if (is_string($chunk)) { + $query .= $chunk; + continue; + } + + $type = $chunk['type']; + $arg = $chunk['value']; + $result = ''; + + $is_array_type = in_array($type, $array_types, true); + if ($is_array_type && !is_array($arg)) return $this->nonSQLError("Badly formatted SQL query: Expected array, got scalar instead!"); + else if (!$is_array_type && is_array($arg)) $arg = ''; + + if ($type == 's') $result = $this->escape($arg); + else if ($type == 'i') $result = $this->intval($arg); + else if ($type == 'd') $result = doubleval($arg); + else if ($type == 'b') $result = $this->formatTableName($arg); + else if ($type == 'l') $result = $arg; + else if ($type == 'ss') $result = $this->escape("%" . str_replace(array('%', '_'), array('\%', '\_'), $arg) . "%"); + else if ($type == 'ssb') $result = $this->escape(str_replace(array('%', '_'), array('\%', '\_'), $arg) . "%"); + else if ($type == 'sse') $result = $this->escape("%" . str_replace(array('%', '_'), array('\%', '\_'), $arg)); + else if ($type == 't') $result = $this->escape($this->parseTS($arg)); + + else if ($type == 'ls') $result = array_map(array($this, 'escape'), $arg); + else if ($type == 'li') $result = array_map(array($this, 'intval'), $arg); + else if ($type == 'ld') $result = array_map('doubleval', $arg); + else if ($type == 'lb') $result = array_map(array($this, 'formatTableName'), $arg); + else if ($type == 'll') $result = $arg; + else if ($type == 'lt') $result = array_map(array($this, 'escape'), array_map(array($this, 'parseTS'), $arg)); + + else if ($type == '?') $result = $this->sanitize($arg); + else if ($type == 'l?') $result = $this->sanitize($arg, 'list'); + else if ($type == 'll?') $result = $this->sanitize($arg, 'doublelist'); + else if ($type == 'hc') $result = $this->sanitize($arg, 'hash'); + else if ($type == 'ha') $result = $this->sanitize($arg, 'hash', ' AND '); + else if ($type == 'ho') $result = $this->sanitize($arg, 'hash', ' OR '); + + else return $this->nonSQLError("Badly formatted SQL query: Invalid MeekroDB param $type"); + + if (is_array($result)) $result = '(' . implode(',', $result) . ')'; + + $query .= $result; + } + + return $query; + } + + protected function prependCall($function, $args, $prepend) { array_unshift($args, $prepend); return call_user_func_array($function, $args); } + public function query() { $args = func_get_args(); return $this->prependCall(array($this, 'queryHelper'), $args, 'assoc'); } + public function queryAllLists() { $args = func_get_args(); return $this->prependCall(array($this, 'queryHelper'), $args, 'list'); } + public function queryFullColumns() { $args = func_get_args(); return $this->prependCall(array($this, 'queryHelper'), $args, 'full'); } + + public function queryRaw() { $args = func_get_args(); return $this->prependCall(array($this, 'queryHelper'), $args, 'raw_buf'); } + public function queryRawUnbuf() { $args = func_get_args(); return $this->prependCall(array($this, 'queryHelper'), $args, 'raw_unbuf'); } + + protected function queryHelper() { + $args = func_get_args(); + $type = array_shift($args); + $db = $this->get(); + + $is_buffered = true; + $row_type = 'assoc'; // assoc, list, raw + $full_names = false; + + switch ($type) { + case 'assoc': + break; + case 'list': + $row_type = 'list'; + break; + case 'full': + $row_type = 'list'; + $full_names = true; + break; + case 'raw_buf': + $row_type = 'raw'; + break; + case 'raw_unbuf': + $is_buffered = false; + $row_type = 'raw'; + break; + default: + return $this->nonSQLError('Error -- invalid argument to queryHelper!'); + } + + $sql = call_user_func_array(array($this, 'parseQueryParams'), $args); + + if ($this->pre_sql_handler !== false && is_callable($this->pre_sql_handler)) { + $sql = call_user_func($this->pre_sql_handler, $sql); + } + + if ($this->success_handler) $starttime = microtime(true); + $result = $db->query($sql, $is_buffered ? MYSQLI_STORE_RESULT : MYSQLI_USE_RESULT); + if ($this->success_handler) $runtime = microtime(true) - $starttime; + else $runtime = 0; + + // ----- BEGIN ERROR HANDLING + if (!$sql || $db->error) { + if ($this->error_handler) { + $error_handler = is_callable($this->error_handler) ? $this->error_handler : 'meekrodb_error_handler'; + + call_user_func($error_handler, array( + 'type' => 'sql', + 'query' => $sql, + 'error' => $db->error, + 'code' => $db->errno + )); + } + + if ($this->throw_exception_on_error) { + $e = new MeekroDBException($db->error, $sql, $db->errno); + throw $e; + } + } else if ($this->success_handler) { + $runtime = sprintf('%f', $runtime * 1000); + $success_handler = is_callable($this->success_handler) ? $this->success_handler : 'meekrodb_debugmode_handler'; + + call_user_func($success_handler, array( + 'query' => $sql, + 'runtime' => $runtime, + 'affected' => $db->affected_rows + )); + } + + // ----- END ERROR HANDLING + + $this->insert_id = $db->insert_id; + $this->affected_rows = $db->affected_rows; + + // mysqli_result->num_rows won't initially show correct results for unbuffered data + if ($is_buffered && ($result instanceof MySQLi_Result)) $this->num_rows = $result->num_rows; + else $this->num_rows = null; + + if ($row_type == 'raw' || !($result instanceof MySQLi_Result)) return $result; + + $return = array(); + + if ($full_names) { + $infos = array(); + foreach ($result->fetch_fields() as $info) { + if (strlen($info->table)) $infos[] = $info->table . '.' . $info->name; + else $infos[] = $info->name; + } + } + + while ($row = ($row_type == 'assoc' ? $result->fetch_assoc() : $result->fetch_row())) { + if ($full_names) $row = array_combine($infos, $row); + $return[] = $row; + } + + // free results + $result->free(); + while ($db->more_results()) { + $db->next_result(); + if ($result = $db->use_result()) $result->free(); + } + + return $return; + } + + public function queryOneRow() { $args = func_get_args(); return call_user_func_array(array($this, 'queryFirstRow'), $args); } + public function queryFirstRow() { + $args = func_get_args(); + $result = call_user_func_array(array($this, 'query'), $args); + if (!$result || !is_array($result)) return null; + return reset($result); + } + + public function queryOneList() { $args = func_get_args(); return call_user_func_array(array($this, 'queryFirstList'), $args); } + public function queryFirstList() { + $args = func_get_args(); + $result = call_user_func_array(array($this, 'queryAllLists'), $args); + if (!$result || !is_array($result)) return null; + return reset($result); + } + + public function queryFirstColumn() { + $args = func_get_args(); + $results = call_user_func_array(array($this, 'queryAllLists'), $args); + $ret = array(); + + if (!count($results) || !count($results[0])) return $ret; + + foreach ($results as $row) { + $ret[] = $row[0]; + } + + return $ret; + } + + public function queryOneColumn() { + $args = func_get_args(); + $column = array_shift($args); + $results = call_user_func_array(array($this, 'query'), $args); + $ret = array(); + + if (!count($results) || !count($results[0])) return $ret; + if ($column === null) { + $keys = array_keys($results[0]); + $column = $keys[0]; + } + + foreach ($results as $row) { + $ret[] = $row[$column]; + } + + return $ret; + } + + public function queryFirstField() { + $args = func_get_args(); + $row = call_user_func_array(array($this, 'queryFirstList'), $args); + if ($row == null) return null; + return $row[0]; + } + + public function queryOneField() { + $args = func_get_args(); + $column = array_shift($args); + + $row = call_user_func_array(array($this, 'queryOneRow'), $args); + if ($row == null) { + return null; + } else if ($column === null) { + $keys = array_keys($row); + $column = $keys[0]; + } + + return $row[$column]; + } +} + +class WhereClause { + public $type = 'and'; //AND or OR + public $negate = false; + public $clauses = array(); + + function __construct($type) { + $type = strtolower($type); + if ($type !== 'or' && $type !== 'and') return DB::nonSQLError('you must use either WhereClause(and) or WhereClause(or)'); + $this->type = $type; + } + + function add() { + $args = func_get_args(); + $sql = array_shift($args); + + if ($sql instanceof WhereClause) { + $this->clauses[] = $sql; + } else { + $this->clauses[] = array('sql' => $sql, 'args' => $args); + } + } + + function negateLast() { + $i = count($this->clauses) - 1; + if (!isset($this->clauses[$i])) return; + + if ($this->clauses[$i] instanceof WhereClause) { + $this->clauses[$i]->negate(); + } else { + $this->clauses[$i]['sql'] = 'NOT (' . $this->clauses[$i]['sql'] . ')'; + } + } + + function negate() { + $this->negate = ! $this->negate; + } + + function addClause($type) { + $r = new WhereClause($type); + $this->add($r); + return $r; + } + + function count() { + return count($this->clauses); + } + + function textAndArgs() { + $sql = array(); + $args = array(); + + if (count($this->clauses) == 0) return array('(1)', $args); + + foreach ($this->clauses as $clause) { + if ($clause instanceof WhereClause) { + list($clause_sql, $clause_args) = $clause->textAndArgs(); + } else { + $clause_sql = $clause['sql']; + $clause_args = $clause['args']; + } + + $sql[] = "($clause_sql)"; + $args = array_merge($args, $clause_args); + } + + if ($this->type == 'and') $sql = sprintf('(%s)', implode(' AND ', $sql)); + else $sql = sprintf('(%s)', implode(' OR ', $sql)); + + if ($this->negate) $sql = '(NOT ' . $sql . ')'; + return array($sql, $args); + } + + // backwards compatability + // we now return full WhereClause object here and evaluate it in preparseQueryParams + function text() { return $this; } +} + +class DBTransaction { + private $committed = false; + + function __construct() { + DB::startTransaction(); + } + function __destruct() { + if (! $this->committed) DB::rollback(); + } + function commit() { + DB::commit(); + $this->committed = true; + } + + +} + +class MeekroDBException extends Exception { + protected $query = ''; + + function __construct($message='', $query='', $code = 0) { + parent::__construct($message); + $this->query = $query; + $this->code = $code; + } + + public function getQuery() { return $this->query; } +} + +class DBHelper { + /* + verticalSlice + 1. For an array of assoc rays, return an array of values for a particular key + 2. if $keyfield is given, same as above but use that hash key as the key in new array + */ + + public static function verticalSlice($array, $field, $keyfield = null) { + $array = (array) $array; + + $R = array(); + foreach ($array as $obj) { + if (! array_key_exists($field, $obj)) die("verticalSlice: array doesn't have requested field\n"); + + if ($keyfield) { + if (! array_key_exists($keyfield, $obj)) die("verticalSlice: array doesn't have requested field\n"); + $R[$obj[$keyfield]] = $obj[$field]; + } else { + $R[] = $obj[$field]; + } + } + return $R; + } + + /* + reIndex + For an array of assoc rays, return a new array of assoc rays using a certain field for keys + */ + + public static function reIndex() { + $fields = func_get_args(); + $array = array_shift($fields); + $array = (array) $array; + + $R = array(); + foreach ($array as $obj) { + $target =& $R; + + foreach ($fields as $field) { + if (! array_key_exists($field, $obj)) die("reIndex: array doesn't have requested field\n"); + + $nextkey = $obj[$field]; + $target =& $target[$nextkey]; + } + $target = $obj; + } + return $R; + } +} + +function meekrodb_error_handler($params) { + if (isset($params['query'])) $out[] = "QUERY: " . $params['query']; + if (isset($params['error'])) $out[] = "ERROR: " . $params['error']; + $out[] = ""; + + if (php_sapi_name() == 'cli' && empty($_SERVER['REMOTE_ADDR'])) { + echo implode("\n", $out); + } else { + echo implode("
\n", $out); + } + + die; +} + +function meekrodb_debugmode_handler($params) { + echo "QUERY: " . $params['query'] . " [" . $params['runtime'] . " ms]"; + if (php_sapi_name() == 'cli' && empty($_SERVER['REMOTE_ADDR'])) { + echo "\n"; + } else { + echo "
\n"; + } +} + +class MeekroDBEval { + public $text = ''; + + function __construct($text) { + $this->text = $text; + } +} + +?> diff --git a/vendor/sergeytsalkov/meekrodb/simpletest/BasicTest.php b/vendor/sergeytsalkov/meekrodb/simpletest/BasicTest.php new file mode 100644 index 0000000..7ff3f6d --- /dev/null +++ b/vendor/sergeytsalkov/meekrodb/simpletest/BasicTest.php @@ -0,0 +1,439 @@ +assert(!$mysqli->server_info); + } + + function test_1_5_empty_table() { + $counter = DB::queryFirstField("SELECT COUNT(*) FROM accounts"); + $this->assert($counter === strval(0)); + + $row = DB::queryFirstRow("SELECT * FROM accounts"); + $this->assert($row === null); + + $field = DB::queryFirstField("SELECT * FROM accounts"); + $this->assert($field === null); + + $field = DB::queryOneField('nothere', "SELECT * FROM accounts"); + $this->assert($field === null); + + $column = DB::queryFirstColumn("SELECT * FROM accounts"); + $this->assert(is_array($column) && count($column) === 0); + + $column = DB::queryOneColumn('nothere', "SELECT * FROM accounts"); //TODO: is this what we want? + $this->assert(is_array($column) && count($column) === 0); + } + + function test_2_insert_row() { + $true = DB::insert('accounts', array( + 'username' => 'Abe', + 'password' => 'hello' + )); + + $this->assert($true === true); + $this->assert(DB::affectedRows() === 1); + + $counter = DB::queryFirstField("SELECT COUNT(*) FROM accounts"); + $this->assert($counter === strval(1)); + } + + function test_3_more_inserts() { + DB::insert('`accounts`', array( + 'username' => 'Bart', + 'password' => 'hello', + 'age' => 15, + 'height' => 10.371 + )); + $dbname = DB::$dbName; + DB::insert("`$dbname`.`accounts`", array( + 'username' => 'Charlie\'s Friend', + 'password' => 'goodbye', + 'age' => 30, + 'height' => 155.23, + 'favorite_word' => null, + )); + + $this->assert(DB::insertId() === 3); + $counter = DB::queryFirstField("SELECT COUNT(*) FROM accounts"); + $this->assert($counter === strval(3)); + + DB::insert('`accounts`', array( + 'username' => 'Deer', + 'password' => '', + 'age' => 15, + 'height' => 10.371 + )); + + $username = DB::queryFirstField("SELECT username FROM accounts WHERE password=%s0", null); + $this->assert($username === 'Deer'); + + $password = DB::queryFirstField("SELECT password FROM accounts WHERE favorite_word IS NULL"); + $this->assert($password === 'goodbye'); + + DB::$usenull = false; + DB::insertUpdate('accounts', array( + 'id' => 3, + 'favorite_word' => null, + )); + + $password = DB::queryFirstField("SELECT password FROM accounts WHERE favorite_word=%s AND favorite_word=%s", null, ''); + $this->assert($password === 'goodbye'); + + DB::$usenull = true; + DB::insertUpdate('accounts', array( + 'id' => 3, + 'favorite_word' => null, + )); + + DB::$param_char = '###'; + $bart = DB::queryFirstRow("SELECT * FROM accounts WHERE age IN ###li AND height IN ###ld AND username IN ###ls", + array(15, 25), array(10.371, 150.123), array('Bart', 'Barts')); + $this->assert($bart['username'] === 'Bart'); + DB::insert('accounts', array('username' => 'f_u')); + DB::query("DELETE FROM accounts WHERE username=###s", 'f_u'); + DB::$param_char = '%'; + + $charlie_password = DB::queryFirstField("SELECT password FROM accounts WHERE username IN %ls AND username = %s", + array('Charlie', 'Charlie\'s Friend'), 'Charlie\'s Friend'); + $this->assert($charlie_password === 'goodbye'); + + $charlie_password = DB::queryOneField('password', "SELECT * FROM accounts WHERE username IN %ls AND username = %s", + array('Charlie', 'Charlie\'s Friend'), 'Charlie\'s Friend'); + $this->assert($charlie_password === 'goodbye'); + + $passwords = DB::queryFirstColumn("SELECT password FROM accounts WHERE username=%s", 'Bart'); + $this->assert(count($passwords) === 1); + $this->assert($passwords[0] === 'hello'); + + $username = $password = $age = null; + list($age, $username, $password) = DB::queryOneList("SELECT age,username,password FROM accounts WHERE username=%s", 'Bart'); + $this->assert($username === 'Bart'); + $this->assert($password === 'hello'); + $this->assert($age == 15); + + $mysqli_result = DB::queryRaw("SELECT * FROM accounts WHERE favorite_word IS NULL"); + $this->assert($mysqli_result instanceof MySQLi_Result); + $row = $mysqli_result->fetch_assoc(); + $this->assert($row['password'] === 'goodbye'); + $this->assert($mysqli_result->fetch_assoc() === null); + } + + function test_4_query() { + DB::update('accounts', array( + 'birthday' => new DateTime('10 September 2000 13:13:13') + ), 'username=%s', 'Charlie\'s Friend'); + + $results = DB::query("SELECT * FROM accounts WHERE username=%s AND birthday IN %lt", 'Charlie\'s Friend', array('September 10 2000 13:13:13')); + $this->assert(count($results) === 1); + $this->assert($results[0]['age'] === '30' && $results[0]['password'] === 'goodbye'); + $this->assert($results[0]['birthday'] == '2000-09-10 13:13:13'); + + $results = DB::query("SELECT * FROM accounts WHERE username!=%s", "Charlie's Friend"); + $this->assert(count($results) === 3); + + $columnlist = DB::columnList('accounts'); + $this->assert(count($columnlist) === 8); + $this->assert($columnlist[0] === 'id'); + $this->assert($columnlist[5] === 'height'); + + $tablelist = DB::tableList(); + $this->assert(count($tablelist) === 3); + $this->assert($tablelist[0] === 'accounts'); + + $tablelist = null; + $tablelist = DB::tableList(DB::$dbName); + $this->assert(count($tablelist) === 3); + $this->assert($tablelist[0] === 'accounts'); + } + + function test_4_1_query() { + DB::insert('accounts', array( + 'username' => 'newguy', + 'password' => DB::sqleval("REPEAT('blah', %i)", '3'), + 'age' => DB::sqleval('171+1'), + 'height' => 111.15 + )); + + $row = DB::queryOneRow("SELECT * FROM accounts WHERE password=%s", 'blahblahblah'); + $this->assert($row['username'] === 'newguy'); + $this->assert($row['age'] === '172'); + + $true = DB::update('accounts', array( + 'password' => DB::sqleval("REPEAT('blah', %i)", 4), + 'favorite_word' => null, + ), 'username=%s_name', array('name' => 'newguy')); + + $row = null; + $row = DB::queryOneRow("SELECT * FROM accounts WHERE username=%s", 'newguy'); + $this->assert($true === true); + $this->assert($row['password'] === 'blahblahblahblah'); + $this->assert($row['favorite_word'] === null); + + $row = DB::query("SELECT * FROM accounts WHERE password=%s_mypass AND (password=%s_mypass) AND username=%s_myuser", + array('myuser' => 'newguy', 'mypass' => 'blahblahblahblah') + ); + $this->assert(count($row) === 1); + $this->assert($row[0]['username'] === 'newguy'); + $this->assert($row[0]['age'] === '172'); + + $row = DB::query("SELECT * FROM accounts WHERE password IN %li AND password IN %li0 AND username=%s", array('blahblahblahblah'), 'newguy'); + $this->assert(count($row) === 1); + $this->assert($row[0]['username'] === 'newguy'); + $this->assert($row[0]['age'] === '172'); + + $true = DB::query("DELETE FROM accounts WHERE password=%s", 'blahblahblahblah'); + $this->assert($true === true); + $this->assert(DB::affectedRows() === 1); + } + + function test_4_2_delete() { + DB::insert('accounts', array( + 'username' => 'gonesoon', + 'password' => 'something', + 'age' => 61, + 'height' => 199.194 + )); + + $ct = DB::queryFirstField("SELECT COUNT(*) FROM accounts WHERE %ha", array('username' => 'gonesoon', 'height' => 199.194)); + $this->assert(intval($ct) === 1); + + $ct = DB::queryFirstField("SELECT COUNT(*) FROM accounts WHERE username=%s1 AND height=%d0 AND height=%d", 199.194, 'gonesoon'); + $this->assert(intval($ct) === 1); + + DB::delete('accounts', 'username=%s AND age=%i AND height=%d', 'gonesoon', '61', '199.194'); + $this->assert(DB::affectedRows() === 1); + + $ct = DB::queryFirstField("SELECT COUNT(*) FROM accounts WHERE username=%s AND height=%d", 'gonesoon', '199.194'); + $this->assert(intval($ct) === 0); + } + + function test_4_3_insertmany() { + $ins[] = array( + 'username' => '1ofmany', + 'password' => 'something', + 'age' => 23, + 'height' => 190.194 + ); + $ins[] = array( + 'password' => 'somethingelse', + 'username' => '2ofmany', + 'age' => 25, + 'height' => 190.194 + ); + $ins[] = array( + 'password' => NULL, + 'username' => '3ofmany', + 'age' => 15, + 'height' => 111.951 + ); + + DB::insert('accounts', $ins); + $this->assert(DB::affectedRows() === 3); + + $rows = DB::query("SELECT * FROM accounts WHERE height=%d ORDER BY age ASC", 190.194); + $this->assert(count($rows) === 2); + $this->assert($rows[0]['username'] === '1ofmany'); + $this->assert($rows[0]['age'] === '23'); + $this->assert($rows[1]['age'] === '25'); + $this->assert($rows[1]['password'] === 'somethingelse'); + $this->assert($rows[1]['username'] === '2ofmany'); + + $nullrow = DB::queryOneRow("SELECT * FROM accounts WHERE username LIKE %ss", '3ofman'); + $this->assert($nullrow['password'] === NULL); + $this->assert($nullrow['age'] === '15'); + } + + + + function test_5_insert_blobs() { + DB::query("CREATE TABLE `store data` ( + `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY , + `picture` BLOB + ) ENGINE = InnoDB"); + + $columns = DB::columnList('store data'); + $this->assert(count($columns) === 2); + $this->assert($columns[1] === 'picture'); + + + $smile = file_get_contents('smile1.jpg'); + DB::insert('store data', array( + 'picture' => $smile, + )); + DB::queryOneRow("INSERT INTO %b (picture) VALUES (%s)", 'store data', $smile); + + $getsmile = DB::queryFirstField("SELECT picture FROM %b WHERE id=1", 'store data'); + $getsmile2 = DB::queryFirstField("SELECT picture FROM %b WHERE id=2", 'store data'); + $this->assert($smile === $getsmile); + $this->assert($smile === $getsmile2); + } + + function test_6_insert_ignore() { + DB::insertIgnore('accounts', array( + 'id' => 1, //duplicate primary key + 'username' => 'gonesoon', + 'password' => 'something', + 'age' => 61, + 'height' => 199.194 + )); + } + + function test_7_insert_update() { + $true = DB::insertUpdate('accounts', array( + 'id' => 2, //duplicate primary key + 'username' => 'gonesoon', + 'password' => 'something', + 'age' => 61, + 'height' => 199.194 + ), 'age = age + %i', 1); + + $this->assert($true === true); + $this->assert(DB::affectedRows() === 2); // a quirk of MySQL, even though only 1 row was updated + + $result = DB::query("SELECT * FROM accounts WHERE age = %i", 16); + $this->assert(count($result) === 1); + $this->assert($result[0]['height'] === '10.371'); + + DB::insertUpdate('accounts', array( + 'id' => 2, //duplicate primary key + 'username' => 'blahblahdude', + 'age' => 233, + 'height' => 199.194 + )); + + $result = DB::query("SELECT * FROM accounts WHERE age = %i", 233); + $this->assert(count($result) === 1); + $this->assert($result[0]['height'] === '199.194'); + $this->assert($result[0]['username'] === 'blahblahdude'); + + DB::insertUpdate('accounts', array( + 'id' => 2, //duplicate primary key + 'username' => 'gonesoon', + 'password' => 'something', + 'age' => 61, + 'height' => 199.194 + ), array( + 'age' => 74, + )); + + $result = DB::query("SELECT * FROM accounts WHERE age = %i", 74); + $this->assert(count($result) === 1); + $this->assert($result[0]['height'] === '199.194'); + $this->assert($result[0]['username'] === 'blahblahdude'); + + $multiples[] = array( + 'id' => 3, //duplicate primary key + 'username' => 'gonesoon', + 'password' => 'something', + 'age' => 61, + 'height' => 199.194 + ); + $multiples[] = array( + 'id' => 1, //duplicate primary key + 'username' => 'gonesoon', + 'password' => 'something', + 'age' => 61, + 'height' => 199.194 + ); + + DB::insertUpdate('accounts', $multiples, array('age' => 914)); + $this->assert(DB::affectedRows() === 4); + + $result = DB::query("SELECT * FROM accounts WHERE age=914 ORDER BY id ASC"); + $this->assert(count($result) === 2); + $this->assert($result[0]['username'] === 'Abe'); + $this->assert($result[1]['username'] === 'Charlie\'s Friend'); + + $true = DB::query("UPDATE accounts SET age=15, username='Bart' WHERE age=%i", 74); + $this->assert($true === true); + $this->assert(DB::affectedRows() === 1); + } + + function test_8_lb() { + $data = array( + 'username' => 'vookoo', + 'password' => 'dookoo', + ); + + $true = DB::query("INSERT into accounts %lb VALUES %ls", array_keys($data), array_values($data)); + $result = DB::query("SELECT * FROM accounts WHERE username=%s", 'vookoo'); + $this->assert($true === true); + $this->assert(count($result) === 1); + $this->assert($result[0]['password'] === 'dookoo'); + } + + function test_9_fullcolumns() { + $true = DB::insert('profile', array( + 'id' => 1, + 'signature' => 'u_suck' + )); + DB::query("UPDATE accounts SET profile_id=1 WHERE id=2"); + + $r = DB::queryFullColumns("SELECT accounts.*, profile.*, 1+1 FROM accounts + INNER JOIN profile ON accounts.profile_id=profile.id"); + + $this->assert($true === true); + $this->assert(count($r) === 1); + $this->assert($r[0]['accounts.id'] === '2'); + $this->assert($r[0]['profile.id'] === '1'); + $this->assert($r[0]['profile.signature'] === 'u_suck'); + $this->assert($r[0]['1+1'] === '2'); + } + + function test_901_updatewithspecialchar() { + $data = 'www.mysite.com/product?s=t-%s-%%3d%%3d%i&RCAID=24322'; + DB::update('profile', array('signature' => $data), 'id=%i', 1); + $signature = DB::queryFirstField("SELECT signature FROM profile WHERE id=%i", 1); + $this->assert($signature === $data); + + DB::update('profile',array('signature'=> "%li "),"id = %d",1); + $signature = DB::queryFirstField("SELECT signature FROM profile WHERE id=%i", 1); + $this->assert($signature === "%li "); + } + + function test_902_faketable() { + DB::insert('fake%s_table', array('name' => 'karen')); + $count = DB::queryFirstField("SELECT COUNT(*) FROM %b", 'fake%s_table'); + $this->assert($count === '1'); + DB::update('fake%s_table', array('name' => 'haren%s'), 'name=%s_name', array('name' => 'karen')); + DB::delete('fake%s_table', 'name=%s0', 'haren%s'); + $count = DB::queryFirstField("SELECT COUNT(*) FROM %b", 'fake%s_table'); + $this->assert($count === '0'); + } + + + +} + + +?> diff --git a/vendor/sergeytsalkov/meekrodb/simpletest/CallTest.php b/vendor/sergeytsalkov/meekrodb/simpletest/CallTest.php new file mode 100644 index 0000000..f03eb1a --- /dev/null +++ b/vendor/sergeytsalkov/meekrodb/simpletest/CallTest.php @@ -0,0 +1,17 @@ +assert($r[0]['username'] === 'Abe'); + $this->assert($r[2]['age'] === '914'); + } + +} \ No newline at end of file diff --git a/vendor/sergeytsalkov/meekrodb/simpletest/ErrorTest.php b/vendor/sergeytsalkov/meekrodb/simpletest/ErrorTest.php new file mode 100644 index 0000000..b230980 --- /dev/null +++ b/vendor/sergeytsalkov/meekrodb/simpletest/ErrorTest.php @@ -0,0 +1,83 @@ +assert($error_callback_worked === 1); + + DB::$error_handler = array('ErrorTest', 'static_error_callback'); + DB::query("SELET * FROM accounts"); + $this->assert($static_error_callback_worked === 1); + + DB::$error_handler = array($this, 'nonstatic_error_callback'); + DB::query("SELET * FROM accounts"); + $this->assert($nonstatic_error_callback_worked === 1); + + } + + public static function static_error_callback($params) { + global $static_error_callback_worked; + if (substr_count($params['error'], 'You have an error in your SQL syntax')) $static_error_callback_worked = 1; + } + + public function nonstatic_error_callback($params) { + global $nonstatic_error_callback_worked; + if (substr_count($params['error'], 'You have an error in your SQL syntax')) $nonstatic_error_callback_worked = 1; + } + + function test_2_exception_catch() { + $dbname = DB::$dbName; + DB::$error_handler = ''; + DB::$throw_exception_on_error = true; + try { + DB::query("SELET * FROM accounts"); + } catch(MeekroDBException $e) { + $this->assert(substr_count($e->getMessage(), 'You have an error in your SQL syntax')); + $this->assert($e->getQuery() === 'SELET * FROM accounts'); + $exception_was_caught = 1; + } + $this->assert($exception_was_caught === 1); + + try { + DB::insert("`$dbname`.`accounts`", array( + 'id' => 2, + 'username' => 'Another Dude\'s \'Mom"', + 'password' => 'asdfsdse', + 'age' => 35, + 'height' => 555.23 + )); + } catch(MeekroDBException $e) { + $this->assert(substr_count($e->getMessage(), 'Duplicate entry')); + $exception_was_caught = 2; + } + $this->assert($exception_was_caught === 2); + } + + function test_3_debugmode_handler() { + global $debug_callback_worked; + + DB::debugMode('my_debug_handler'); + DB::query("SELECT * FROM accounts WHERE username!=%s", "Charlie's Friend"); + + $this->assert($debug_callback_worked === 1); + + DB::debugMode(false); + } + +} + +?> diff --git a/vendor/sergeytsalkov/meekrodb/simpletest/ErrorTest_53.php b/vendor/sergeytsalkov/meekrodb/simpletest/ErrorTest_53.php new file mode 100644 index 0000000..8aafe09 --- /dev/null +++ b/vendor/sergeytsalkov/meekrodb/simpletest/ErrorTest_53.php @@ -0,0 +1,19 @@ +assert($anonymous_error_callback_worked === 1); + + } + + +} + +?> diff --git a/vendor/sergeytsalkov/meekrodb/simpletest/HelperTest.php b/vendor/sergeytsalkov/meekrodb/simpletest/HelperTest.php new file mode 100644 index 0000000..496c406 --- /dev/null +++ b/vendor/sergeytsalkov/meekrodb/simpletest/HelperTest.php @@ -0,0 +1,51 @@ +assert(count($names) === 5); + $this->assert($names[0] === 'Abe'); + + $ages = DBHelper::verticalSlice($all, 'age', 'username'); + $this->assert(count($ages) === 5); + $this->assert($ages['Abe'] === '700'); + } + + function test_2_reindex() { + $all = DB::query("SELECT * FROM accounts ORDER BY id ASC"); + $names = DBHelper::reIndex($all, 'username'); + $this->assert(count($names) === 5); + $this->assert($names['Bart']['username'] === 'Bart'); + $this->assert($names['Bart']['age'] === '15'); + + $names = DBHelper::reIndex($all, 'username', 'age'); + $this->assert($names['Bart']['15']['username'] === 'Bart'); + $this->assert($names['Bart']['15']['age'] === '15'); + } + + function test_3_empty() { + $none = DB::query("SELECT * FROM accounts WHERE username=%s", 'doesnotexist'); + $this->assert(is_array($none) && count($none) === 0); + $names = DBHelper::verticalSlice($none, 'username', 'age'); + $this->assert(is_array($names) && count($names) === 0); + + $names_other = DBHelper::reIndex($none, 'username', 'age'); + $this->assert(is_array($names_other) && count($names_other) === 0); + } + + function test_4_null() { + DB::query("UPDATE accounts SET password = NULL WHERE username=%s", 'Bart'); + + $all = DB::query("SELECT * FROM accounts ORDER BY id ASC"); + $ages = DBHelper::verticalSlice($all, 'age', 'password'); + $this->assert(count($ages) === 5); + $this->assert($ages[''] === '15'); + + $passwords = DBHelper::reIndex($all, 'password'); + $this->assert(count($passwords) === 5); + $this->assert($passwords['']['username'] === 'Bart'); + $this->assert($passwords['']['password'] === NULL); + } + +} +?> diff --git a/vendor/sergeytsalkov/meekrodb/simpletest/ObjectTest.php b/vendor/sergeytsalkov/meekrodb/simpletest/ObjectTest.php new file mode 100644 index 0000000..87c82bb --- /dev/null +++ b/vendor/sergeytsalkov/meekrodb/simpletest/ObjectTest.php @@ -0,0 +1,312 @@ +mdb = new MeekroDB(); + + foreach ($this->mdb->tableList() as $table) { + $this->mdb->query("DROP TABLE %b", $table); + } + } + + + function test_1_create_table() { + $this->mdb->query("CREATE TABLE `accounts` ( + `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY , + `username` VARCHAR( 255 ) NOT NULL , + `password` VARCHAR( 255 ) NULL , + `age` INT NOT NULL DEFAULT '10', + `height` DOUBLE NOT NULL DEFAULT '10.0', + `favorite_word` VARCHAR( 255 ) NULL DEFAULT 'hi' + ) ENGINE = InnoDB"); + } + + function test_1_5_empty_table() { + $counter = $this->mdb->queryFirstField("SELECT COUNT(*) FROM accounts"); + $this->assert($counter === strval(0)); + + $row = $this->mdb->queryFirstRow("SELECT * FROM accounts"); + $this->assert($row === null); + + $field = $this->mdb->queryFirstField("SELECT * FROM accounts"); + $this->assert($field === null); + + $field = $this->mdb->queryOneField('nothere', "SELECT * FROM accounts"); + $this->assert($field === null); + + $column = $this->mdb->queryFirstColumn("SELECT * FROM accounts"); + $this->assert(is_array($column) && count($column) === 0); + + $column = $this->mdb->queryOneColumn('nothere', "SELECT * FROM accounts"); //TODO: is this what we want? + $this->assert(is_array($column) && count($column) === 0); + } + + function test_2_insert_row() { + $this->mdb->insert('accounts', array( + 'username' => 'Abe', + 'password' => 'hello' + )); + + $this->assert($this->mdb->affectedRows() === 1); + + $counter = $this->mdb->queryFirstField("SELECT COUNT(*) FROM accounts"); + $this->assert($counter === strval(1)); + } + + function test_3_more_inserts() { + $this->mdb->insert('`accounts`', array( + 'username' => 'Bart', + 'password' => 'hello', + 'age' => 15, + 'height' => 10.371 + )); + $dbname = $this->mdb->dbName; + $this->mdb->insert("`$dbname`.`accounts`", array( + 'username' => 'Charlie\'s Friend', + 'password' => 'goodbye', + 'age' => 30, + 'height' => 155.23, + 'favorite_word' => null, + )); + + $this->assert($this->mdb->insertId() === 3); + + $counter = $this->mdb->queryFirstField("SELECT COUNT(*) FROM accounts"); + $this->assert($counter === strval(3)); + + $password = $this->mdb->queryFirstField("SELECT password FROM accounts WHERE favorite_word IS NULL"); + $this->assert($password === 'goodbye'); + + $this->mdb->param_char = '###'; + $bart = $this->mdb->queryFirstRow("SELECT * FROM accounts WHERE age IN ###li AND height IN ###ld AND username IN ###ls", + array(15, 25), array(10.371, 150.123), array('Bart', 'Barts')); + $this->assert($bart['username'] === 'Bart'); + $this->mdb->param_char = '%'; + + $charlie_password = $this->mdb->queryFirstField("SELECT password FROM accounts WHERE username IN %ls AND username = %s", + array('Charlie', 'Charlie\'s Friend'), 'Charlie\'s Friend'); + $this->assert($charlie_password === 'goodbye'); + + $charlie_password = $this->mdb->queryOneField('password', "SELECT * FROM accounts WHERE username IN %ls AND username = %s", + array('Charlie', 'Charlie\'s Friend'), 'Charlie\'s Friend'); + $this->assert($charlie_password === 'goodbye'); + + $passwords = $this->mdb->queryFirstColumn("SELECT password FROM accounts WHERE username=%s", 'Bart'); + $this->assert(count($passwords) === 1); + $this->assert($passwords[0] === 'hello'); + + $username = $password = $age = null; + list($age, $username, $password) = $this->mdb->queryOneList("SELECT age,username,password FROM accounts WHERE username=%s", 'Bart'); + $this->assert($username === 'Bart'); + $this->assert($password === 'hello'); + $this->assert($age == 15); + + $mysqli_result = $this->mdb->queryRaw("SELECT * FROM accounts WHERE favorite_word IS NULL"); + $this->assert($mysqli_result instanceof MySQLi_Result); + $row = $mysqli_result->fetch_assoc(); + $this->assert($row['password'] === 'goodbye'); + $this->assert($mysqli_result->fetch_assoc() === null); + } + + function test_4_query() { + $results = $this->mdb->query("SELECT * FROM accounts WHERE username=%s", 'Charlie\'s Friend'); + $this->assert(count($results) === 1); + $this->assert($results[0]['age'] == 30 && $results[0]['password'] == 'goodbye'); + + $results = $this->mdb->query("SELECT * FROM accounts WHERE username!=%s", "Charlie's Friend"); + $this->assert(count($results) === 2); + + $columnlist = $this->mdb->columnList('accounts'); + $this->assert(count($columnlist) === 6); + $this->assert($columnlist[0] === 'id'); + $this->assert($columnlist[4] === 'height'); + + $tablelist = $this->mdb->tableList(); + $this->assert(count($tablelist) === 1); + $this->assert($tablelist[0] === 'accounts'); + + $tablelist = null; + $tablelist = $this->mdb->tableList($this->mdb->dbName); + $this->assert(count($tablelist) === 1); + $this->assert($tablelist[0] === 'accounts'); + } + + function test_4_1_query() { + $this->mdb->insert('accounts', array( + 'username' => 'newguy', + 'password' => $this->mdb->sqleval("REPEAT('blah', %i)", '3'), + 'age' => $this->mdb->sqleval('171+1'), + 'height' => 111.15 + )); + + $row = $this->mdb->queryOneRow("SELECT * FROM accounts WHERE password=%s", 'blahblahblah'); + $this->assert($row['username'] === 'newguy'); + $this->assert($row['age'] === '172'); + + $this->mdb->update('accounts', array( + 'password' => $this->mdb->sqleval("REPEAT('blah', %i)", 4), + 'favorite_word' => null, + ), 'username=%s', 'newguy'); + + $row = null; + $row = $this->mdb->queryOneRow("SELECT * FROM accounts WHERE username=%s", 'newguy'); + $this->assert($row['password'] === 'blahblahblahblah'); + $this->assert($row['favorite_word'] === null); + + $this->mdb->query("DELETE FROM accounts WHERE password=%s", 'blahblahblahblah'); + $this->assert($this->mdb->affectedRows() === 1); + } + + function test_4_2_delete() { + $this->mdb->insert('accounts', array( + 'username' => 'gonesoon', + 'password' => 'something', + 'age' => 61, + 'height' => 199.194 + )); + + $ct = $this->mdb->queryFirstField("SELECT COUNT(*) FROM accounts WHERE username=%s AND height=%d", 'gonesoon', 199.194); + $this->assert(intval($ct) === 1); + + $ct = $this->mdb->queryFirstField("SELECT COUNT(*) FROM accounts WHERE username=%s1 AND height=%d0 AND height=%d", 199.194, 'gonesoon'); + $this->assert(intval($ct) === 1); + + $this->mdb->delete('accounts', 'username=%s AND age=%i AND height=%d', 'gonesoon', '61', '199.194'); + $this->assert($this->mdb->affectedRows() === 1); + + $ct = $this->mdb->queryFirstField("SELECT COUNT(*) FROM accounts WHERE username=%s AND height=%d", 'gonesoon', '199.194'); + $this->assert(intval($ct) === 0); + } + + function test_4_3_insertmany() { + $ins[] = array( + 'username' => '1ofmany', + 'password' => 'something', + 'age' => 23, + 'height' => 190.194 + ); + $ins[] = array( + 'password' => 'somethingelse', + 'username' => '2ofmany', + 'age' => 25, + 'height' => 190.194 + ); + + $this->mdb->insert('accounts', $ins); + $this->assert($this->mdb->affectedRows() === 2); + + $rows = $this->mdb->query("SELECT * FROM accounts WHERE height=%d ORDER BY age ASC", 190.194); + $this->assert(count($rows) === 2); + $this->assert($rows[0]['username'] === '1ofmany'); + $this->assert($rows[0]['age'] === '23'); + $this->assert($rows[1]['age'] === '25'); + $this->assert($rows[1]['password'] === 'somethingelse'); + $this->assert($rows[1]['username'] === '2ofmany'); + + } + + + + function test_5_insert_blobs() { + $this->mdb->query("CREATE TABLE `storedata` ( + `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY , + `picture` BLOB + ) ENGINE = InnoDB"); + + + $smile = file_get_contents('smile1.jpg'); + $this->mdb->insert('storedata', array( + 'picture' => $smile, + )); + $this->mdb->query("INSERT INTO storedata (picture) VALUES (%s)", $smile); + + $getsmile = $this->mdb->queryFirstField("SELECT picture FROM storedata WHERE id=1"); + $getsmile2 = $this->mdb->queryFirstField("SELECT picture FROM storedata WHERE id=2"); + $this->assert($smile === $getsmile); + $this->assert($smile === $getsmile2); + } + + function test_6_insert_ignore() { + $this->mdb->insertIgnore('accounts', array( + 'id' => 1, //duplicate primary key + 'username' => 'gonesoon', + 'password' => 'something', + 'age' => 61, + 'height' => 199.194 + )); + } + + function test_7_insert_update() { + $this->mdb->insertUpdate('accounts', array( + 'id' => 2, //duplicate primary key + 'username' => 'gonesoon', + 'password' => 'something', + 'age' => 61, + 'height' => 199.194 + ), 'age = age + %i', 1); + + $this->assert($this->mdb->affectedRows() === 2); // a quirk of MySQL, even though only 1 row was updated + + $result = $this->mdb->query("SELECT * FROM accounts WHERE age = %i", 16); + $this->assert(count($result) === 1); + $this->assert($result[0]['height'] === '10.371'); + + $this->mdb->insertUpdate('accounts', array( + 'id' => 2, //duplicate primary key + 'username' => 'blahblahdude', + 'age' => 233, + 'height' => 199.194 + )); + + $result = $this->mdb->query("SELECT * FROM accounts WHERE age = %i", 233); + $this->assert(count($result) === 1); + $this->assert($result[0]['height'] === '199.194'); + $this->assert($result[0]['username'] === 'blahblahdude'); + + $this->mdb->insertUpdate('accounts', array( + 'id' => 2, //duplicate primary key + 'username' => 'gonesoon', + 'password' => 'something', + 'age' => 61, + 'height' => 199.194 + ), array( + 'age' => 74, + )); + + $result = $this->mdb->query("SELECT * FROM accounts WHERE age = %i", 74); + $this->assert(count($result) === 1); + $this->assert($result[0]['height'] === '199.194'); + $this->assert($result[0]['username'] === 'blahblahdude'); + + $multiples[] = array( + 'id' => 3, //duplicate primary key + 'username' => 'gonesoon', + 'password' => 'something', + 'age' => 61, + 'height' => 199.194 + ); + $multiples[] = array( + 'id' => 1, //duplicate primary key + 'username' => 'gonesoon', + 'password' => 'something', + 'age' => 61, + 'height' => 199.194 + ); + + $this->mdb->insertUpdate('accounts', $multiples, array('age' => 914)); + $this->assert($this->mdb->affectedRows() === 4); + + $result = $this->mdb->query("SELECT * FROM accounts WHERE age=914 ORDER BY id ASC"); + $this->assert(count($result) === 2); + $this->assert($result[0]['username'] === 'Abe'); + $this->assert($result[1]['username'] === 'Charlie\'s Friend'); + + $this->mdb->query("UPDATE accounts SET age=15, username='Bart' WHERE age=%i", 74); + $this->assert($this->mdb->affectedRows() === 1); + } + +} + + +?> diff --git a/vendor/sergeytsalkov/meekrodb/simpletest/TransactionTest.php b/vendor/sergeytsalkov/meekrodb/simpletest/TransactionTest.php new file mode 100644 index 0000000..76f1f23 --- /dev/null +++ b/vendor/sergeytsalkov/meekrodb/simpletest/TransactionTest.php @@ -0,0 +1,30 @@ +assert($depth === 1); + + DB::query("UPDATE accounts SET age=%i WHERE username=%s", 700, 'Abe'); + $depth = DB::startTransaction(); + $this->assert($depth === 1); + + DB::query("UPDATE accounts SET age=%i WHERE username=%s", 800, 'Abe'); + $depth = DB::rollback(); + $this->assert($depth === 0); + + $age = DB::queryFirstField("SELECT age FROM accounts WHERE username=%s", 'Abe'); + $this->assert($age == 700); + + $depth = DB::rollback(); + $this->assert($depth === 0); + + $age = DB::queryFirstField("SELECT age FROM accounts WHERE username=%s", 'Abe'); + $this->assert($age == 700); + } + +} +?> diff --git a/vendor/sergeytsalkov/meekrodb/simpletest/TransactionTest_55.php b/vendor/sergeytsalkov/meekrodb/simpletest/TransactionTest_55.php new file mode 100644 index 0000000..a409098 --- /dev/null +++ b/vendor/sergeytsalkov/meekrodb/simpletest/TransactionTest_55.php @@ -0,0 +1,85 @@ +assert($depth === 1); + DB::query("UPDATE accounts SET age=%i WHERE username=%s", 700, 'Abe'); + + $depth = DB::startTransaction(); + $this->assert($depth === 2); + DB::query("UPDATE accounts SET age=%i WHERE username=%s", 800, 'Abe'); + + $depth = DB::startTransaction(); + $this->assert($depth === 3); + $this->assert(DB::transactionDepth() === 3); + DB::query("UPDATE accounts SET age=%i WHERE username=%s", 500, 'Abe'); + $depth = DB::commit(); + + $this->assert($depth === 2); + + $age = DB::queryFirstField("SELECT age FROM accounts WHERE username=%s", 'Abe'); + $this->assert($age == 500); + + $depth = DB::rollback(); + $this->assert($depth === 1); + + $age = DB::queryFirstField("SELECT age FROM accounts WHERE username=%s", 'Abe'); + $this->assert($age == 700); + + $depth = DB::commit(); + $this->assert($depth === 0); + + $age = DB::queryFirstField("SELECT age FROM accounts WHERE username=%s", 'Abe'); + $this->assert($age == 700); + + + DB::$nested_transactions = false; + } + + function test_2_transactions() { + DB::$nested_transactions = true; + + DB::query("UPDATE accounts SET age=%i WHERE username=%s", 600, 'Abe'); + + DB::startTransaction(); + DB::query("UPDATE accounts SET age=%i WHERE username=%s", 700, 'Abe'); + DB::startTransaction(); + DB::query("UPDATE accounts SET age=%i WHERE username=%s", 800, 'Abe'); + DB::rollback(); + + $age = DB::queryFirstField("SELECT age FROM accounts WHERE username=%s", 'Abe'); + $this->assert($age == 700); + + DB::rollback(); + + $age = DB::queryFirstField("SELECT age FROM accounts WHERE username=%s", 'Abe'); + $this->assert($age == 600); + + DB::$nested_transactions = false; + } + + function test_3_transaction_rollback_all() { + DB::$nested_transactions = true; + + DB::query("UPDATE accounts SET age=%i WHERE username=%s", 200, 'Abe'); + + $depth = DB::startTransaction(); + $this->assert($depth === 1); + DB::query("UPDATE accounts SET age=%i WHERE username=%s", 300, 'Abe'); + $depth = DB::startTransaction(); + $this->assert($depth === 2); + + DB::query("UPDATE accounts SET age=%i WHERE username=%s", 400, 'Abe'); + $depth = DB::rollback(true); + $this->assert($depth === 0); + + $age = DB::queryFirstField("SELECT age FROM accounts WHERE username=%s", 'Abe'); + $this->assert($age == 200); + + DB::$nested_transactions = false; + } + +} +?> diff --git a/vendor/sergeytsalkov/meekrodb/simpletest/WhereClauseTest.php b/vendor/sergeytsalkov/meekrodb/simpletest/WhereClauseTest.php new file mode 100644 index 0000000..14ceee7 --- /dev/null +++ b/vendor/sergeytsalkov/meekrodb/simpletest/WhereClauseTest.php @@ -0,0 +1,83 @@ +add('username=%s', 'Bart'); + $where->add('password=%s', 'hello'); + + $result = DB::query("SELECT * FROM accounts WHERE %l", $where->text()); + $this->assert(count($result) === 1); + $this->assert($result[0]['age'] === '15'); + } + + function test_2_simple_grouping() { + $where = new WhereClause('and'); + $where->add('password=%s', 'hello'); + $subclause = $where->addClause('or'); + $subclause->add('age=%i', 15); + $subclause->add('age=%i', 14); + + $result = DB::query("SELECT * FROM accounts WHERE %l", $where->text()); + $this->assert(count($result) === 1); + $this->assert($result[0]['age'] === '15'); + } + + function test_3_negate_last() { + $where = new WhereClause('and'); + $where->add('password=%s', 'hello'); + $subclause = $where->addClause('or'); + $subclause->add('username!=%s', 'Bart'); + $subclause->negateLast(); + + $result = DB::query("SELECT * FROM accounts WHERE %l", $where->text()); + $this->assert(count($result) === 1); + $this->assert($result[0]['age'] === '15'); + } + + function test_4_negate_last_query() { + $where = new WhereClause('and'); + $where->add('password=%s', 'hello'); + $subclause = $where->addClause('or'); + $subclause->add('username!=%s', 'Bart'); + $where->negateLast(); + + $result = DB::query("SELECT * FROM accounts WHERE %l", $where); + $this->assert(count($result) === 1); + $this->assert($result[0]['age'] === '15'); + } + + function test_5_negate() { + $where = new WhereClause('and'); + $where->add('password=%s', 'hello'); + $subclause = $where->addClause('or'); + $subclause->add('username!=%s', 'Bart'); + $subclause->negate(); + + $result = DB::query("SELECT * FROM accounts WHERE %l", $where); + $this->assert(count($result) === 1); + $this->assert($result[0]['age'] === '15'); + } + + function test_6_negate_two() { + $where = new WhereClause('and'); + $where->add('password=%s', 'hello'); + $where->add('username=%s', 'Bart'); + $where->negate(); + + $result = DB::query("SELECT * FROM accounts WHERE %l", $where); + $this->assert(count($result) === 7); + } + + function test_7_or() { + $where = new WhereClause('or'); + $where->add('username=%s', 'Bart'); + $where->add('username=%s', 'Abe'); + + $result = DB::query("SELECT * FROM accounts WHERE %l", $where); + $this->assert(count($result) === 2); + } + + +} + +?> diff --git a/vendor/sergeytsalkov/meekrodb/simpletest/smile1.jpg b/vendor/sergeytsalkov/meekrodb/simpletest/smile1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..672649659577b4feb2bcf85a899c0e8ba62a4816 GIT binary patch literal 48874 zcmeFacUTn5vj94Pf)PXn6i}2PB4Nons3ZXa$r%o?9_?gdr?o_E#lTuWDM_ zL18WkfQy4eK!`(7h=cPgC$|tMmk_T2*a`p$UgCZ27l#9Ym-yf5<7>Sn_$z;e2>^t6 z1mAch{8cl~EMK%IQ!7mpqP2knb8-{}3qJMN!!xdNOylF3j)0l>$t0>nop z0Qvx=fQK6fo&aY~oH%jv#F>*P&yb!zb()l%iHR>9UWhMzZ9@7#A%J@ake&cu0xt>h=m30DJOWZY+$bpaDO@d{ zILPI3yrbir$ONFF96L@(bmHWx)1W#0T8RhX6MU~c2jCsUBfvj~f1HT$#BqW%++Zas z!Le)SIgj5~HX@^Qc*sR~A>>v59eM_GmG{QnJn%=I5=4xls$VA7O%S{kNd=FuONOaI zr9LD(@=rd5>7Q#(Dl2$bkbL*>SFiAr}rgc(2m=g`2^60{$pe zLY3SE!L!atc*p?Jb>0tMAQQ=yP$_jjN7Kn4Ed19TF#W{>ZU{I-aMUL$AP%6^LS-45 z8A4^{WTBWp(4C#wJe6Ugrzyjh!_sULUfUHrmMO@&hUF|QDMFD}ue$K#Cc8^-b?7`> zZ3B1A_P##aGm6#>nlZ2O`%Jy zi`u>YNK6BC&@LHa<|naih6CEX5|g#s(JQFOBD4cYO|Hw@_*_DdhyCzG1We-Bs`GX$ z)DwbHhOZp&6BE*3vY)$#-4A%~vamdA;)0zLmoC;6ZN&lgkD>4Z&1HWM-q`6K$z&nW3t-}Ai}7L_Xx_LRGmV3}#+7<*0!pqys73Le;HY(bphKqT3mWX;<>nxfGb;C91SFImx zi}&YQk1k-%GpdV|TafjEw`T2efR7IjQ18G28f*f>w8e{|dJ^pD36xFCm9^}6#>!r^ z_&X*0zFRA3!F}C*9FSIw1CsK(^qKCU>$=>roQ(^mFxH1&#MHJK4F^}Gm_~I=c~@|N zG$t|0%m3v}StU)Yz?XaXoG|k^z*{`&2PVly%)QJdQVmiE$-qGYThu4}dm9Q(=c zEyMVbs|1tS@kV0OXt4Qtw0hAw&Nulh_&v?w_?BE zk8BsurO;VJ%Arf9)Y)cA%-flpF zL>EpBabmM|{{U`)>(c#HLYMpR7Y62-gtkrYkDiSX;87CR6_>>UjaC_5Vg-(3MS5e= zQLR32ejT0pm3o z%G7=T(*(khG&A+sr$%Ylee81UH%NRoqGtD5&3C2QV~GxQ$YvzxUNl6-xlYk;+^>ls z!$8(J;(FPNyn|&`=Hpdz^ST_|!|zjvX}MW&QLQE0>b|O|Vv$(V)Z`bCJO6^==Kbqj zms2kfz6h0z)LjgB3x41Ru#vRocMx^j)(&uZ;HYxgs zOH2~;6*8)=d6(CKl0tU3V<9!2>0+Y^<7xT2?>jy$UR-HJ-hVO<4^VCifXWnNd;TF++O5SP|H{t@S1 zZ|}KGkaAwHVzq_DR!#W_ZoSMRuR4ZMy%w$rrarN- zFqh;$p}W@Z#MhGO42@-KBKPK*M@ctlD z{t>q3!noW{S{;j#?ujU8QKu}*MRWPm z6pZ%!k8f=&IR>roKDulj@0K&QvxpLfEVHG~C7z2jZ%2^%w6GR((r;B6^6x6V^?Sad zGF?+2UZRPTo_!;4TmD+S>D5>oM&Cx?st!HZwX!&_fp{}doySU{_K6`H5olnR&DGv%C$Vc+B9m4s$wOKjC5}j>GOgl5dS0 z+w15d$5+m8Pv7^_@q)|@mUiNR+?+9=-kVF8X-P7A@yeX|K74}m)_O-|;DAS^UUyk& z7f)9=?VG&3NRT>PHh>Dc6!=1{->(C$$)1K~*<=V9DHGPPKz?e%0qFzWfx(@)?uCL< zC^F!Vxs#UY4L)(_;WhRUj1{x4HBp*K%~F5gAISIIY58f5-KIX+u!xO`nyF*0)$}iD zKLyZQ<+G#+aF~I{8ovg%ngql)AFUkA)Yv@E49? z5^#WVJ-Q5gb6v>U)~!m3!K^xxs8@ozr0U&1ttBFE3F*;|p~X13__DmkGPj$&b8|K0 zthLdIQ$9b&nb<-8n)LdTI;f)1nZujSXKX$W@T*izjx~ebYr3dZR=53Wdo2$UT!x}3 z%gx%U67NFxMRfGiW(d$~Xzf!QHMhUDDP(LLB4Bb!Rfl5&I%6?dRA)-=^lqA97%(#z z)pG8Yj)NTMo(c28hR(HfcE#YWJA?i3{{7-jxoUL_mJ{JHnC$LzFYD&G@QtELa3R2R zAJw9yl|L|c^m&*oO`#y!VP;!qgRC3;a&U)!XF>o=gWNgeRxN|;S>U*|;N^~PV$xlD zm!I5JtSeu$z-yPS`0{cvmSZ8m!B!i?*89dARiwXIaWKTLYYjfF1aNTf2Him_a{P${ z$cAyiTboI-2PvVlP%dUhe^g%j^wb~xr_+Rl@>E^x-&>$>RqP!k!m5gmm8*x@2hp^h zIT1X?ftC(#7C>3&b#cLA37wP(dK&viYt*wloS2(F3pfDb--*SC=;$+qDyJUZz7M56 zx}Qg{u$#otXz86Gwz-?wZufaM8u%D{hfoY+tZ9XQtXj=t4~*z{ z9`E)Jk)@H=n)_4Tg!4RYswzf&)xll-qtudOmn=iFT%<4ze0-FV%f9UJ2F`B3;kHGD zVeDi_CMz25HY{pBJhM=S&ST8l3sDI45ox00hpyfm)G^$sRK@1kb-swTa<{E{|z@!IROX{cVu zbYJl4UcnLuRH`YjIl zQnTKSRK~tlM)?Ekh{x`)g=L1Urd+R#7pskL!EnII(!E&Zl3400jCRb;6%pmL=@4|q zoW}X%4R?p>C*l&sS~y_J-`L_yLb=ata0(lvemuh+8o^t|itw;_)D8*B;?l5;%Ewe3 zPy}ye&+Fziae!M>>)P6GBm3c2JH1XUnoAA+r^IqUQ)SpA)fz4LdG(fwhPShHv4M%7 zcaWkmj7PUm4{esFV^G4u>MO`%)m?NMdx88ANma3E$BuhN{Ngn70}iOo5mTidEpyw9 zme~x6xS~r_(#DL2L*vAih;JOS%3$*)SddS!?`=h zB1n33Q{#r&(KUTVix>{T=DM_^cxSR$l2`kYO+3XSOcP&axw*}8w?Jn$m56VvJj`1o z>3o6Ax;}E3?n5L2s(aDEnj1L>>5cDoI@MHyX7228nHvx4+*(2Ix{I$U9l$n6H)Ide z_#?wxR!x#kp4msd-Ix;RVWJ&XOJcZD$=|EA9{aH8Vyj}w?1Wh$;qC2Cs0+JzC-@K_ zfFU_x+9e-(bRs03B@Eq*g$QZtv$xdK6QxIA?>lMwWC>ko2)^o^>F7eHpd!gCmcX}8 zbK9L7JRe0^EuE)#1SEY2IjWmb6wKI!7^{}QIrSGt10Uh`Wl_ zhHl!$V+EolbbE!|j*)o1?T8j{YN)Uq$N1`AKn5Z+OM;O@78_o-aKK#TQ0DY5e=TQ> zNM-8ODe%sCo1TG0GhfyLe2WD!i%HCfU>mtF#Wyz>wJazsSM>V zfBuNg^_hlrO;&GS1(pibQ1X`gt0uT!a9(_)V8F+j8ID9HO7uZu3pO)|S$^h%xNBLB z3O04Nh93*Zn2o~jzwx(7TG4CpHr*-0oYoqj1?N;z&3aAiP7_0+TQv;A8#&T+$LGwo z%bb(-VtTGq`&m<@q~Nn!88XL96~ceLCR6`xcdyWcfUH{)QzoQn>l~L(ljXd5bQ?qk{I>xR(x6l74R;6 z(Fn1QsrMqm94}qSckzpqUJ!_U8A$GZ&3~ zE~cB%&|~)xuD{}w6*a{5AH7uz(CT2b5{mT&qxil2bG9}NA4Ulzw%0e|d)?E;KE_mc z?8;%RAjv4?63Gg;9kG+4@sgIo$TB6II590*)BSCqoprPc4fx6rK402aS-nGdpj2{; zEIVr7es-$7Y+pFQ@GyI7n*V^0H#UA5`DqMXdY#7=_Qo&l8i={ju9`i-7%1)g;s9mO z>&Bkcmh7-JFRM~o9!JBR3qi5HW;Y9v8cnd-VSl&nQY4xQiv(W-6EMg1=_UmeH2K;7 zoN6OD>4+I58GBMA#}?H{Y6Pyn583(eqhnEq=@rhJ3MrM*kZdYF+0~sXsyH05l5GvX zfyne)>&X)<09adRd?HMheoKL@PTe{&;#@l75}mk9ke>Kt4u|guQDE|cDn=vYUFGx` zku@toyKh#m(V=umJ5AUbqL3nTPGXsG4qrHb?|OgX{%KQ&f&+=T=9`}NvLvHZktDmB zq|XPAgAZMq;6vApP-Ne7!mEf?UzAvWkC6Wp?U<`mCXcsrylUEpX8EzjHP~rwbU}Xe zhTC5D<0}_0(RPWy!rSkToKFJnKzCeQtRNv~u^gt5wKD3$KkV~l)EK!UEuGxmkhid3 zow#umm76B9=+i5`MdJbITG=<$ZWl|t-zqxdH5SNCZIK5)XQRD4I=kh))X<56pQz3B zw`o=jBXiB~7s$smxg={WY=Mt79W@i;?=>|gE0E7Txhd&`eDYXvKwQ%}Iv<;?gWwW7 zd|Z9h@O?)Hyyq#f=X91E>eLE&DP4}{A-k4GRkU86MNOe@zOe+Krv2po)=TU0r&UZ< zm-fqrLB%so84tW@Z1P@i7w4eGxBG6comV!W`7-B2XmKWF1+pK8W601s7l}R*%st;vaP{#Bxk<*BL0Ip? zmU{xDwhdWnj|F2PHmD;_wPtdp%%i5xMd?*X;Y%mhF~6NZ6=dehc4cKC+HOaFZ1 zmbjZAB$;5y+<>|FcqDii2k>L~l%r52cS2|NQ62}Tla*ePITLd|JOnor?;c<~)In{& zf59d`W&HN+`vn)*2*Ih~-B!OoM;tIYE<)@>b6_IAzgvf_qNU7`g@c=6Q~6MzKeoy} zPseR`_@sqcg?WSflmV5cq>=rc99GUxj8zv&F@`#s;7j!TE}sM4xfCaXi795}n6%tZ z^5j!rh>=}yp@kjkVLR9TQK;x5=BRrxSm+?<#DYIaTCW# z+CARo5 z{pY$z1XpgHvA;}r(U(cZ7M!!;pkalo;s$XmS0?{*fN-;O00MVp6^=0;?Z2PoH(Qn9LfsHjeqOw`Av&gKqzqJ zB>Ji!s>33|ZSe9{p2H%5ul4l=VF&MsONRpwsDVB<8VgB&AXKLp7bNP-V z%=T;fkQD$>F}L_ue^e$!*jSpFA~bC7A;3z!U-~(IR0o33gD25ZL00l7+C=7Xn3Mf4 zAVL`2(%jO{)XvEkY;#6R^^m&K5ezJ!HF9!<$(Y)i!i^kFp&$TIbF(-7hJ5NP@*(7~ zM%LE+DwzCl%TM40w^5VQQUkmCrrbm2{|Zq+n4A6rAvCgaR5LRF1x9RQ3br$Kb(BTi zRa3ZU41?Jm5 zj-WyP2mCZR#1?-?Kbm9lDmk8Z^OCt3!O?;&+pO z2^PQ;?=yhMdI*;RE`qMt-_F|K&f3}S-_F|K&f4G3+TYIF-_F|K&f4G3+TYIF-_F|K z&f4G3+TYIF-_F|K&f4G3+TYIF-_F|K&f4G3+TYIF-_F|K&f0%+)_(OyTm#(-0H6w< zphp4#NPyb_6o3K7pp)+^a38P$^N!$&ILd)8Owc9v-(y?_B)*dSO8<~30F?afQ9OeD zb@}R{{Hy$P?ilEs`byzvD99^7(0>XLj@vv+k$T|gdtmt^wE#w{Ob=<`0f#up^1YAR9Hxgf!1Tx?^VJth1Ue-_Uhu$A3@;K` zI6B%3K_GSrcB8|O{@6`mwh&h%dk7~x2LuoiceOV%u{L$QYHSL61Vx$FDr%UnT0%vc zGOyXjvL|lbjZS8GM9gVKK+S=G5gj_|Lj))6^ z`9m;->FN=RqqQiLmcsq3j-a2-+S2hV=w)Z)5@5Y*1~;-bb%DXHuX3{UF@Xf(P%|MF zN$GFoz>+A_H@;n5T-aT>*>Q0;+3XPXU~flkSZe)f z_KUcdT1V1?9i6&*)Rm+u!US$gu;HO~DU1|GCq{n(y6Sy()586gu+jse&3e z731L&{ippOo>xpdkC7#`2dz0V_cDa6`aR`M+W0`^T>TJY4qQtA84^A26Z2mIy}}+)Ydb z@}IE(8}=P7&Hf8RJFNMM>BFKB=*%|-XUCy|i*brT{sVSsE=NEu6;lMv#_0%=p9}IG z_h;}AT-w#(f2Dzch5XyPeyi(WY2aTW|F*8*>iSn2_*clk zt?ReC{*?y)74rXA>pJz$qB=4fI~% zd2wiiP(V9Q+&w51)XL=r|Y#kAMIl{}>qKkBE>E?>Ojp!6zU+ zcKkfyH6l(rE;29@-5nKU`U?(V?71Xv3Gx#ULtYiAnjjeRKXg3~E2Q}HzB8Fea$@qM zIv*ut_lu(I8i!Hs05GK838Lf2PaHAxl_D6|j_|fJ9oHQr2Nh$G8rj2;qyl;gFu>gh zZq@f)CWyyhIwzA0KQfSa^QiIu8k;Wh-OsH5N1m8m`Fv)P64e9v8Dd@cm3vf>v1ku# z7bbZMNzH@$-g@7NgWEP0mlYZc=IFLQ#}5maK$=4nGx1m-y`8Q(FX+b0Pww;Rm_f^& zM~X|E-4k9KA7R0#e`fO24NK=e8oFM(RYvpqv}>ksS6YJgJ_`)(AC%w-HS;#N%7%!UThn0p83+43&$|t7}6bJuiekG)k!M%tctUU=S>h_ zxme~F`DQ{#HnAu#RMK$%=H=@Cj?oH*;wObdG2!{edPVD<#p?<4ZeA6$%aeAh6TUcL zkW-#p@(NiAskb(RCQ(m|VrAdVk~^YrJVdW%Rg5gwvjP#Gk?<&EN+!wM$r22Hf$nex zzorhu0Z*B>!SEv5YqXf$sRL&50&Vm%_$_!+UJ(5={d+|x+YAhalf`ZK^fIth-9(%v zyvEmqsYb0c1lrdt!b3yvU}0@P7j?@GH*S*8JKLl=@KBhX@GL~w&bPe6HcT? zH^`eOobF?iQ#el_IV1D(Ekz^wCiQMuG&yzT2VT_=`<50pe3IDwib=PnHw8Mn4hVKJ zsRj9{UaCa4m>9h41eXFvv{+k6cPj&{h9Ju+){&cZJxve(!=Qcz5aB-k*9J()&HMIE ztovZUTkL%Hq@q}7qhGajY0=DXieMQIAa%aava+4yH&Q0RIMb`u@id=Ff1KskvH6_> zzN~3DZ$_QoOcK)^PtM1-oZwQY28U4F-WKG_ifCchq&iHwhPlpggnHlAu8F)%B%n)j zX2SYZwgXdGg(=HMa2&<^k^P6tHmp#sUiGS_FnLmC-kU6=(o7_>brHk*%7_w&To%ui z9urhS27j5cY%~~y#97hQQP+j~a-k5lXxC2gu186y?`E9zUV_n@ZT*ZXR%c?_W#CR# zx4wSuISa`%m$U!030JCRuX#V;SU>8QpK@cgS`64M%dBrI@b_Hu&qGTtUA*bsdx)nMS zDj+F2FGush=rAZPKy<1vPmb<@DRhq9zp8u9`M%QYa*u%lwC3xW5Koyml+uXD_2(VD zEI&6>t;~KL;_q2o=b%eV~2#pbN17i&xBSiUs+vM z!>*w9Zo7@$F}xETN#NP?>~-qh>xwH|iY>|`T62&cC@gA7IM%jB@9B#^wBGZ0|AnSbmK_v~#I=NxQzbZCv1hf26%OP5EbaES-aSi>1h$$lINk9+pS~cAGTQS`xVe zt+*hov=7~tzb+v^l}K=%|Gb*GZn)_=Q+4hP%15oRCCgQ7>jf%x-4>o&$Dea~yAn-K z=C8@b<*;kyi`2#eJouI)!g+YbIr>hq)j@;l;Wk#qAy{eYc=L0LV011hj6z;C6}EaG zqB(9Z>DV%3B79~~=XuC#hh1E-2lrg#So^eHX;un6GmkKBTSqQdDWqGkwxz0pB_~8Z zGonpWGfUI2Ke*5^Fl+MMW_ge*qhV{CE>-`Xab^z={nz>z<#g%t>6%POs55auWrBP_ z_;kCZjHo_+xVkHE&7kGgm4v&qa2>V~zZksO+^>0|sKu7^XxKhQ zD@$5((bBOwCdEa{Nz`?{J4@dE8MNDp*s;V@eVRo*r@2K~b+i8R!2SsIxoO{CrRVb= z4w0fEEy6s6S)@wd&?r4r$NqC*lFa87i$2@N9xLVa=LrmgglW-jvk2~~R$XD!ex{%+ zrl0OA%NuI}cr@uh4Z}}ag4w%M;h9ZT!B$(vO==jXPd5{&@AK&40A^=zgj!&U?#Yp2 zZ8l9gdpXq#edQ!ijSz~N>5|!xWt+yGT+V?~>a^baZs6B=x+y&g_EE+Z!}38PFlQ z@%ZDPOG~PKU8dGArru-he7tdChor33ptaIvv=lMW+;CIg20gDXHQ8T_&6~eI8o&GG zO+}}9MGmH2J;`J1M6R!9{kDTA^6uykVe4>gbWw{|fwpR)uzM&Y%SYWCGcer(3F^|2 zJyvVRs^LO5R0XMCNv@pY^B12-MHn`#XkXarxbRMMEAoy8=`<9c!~twI8Xaq2Lgpls zi=9KvIQLl2G?Q)!cbtPY9-QKrPk5+_vOjAs;*zfgf4h%J@ z`SGlC@l0$~NRJl^iiWod3AYxo#rub;u!Lo=lG{b7XD;>^4=^gkHZQXeJ!P!)jf`BX zGnnqF-xbPnv7X@>cNe&px_Iz8X+}EcZA_hTN`?4>Ox?=8FayKaNae@F!}3HWbgS#m z^Mm9()h-SpO*&mwCpYeWCJgb~F*GUJYi?@sOj(D%2-RYI09^EY@I!6?RmQp^7HT`% zf2xq#qBr4%>4@cPjjit7_)M$ZNYq_w*A1k2X(HPgr+;XDQf6^ys+ozaYGt56p3*(! ztwJMZ@*9=P?)SGHtN-Y*T#+W*D|YM^&EKJY&>)m7x=*Wfv%PWl^~|73!6<{%DqEH; zE0emKm8(Y@JdC?x@oz+S4DEk5X&M(*7l)VqtY`@#Ut$c>|IsqV~Lq-FS=h@>Z~d$ z2a(G^>ZwqduUSPqY~Kybygy#-6zO=*g?(>@@b;%k{zoNaGZu{n%)P!#pW+w2Vk5hj z$vojQEYu8&GWks!Wm#%!hNqa9qB>swhuUay-G4Jbe1Ta_-u2j}E@2jGICSZ+EM>UYo zmXK;z7(>E3kh!n?O>4ipD3qXkO}>ItgwOepifys_js)+FBjenrIR(0a;v?R zgPU!;(+auiAD#RA0HUCyAQk_in12Gea_!ofIXB<)))+0N*kB~jRb-yAF4tLmu=8kM z(LOYeVd_SuTG;!vzUVu}urXz*bC-PBN0z*NHU%ZADIVE5md^C&vrMnY4;n`SUsQCC?i#Ny$QLXa&;EM^r~6NW^7RM8A{nuH1I}K ze0L`Az98jn%^Y=~Pn(~epsj4mjx?qT#o}I7z+2?{3Pol{BJ4k+wOioo|7>JfE?kD! zHECC8dciuZ7AmJ*v=cNnv#Q@-+E1CwBpgM}*BqfHgrO00G@8z4zt6~^nA;s-+w78uIj z#-k!!)SGkR>*|K5;wwC0rY_Fv*Pha{%zBx{x2UUwaQLpgXpyrSzm>Mk*$U+yA!UY` z1X|*-#y+R)>R1i#m0=#NzO~0jOQ&yWdEB_l5@!W{q_eOhp_o3|7!!HOdGJwN3VyBP z0sLSa$(>L!XJ+2O%Aw1l9IPTaP$y+{4xpp_Mauv80-;YUyUx^3U}0{Ka!Fa#@Uk7V zbdyqHOoA2K+sH6ym0z5lpW-#kasfsAQoi+QbMvm}dFhR@nB1L#fwqMpEq3K=)xPAm z5UO}H;o3Dhez!KhK!RwSCV?4*Z3p`{Q?=S&`4Z|LMOW%jP{V#}BE-$de_X34g8VMm z{UpYjm^|&Qg~G1DF>Xg@`q;8EhcXqvC6U17%>GnId8#})?=EKX;anX9y-kwK)%lk6 z>Tjk$OUk#%txIhUP6amHeKG;1H-)PNggS(}zD|^b^1T^o8vyivlA8e6`_n+vV=WO^ zhE0qkSj_qE^$x4EeqQ(#f11a4zO-#C4(}NlEthAom@WR{hsNM`J?bcDgU%?yYsWo z{2|xvVcp^^;Sk|LWr4g9%9Me3f@UyYXS=;wNaTgt?V6F$#lx}wqx333ANiA<|KqGR z^)PgbKbO;%y_2rem%PvAdAKLc5Ff2v(P57A>&5}w2D)~RYMMGwn^85j%m!AgD(3yW zP^IlY-EP(KSZdlT2kT?$A<(N*x-3PCY%VXsQQvFhGti$s3B6u07%>wOyIBrBP)3Og zMA>Ee8kb@>xm#8+LE~D_MsH=1Z`}y2EK;9r*zK-waLcqi&RhrGp=9H~Q$;n;zG9d( zJKEdH>NM%Uz&U2(?@;7o!0j?I(PCoY7c428WY7cKjGErK%+3`snMRm;iB(lsRVnpc zz!%`{5AkVneLu!~zN)gMK}W&MjZVVWt}axYrbxOtL;e04_N~!@mFUNb5YK7NB+HUV zRhFg(Ez}s}gy{mo_?5Q|Rpp3WNS@*Q^O=FLnEJGs`fJg%ihJebu@Ac>zRU8#m~p zi_=`Ex272tRp2|T{uY~qce}@4OL|q%#Oe6OU2aJ3-K)JUubg%*BEfjB0!kk=%+z@? z@(wZlJvAk}vk0|3O=x57&i=DB_n8%5%Ajz5dt&*7_R;v(4sMTnRgZ}IIu{dKPBBhp zxf{TV)OSCm`*#^U+D+j|d)VpY)dkijZ9~N#zCyx%Ojl-=F#K*QEG?ref6i=AsJ)d* z4I3Ys&Y?`@$qjdBTA^3zJ=Y-U<{IfB?rii5YsQl+N5MpyPqq}}+qLb6%_xKCRxZXl zF89+rweJOUZSAUoZ6q|F#N4$<7&Bx{xe2jk23QDcO}F zv%+smvxf$KYYuF?Gfe6GpQx01kZ&Yh%q+06Ot?tPhW^Wv+7ul+KTRu3R}(hA z#=2>%n<*oQ-Ci}7aw2VC5?u`6j2~i)o6=(xEWTK0JUkM5+U_G_hWNeS=-RlOK>zB# z>9(!f1U-fd2b6ZPS}~sY{p7kX&~lGYY@8Z8%D27psn+0THM#n3vj?$4u2pwWp

M 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 literal 0 HcmV?d00001 diff --git a/vendor/sergeytsalkov/meekrodb/simpletest/test.php b/vendor/sergeytsalkov/meekrodb/simpletest/test.php new file mode 100755 index 0000000..6c0ae69 --- /dev/null +++ b/vendor/sergeytsalkov/meekrodb/simpletest/test.php @@ -0,0 +1,87 @@ +#!/usr/bin/php +fail(); + } + + protected function fail($msg = '') { + echo "FAILURE! $msg\n"; + debug_print_backtrace(); + die; + } + + +} + +function microtime_float() +{ + list($usec, $sec) = explode(" ", microtime()); + return ((float)$usec + (float)$sec); +} + +if (phpversion() >= '5.3') $is_php_53 = true; +else $is_php_53 = false; + +ini_set('date.timezone', 'America/Los_Angeles'); + +error_reporting(E_ALL | E_STRICT); +require_once '../db.class.php'; +include 'test_setup.php'; //test config values go here +// WARNING: ALL tables in the database will be dropped before the tests, including non-test related tables. +DB::$user = $set_db_user; +DB::$password = $set_password; +DB::$dbName = $set_db; +DB::$host = $set_host; +DB::get(); //connect to mysql + +require_once 'BasicTest.php'; +require_once 'CallTest.php'; +require_once 'ObjectTest.php'; +require_once 'WhereClauseTest.php'; +require_once 'ErrorTest.php'; +require_once 'TransactionTest.php'; +require_once 'HelperTest.php'; + +$classes_to_test = array( + 'BasicTest', + 'CallTest', + 'WhereClauseTest', + 'ObjectTest', + 'ErrorTest', + 'TransactionTest', + 'HelperTest', +); + +if ($is_php_53) { + require_once 'ErrorTest_53.php'; + $classes_to_test[] = 'ErrorTest_53'; +} else { + echo "PHP 5.3 not detected, skipping 5.3 tests..\n"; +} + +$mysql_version = DB::serverVersion(); +if ($mysql_version >= '5.5') { + require_once 'TransactionTest_55.php'; + $classes_to_test[] = 'TransactionTest_55'; +} else { + echo "MySQL 5.5 not available (version is $mysql_version) -- skipping MySQL 5.5 tests\n"; +} + +$time_start = microtime_float(); +foreach ($classes_to_test as $class) { + $object = new $class(); + + foreach (get_class_methods($object) as $method) { + if (substr($method, 0, 4) != 'test') continue; + echo "Running $class::$method..\n"; + $object->$method(); + } +} +$time_end = microtime_float(); +$time = round($time_end - $time_start, 2); + +echo "Completed in $time seconds\n"; + + +?>