Compare commits

..

4 Commits

Author SHA1 Message Date
Clemens Schwaighofer
51e3cc7c7f Merge branch 'NewFeatures' into Features-DB_IO_SQLite 2024-11-18 16:22:53 +09:00
Clemens Schwaighofer
b7935dcb71 Merge branch 'NewFeatures' into Features-DB_IO_SQLite 2024-11-15 19:46:33 +09:00
Clemens Schwaighofer
89e8f79cae Merge branch 'NewFeatures' into Features-DB_IO_SQLite 2024-11-07 14:32:03 +09:00
Clemens Schwaighofer
1a027e5c7d DB SqLite interface class 2024-10-21 10:18:56 +09:00
25 changed files with 835 additions and 115 deletions

View File

@@ -36,7 +36,7 @@ if [ -n "${2}" ] && [ -z "${php_bin}" ]; then
fi;
# Note 4dev/tests/bootstrap.php has to be set as bootstrap file in phpunit.xml
phpunit_call="${php_bin}${base}vendor/bin/phpunit ${opt_testdox} -c ${base}phpunit.xml ${base}4dev/tests/";
phpunit_call="${php_bin}${base}tools/phpunit ${opt_testdox} -c ${base}phpunit.xml ${base}4dev/tests/";
${phpunit_call};

View File

@@ -319,36 +319,6 @@ final class CoreLibsConvertMathTest extends TestCase
[6, 12, 18],
]
],
'inblanaced [2x2,3] x [3x2]' => [
'a' => [
[1, 2, 3],
[4, 5]
],
'b' => [
[6, 7],
[8, 9],
[10, 11]
],
'result' => [
[52, 58],
[64, 73],
]
],
'inblanaced [2x3] x [3x1,2]' => [
'a' => [
[1, 2, 3],
[4, 5, 7]
],
'b' => [
[7, 8],
[9, 10],
[11]
],
'result' => [
[58, 28],
[150, 82],
]
],
];
}

View File

@@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
namespace tests;
use PHPUnit\Framework\TestCase;
/**
* Test class for DB\SqLite
* This will only test the SqLite parts
* @coversDefaultClass \CoreLibs\DB\SqLite
* @testdox \CoreLibs\SqLite method tests for extended DB interface
*/
final class CoreLibsDBESqLiteTest extends TestCase
{
/**
* Undocumented function
*
* @return void
*/
protected function setUp(): void
{
if (!extension_loaded('sqlite')) {
$this->markTestSkipped(
'The SqLite extension is not available.'
);
}
}
/**
* Undocumented function
*
* @testdox DB\SqLite Class tests
*
* @return void
*/
public function testSqLite()
{
$this->markTestIncomplete(
'DB\SqLite Tests have not yet been implemented'
);
}
}
// __END__

View File

@@ -7,11 +7,11 @@
"php": ">=8.3"
},
"require-dev": {
"phpstan/phpstan": "^2.0",
"phpstan/phpstan-deprecation-rules": "^2.0",
"phpstan/extension-installer": "^1.4",
"phpstan/phpstan": "^1.12",
"phan/phan": "^5.4",
"phpstan/extension-installer": "^1.4",
"phpunit/phpunit": "^9",
"phpstan/phpstan-deprecation-rules": "^1.2",
"yamadashy/phpstan-friendly-formatter": "^1.1"
},
"config": {

View File

@@ -2,7 +2,6 @@
includes:
- phpstan-conditional.php
#- ./vendor/yamadashy/phpstan-friendly-formatter/extension.neon
# - phar://phpstan.phar/conf/bleedingEdge.neon
parameters:
tmpDir: %currentWorkingDirectory%/tmp/phpstan-corelibs
#errorFormat: friendly

View File

@@ -115,6 +115,9 @@ print "ARRAYFLATFORKEY: " . DgS::printAr(ArrayHandler::arrayFlatForKey($test_arr
*/
function rec(string $pre, string $cur, array $node = [])
{
if (!is_array($node)) {
$node = [];
}
print "<div style='color: green;'>#### PRE: " . $pre . ", CUR: " . $cur . ", N-c: "
. count($node) . " [" . join('|', array_keys($node)) . "]</div>";
if (!$pre) {

View File

@@ -70,7 +70,8 @@ for ($i = 1; $i <= 6; $i++) {
print $i . ") " . $cache_flag . ": "
. "res: " . (is_bool($res) ?
"<b>Bool:</b> " . Support::prBl($res) :
"Array: Yes"
(is_array($res) ?
"Array: " . Support::prBl(is_array($res)) : '{-}')
) . ", "
. "cursor_ext: <pre>" . Support::printAr(
SetVarType::setArray($db->dbGetCursorExt($q_db_ret))
@@ -88,7 +89,8 @@ for ($i = 1; $i <= 6; $i++) {
print $i . ") " . $cache_flag . ": "
. "res: " . (is_bool($res) ?
"<b>Bool:</b> " . Support::prBl($res) :
"Array: Yes"
(is_array($res) ?
"Array: " . Support::prBl(is_array($res)) : '{-}')
) . ", "
. "cursor_ext: <pre>" . Support::printAr(
SetVarType::setArray($db->dbGetCursorExt($q_db_ret))
@@ -106,7 +108,8 @@ for ($i = 1; $i <= 6; $i++) {
print $i . ") " . $cache_flag . ": "
. "res: " . (is_bool($res) ?
"<b>Bool:</b> " . Support::prBl($res) :
"Array: Yes"
(is_array($res) ?
"Array: " . Support::prBl(is_array($res)) : '{-}')
) . ", "
. "cursor_ext: <pre>" . Support::printAr(
SetVarType::setArray($db->dbGetCursorExt($q_db_ret))
@@ -124,7 +127,8 @@ for ($i = 1; $i <= 6; $i++) {
print $i . ") " . $cache_flag . ": "
. "res: " . (is_bool($res) ?
"<b>Bool:</b> " . Support::prBl($res) :
"Array: Yes"
(is_array($res) ?
"Array: " . Support::prBl(is_array($res)) : '{-}')
) . ", "
. "cursor_ext: <pre>" . Support::printAr(
SetVarType::setArray($db->dbGetCursorExt($q_db_ret))
@@ -142,7 +146,8 @@ for ($i = 1; $i <= 6; $i++) {
print $i . ") " . $cache_flag . ": "
. "res: " . (is_bool($res) ?
"<b>Bool:</b> " . Support::prBl($res) :
"Array: Yes"
(is_array($res) ?
"Array: " . Support::prBl(is_array($res)) : '{-}')
) . ", "
. "cursor_ext: <pre>" . Support::printAr(
SetVarType::setArray($db->dbGetCursorExt($q_db_ret))

View File

@@ -316,8 +316,7 @@ print "EOM STRING EXEC RETURN TEST: " . print_r(
$db->dbReturnRowParams(
$query_select,
[$__last_insert_id]
),
true
)
) . "<br>";
// B
$status = $db->dbExecParams(
@@ -346,8 +345,7 @@ print "EOM STRING EXEC RETURN TEST: " . print_r(
$db->dbReturnRowParams(
$query_select,
[$__last_insert_id]
),
true
)
) . "<br>";
// params > 10 for debug
// error catcher
@@ -676,7 +674,7 @@ echo "<hr>";
print "COMPOSITE ELEMENT READ<br>";
$res = $db->dbReturnRow("SELECT item, count, (item).name, (item).price, (item).supplier_id FROM on_hand");
print "ROW: <pre>" . print_r($res, true) . "</pre>";
print "ROW: <pre>" . print_r($res) . "</pre>";
var_dump($res);
print "Field Name/Types: <pre>" . print_r($db->dbGetFieldNameTypes(), true) . "</pre>";
echo "<hr>";

View File

@@ -0,0 +1,157 @@
<?php // phpcs:ignore warning
/**
* @phan-file-suppress PhanTypeSuspiciousStringExpression
*/
declare(strict_types=1);
// turn on all error reporting
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start();
// basic class test file
define('USE_DATABASE', true);
define('DATABASE', 'sqlite' . DIRECTORY_SEPARATOR);
// sample config
require 'config.php';
// define log file id
$LOG_FILE_ID = 'classTest-db';
ob_end_flush();
$sql_file = BASE . MEDIA . DATABASE . "class_test.db.sqlite.sq3";
use CoreLibs\DB\SqLite;
use CoreLibs\Debug\Support;
use CoreLibs\Convert\SetVarType;
$log = new CoreLibs\Logging\Logging([
'log_folder' => BASE . LOG,
'log_file_id' => $LOG_FILE_ID,
'log_per_date' => true,
]);
// db connection and attach logger
$db = new CoreLibs\DB\SqLite($log, "sqlite:" . $sql_file);
$db->log->debug('START', '=============================>');
$PAGE_NAME = 'TEST CLASS: DB: SqLite';
print "<!DOCTYPE html>";
print "<html><head><title>" . $PAGE_NAME . "</title></head>";
print "<body>";
print '<div><a href="class_test.php">Class Test Master</a></div>';
print "<hr>";
echo "Create Tables on demand<br>";
$query = <<<SQL
CREATE TABLE IF NOT EXISTS test (
test_id INTEGER PRIMARY KEY,
c_text TEXT,
c_integer INTEGER,
c_integer_default INTEGER DEFAULT -1,
c_bool BOOLEAN,
c_datetime TEXT,
c_datetime_microseconds TEXT,
c_datetime_default TEXT DEFAULT CURRENT_TIMESTAMP,
c_date TEXT,
c_julian REAL,
c_unixtime DATETIME,
c_unixtime_alt DATETIME,
c_numeric NUMERIC,
c_real REAL,
c_blob
)
SQL;
$db->dbExec($query);
// **********************
$query = <<<SQL
CREATE TABLE IF NOT EXISTS test_no_pk (
c_text TEXT,
c_integer INTEGER
)
SQL;
$db->dbExec($query);
print "<hr>";
$table = 'test';
echo "Table info for: " . $table . "<br>";
if (($table_info = $db->dbShowTableMetaData($table)) === false) {
print "Read problem for: $table<br>";
} else {
print "TABLE INFO: <pre>" . print_r($table_info, true) . "</pre><br>";
}
print "<hr>";
echo "Insert into 'test'<br>";
$query = <<<SQL
INSERT INTO test (
c_text, c_integer, c_bool,
c_datetime, c_datetime_microseconds, c_date,
c_julian, c_unixtime, c_unixtime_alt,
c_numeric, c_real, c_blob
) VALUES (
?, ?, ?,
?, ?, ?,
julianday(?), ?, unixepoch(?),
?, ?, ?
)
SQL;
$db->dbExecParams($query, [
'test', rand(1, 100), true,
date('Y-m-d H:i:s'), date_format(date_create("now"), 'Y-m-d H:i:s.u'), date('Y-m-d'),
// julianday pass through
date('Y-m-d H:i:s'),
// use "U" if no unixepoch in query
date('U'), date('Y-m-d H:i:s'),
1.5, 10.5, 'Anything'
]);
print "<hr>";
echo "Insert into 'test_no_pk'<br>";
$query = <<<SQL
INSERT INTO test_no_pk (
c_text, c_integer
) VALUES (
?, ?
)
SQL;
$db->dbExecParams($query, ['test no pk', rand(100, 200)]);
print "<hr>";
$query = <<<SQL
SELECT test_id, c_text, c_integer, c_integer_default, c_datetime_default
FROM test
SQL;
while (is_array($row = $db->dbReturnArray($query))) {
print "ROW: PK(test_id): " . $row["test_id"]
. ", Text: " . $row["c_text"] . ", Int: " . $row["c_integer"]
. ", Int Default: " . $row["c_integer_default"]
. ", Date Default: " . $row["c_datetime_default"]
. "<br>";
}
echo "<hr>";
$query = <<<SQL
SELECT rowid, c_text, c_integer
FROM test_no_pk
SQL;
while (is_array($row = $db->dbReturnArray($query))) {
print "ROW[CURSOR]: PK(rowid): " . $row["rowid"]
. ", Text: " . $row["c_text"] . ", Int: " . $row["c_integer"]
. "<br>";
}
print "</body></html>";
// __END__

View File

@@ -73,6 +73,7 @@ $test_files = [
'class_test.db.query-placeholder.php' => 'Class Test: DB query placeholder convert',
'class_test.db.dbReturn.php' => 'Class Test: DB dbReturn',
'class_test.db.single.php' => 'Class Test: DB single query tests',
'class_test.db.sqlite.php' => 'Class Test: DB: SqLite',
'class_test.convert.colors.php' => 'Class Test: CONVERT COLORS',
'class_test.check.colors.php' => 'Class Test: CHECK COLORS',
'class_test.mime.php' => 'Class Test: MIME',

View File

@@ -24,7 +24,7 @@
declare(strict_types=1);
ob_start();
require 'config.php'; /** @phpstan-ignore-line Is path, is symlinked */
require 'config.php';
// should be utf8
header("Content-type: text/html; charset=" . DEFAULT_ENCODING);

View File

@@ -960,7 +960,10 @@ class Login
. "AND ear.edit_access_right_id = epa.edit_access_right_id "
. "AND epa.enabled = 1 AND epa.edit_group_id = " . $res["edit_group_id"] . " "
. "ORDER BY ep.order_number";
while (is_array($res = $this->db->dbReturn($q))) {
while ($res = $this->db->dbReturn($q)) {
if (!is_array($res)) {
break;
}
// page id array for sub data readout
$edit_page_ids[$res['edit_page_id']] = $res['cuid'];
// create the array for pages
@@ -1300,9 +1303,11 @@ class Login
{
$is_valid_password = true;
// check for valid in regex arrays in list
foreach ($this->password_valid_chars as $password_valid_chars) {
if (!preg_match("/$password_valid_chars/", $password)) {
$is_valid_password = false;
if (is_array($this->password_valid_chars)) {
foreach ($this->password_valid_chars as $password_valid_chars) {
if (!preg_match("/$password_valid_chars/", $password)) {
$is_valid_password = false;
}
}
}
// check for min length

View File

@@ -425,7 +425,10 @@ class Backend
?string $set_content_path = null,
int $flag = 0,
): array {
if ($set_content_path === null) {
if (
$set_content_path === null ||
!is_string($set_content_path)
) {
/** @deprecated adbTopMenu missing set_content_path parameter */
trigger_error(
'Calling adbTopMenu without set_content_path parameter is deprecated',

View File

@@ -119,13 +119,6 @@ class Colors
/**
* check if html/css color string is valid
*
* TODO: update check for correct validate values
* - space instead of ","
* - / opcatiy checks
* - loose numeric values
* - lab/lch,oklab/oklch validation too
*
* @param string $color A color string of any format
* @param int $flags defaults to ALL, else use | to combined from
* HEX_RGB, HEX_RGBA, RGB, RGBA, HSL, HSLA
@@ -175,9 +168,9 @@ class Colors
if (preg_match("/$regex/", $color)) {
// if valid regex, we now need to check if the content is actually valid
// only for rgb/hsl type
/** @var int<0, max>|false */
/** @var int|false */
$rgb_flag = strpos($color, 'rgb');
/** @var int<0, max>|false */
/** @var int|false */
$hsl_flag = strpos($color, 'hsl');
// if both not match, return true
if (

View File

@@ -246,7 +246,7 @@ class CieXyz
self::convertArray(array_map(
fn ($k, $v) => $v * $d50[$k],
array_keys($xyz),
$xyz,
array_values($xyz),
)),
options: ["whitepoint" => 'D50']
);

View File

@@ -158,8 +158,6 @@ class Math
* [0, 0, 0] <- automatically added
* ]
*
* The same is done for unbalanced entries, they are filled with 0
*
* @param array<float|int|array<int|float>> $a m x n matrice
* @param array<float|int|array<int|float>> $b n x p matrice
*
@@ -188,7 +186,7 @@ class Math
// so that we can multiply row by row
$bCols = array_map(
callback: fn ($k) => array_map(
(fn ($i) => is_array($i) ? $i[$k] ?? 0 : 0),
(fn ($i) => is_array($i) ? $i[$k] : 0),
$b,
),
array: array_keys($b[0]),

View File

@@ -38,7 +38,7 @@ class Uids
$uniqid_length++;
}
/** @var int<1,max> make sure that internal this is correct */
$random_bytes_length = (int)(($uniqid_length - ($uniqid_length % 2)) / 2);
$random_bytes_length = ($uniqid_length - ($uniqid_length % 2)) / 2;
$uniqid = bin2hex(random_bytes($random_bytes_length));
// if not forced shorten return next lower length
if (!$force_length) {

View File

@@ -374,7 +374,7 @@ class ArrayIO extends \CoreLibs\DB\IO
public function dbDelete(array $table_array = [], bool $acl_limit = false): array
{
// is array and has values, override set and set new
if (count($table_array)) {
if (is_array($table_array) && count($table_array)) {
$this->table_array = $table_array;
}
if (!$this->dbCheckPkSet()) {
@@ -440,7 +440,7 @@ class ArrayIO extends \CoreLibs\DB\IO
public function dbRead(bool $edit = false, array $table_array = []): array
{
// if array give, overrules internal array
if (count($table_array)) {
if (is_array($table_array) && count($table_array)) {
$this->table_array = $table_array;
}
if (!$this->dbCheckPkSet()) {

View File

@@ -914,7 +914,7 @@ class IO
if ($cursor !== false) {
[$db_prefix, $db_error_string] = $this->db_functions->__dbPrintError($cursor);
}
if ($cursor === false && method_exists($this->db_functions, '__dbPrintError')) { /** @phpstan-ignore-line */
if ($cursor === false && method_exists($this->db_functions, '__dbPrintError')) {
[$db_prefix, $db_error_string] = $this->db_functions->__dbPrintError();
}
// prefix the master if not the same
@@ -1737,7 +1737,7 @@ class IO
{
if (
!empty($this->dbh) &&
$this->dbh instanceof \PgSql\Connection /** @phpstan-ignore-line future could be other */
$this->dbh instanceof \PgSql\Connection
) {
// reset any client encodings set
$this->dbResetEncoding();

View File

@@ -0,0 +1,90 @@
<?php
/**
* AUTHOR: Clemens Schwaighofer
* CREATED: Ymd
* DESCRIPTION:
* DescriptionHere
*/
declare(strict_types=1);
namespace CoreLibs\DB\Interface;
interface DatabaseInterface
{
/**
* Table meta data
* Note that if columns have multi
*
* @param string $table
* @return array<array<string,mixed>>|false
*/
public function dbShowTableMetaData(string $table): array|false;
/**
* for reading or simple execution, no return data
*
* @param string $query
* @return int|false
*/
public function dbExec(string $query): int|false;
/**
* Run a simple query and return its statement
*
* @param string $query
* @return \PDOStatement|false
*/
public function dbQuery(string $query): \PDOStatement|false;
/**
* Execute one query with params
*
* @param string $query
* @param array<mixed> $params
* @return \PDOStatement|false
*/
public function dbExecParams(string $query, array $params): \PDOStatement|false;
/**
* Prepare query
*
* @param string $query
* @return \PDOStatement|false
*/
public function dbPrepare(string $query): \PDOStatement|false;
/**
* execute a cursor
*
* @param \PDOStatement $cursor
* @param array<mixed> $params
* @return bool
*/
public function dbCursorExecute(\PDOStatement $cursor, array $params): bool;
/**
* return array with data, when finshed return false
* also returns false on error
*
* TODO: This is currently a one time run
* if the same query needs to be run again, the cursor_ext must be reest
* with dbCacheReset
*
* @param string $query
* @param array<mixed> $params
* @return array<mixed>|false
*/
public function dbReturnArray(string $query, array $params = []): array|false;
/**
* get current db handler
* this is for raw access
*
* @return \PDO
*/
public function getDbh(): \PDO;
}
// __END__

View File

@@ -0,0 +1,432 @@
<?php
/**
* AUTHOR: Clemens Schwaighofer
* CREATED: 2024/8/21
* DESCRIPTION:
* SQL Lite interface
* Note: This is a very simple library and in future should perhaps merge with the master
* CoreLibs SQL interface
*
* TODO: This should move to the CoreLibs\DB\IO class as a sub type for "sqlite" next to "pgsql"
*/
declare(strict_types=1);
namespace CoreLibs\DB;
use CoreLibs\Create\Hash;
class SqLite implements Interface\DatabaseInterface
{
/** @var \CoreLibs\Logging\Logging logging */
public \CoreLibs\Logging\Logging $log;
/** @var string database connection string */
private string $dsn;
/** @var \PDO database handler */
private \PDO $dbh;
/** @var PDOStatement|false one cursor, for internal handling */
// private \PDOStatement|false $cursor;
/** @var array<string,mixed> extended cursoers string index with content */
private array $cursor_ext = [];
/**
* init database system
*
* @param \CoreLibs\Logging\Logging $log
* @param string $dsn
*/
public function __construct(
\CoreLibs\Logging\Logging $log,
string $dsn
) {
$this->log = $log;
// open new connection
if ($this->__connectToDB($dsn) === false) {
throw new \ErrorException("Cannot load database: " . $dsn, 1);
}
}
// *********************************************************************
// MARK: PRIVATE METHODS
// *********************************************************************
/**
* Get a cursor dump with all info
*
* @param \PDOStatement $cursor
* @return string|false
*/
private function __dbGetCursorDump(\PDOStatement $cursor): string|false
{
// get the cursor info
ob_start();
$cursor->debugDumpParams();
$cursor_dump = ob_get_contents();
ob_end_clean();
return $cursor_dump;
}
/**
* fetch rows from a cursor (post execute)
*
* @param \PDOStatement $cursor
* @return array<mixed>|false
*/
private function __dbFetchArray(\PDOStatement $cursor): array|false
{
try {
// on empty array return false
// TODO make that more elegant?
return empty($row = $cursor->fetch(mode:\PDO::FETCH_NAMED)) ? false : $row;
} catch (\PDOException $e) {
$this->log->error(
"Cannot fetch from cursor",
[
"dsn" => $this->dsn,
"DumpParams" => $this->__dbGetCursorDump($cursor),
"PDOException" => $e
]
);
return false;
}
}
// MARK: open database
/**
* Open database
* reports errors for wrong DSN or failed connection
*
* @param string $dsn
* @return bool
*/
private function __connectToDB(string $dsn): bool
{
// check if dsn starts with ":"
if (!str_starts_with($dsn, "sqlite:")) {
$this->log->error(
"Invalid dsn string",
[
"dsn" => $dsn
]
);
return false;
}
// TODO: if not ":memory:" check if path to file is writeable by system
// avoid double open
if (!empty($this->dsn) && $dsn == $this->dsn && $this->dbh instanceof \PDO) {
$this->log->info(
"Connection already establisehd with this dsn",
[
"dsn" => $dsn,
]
);
return true;
}
// TODO: check that folder is writeable
// set DSN and open connection
$this->dsn = $dsn;
try {
$this->dbh = new \PDO($this->dsn);
} catch (\PDOException $e) {
$this->log->error(
"Cannot open database",
[
"dsn" => $this->dsn,
"PDOException" => $e
]
);
return false;
}
return true;
}
// *********************************************************************
// MARK: PUBLIC METHODS
// *********************************************************************
// MARK: db meta data (table info)
/**
* Table meta data
* Note that if columns have multi
*
* @param string $table
* @return array<array<string,mixed>>|false
*/
public function dbShowTableMetaData(string $table): array|false
{
$table_info = [];
$query = <<<SQL
SELECT
ti.cid, ti.name, ti.type, ti.'notnull', ti.dflt_value, ti.pk,
il_ii.idx_name, il_ii.idx_unique, il_ii.idx_origin, il_ii.idx_partial
FROM
sqlite_schema AS m,
pragma_table_info(m.name) AS ti
LEFT JOIN (
SELECT
il.name AS idx_name, il.'unique' AS idx_unique, il.origin AS idx_origin, il.partial AS idx_partial,
ii.cid AS tbl_cid
FROM
sqlite_schema AS m,
pragma_index_list(m.name) AS il,
pragma_index_info(il.name) AS ii
WHERE m.name = ?1
) AS il_ii ON (ti.cid = il_ii.tbl_cid)
WHERE
m.name = ?1
SQL;
while (is_array($row = $this->dbReturnArray($query, [$table]))) {
$table_info[] = [
'cid' => $row['cid'],
'name' => $row['name'],
'type' => $row['type'],
'notnull' => $row['notnull'],
'dflt_value' => $row['dflt_value'],
'pk' => $row['pk'],
'idx_name' => $row['idx_name'],
'idx_unique' => $row['idx_unique'],
'idx_origin' => $row['idx_origin'],
'idx_partial' => $row['idx_partial'],
];
}
if (!$table_info) {
return false;
}
return $table_info;
}
// MARK: db exec
/**
* for reading or simple execution, no return data
*
* @param string $query
* @return int|false
*/
public function dbExec(string $query): int|false
{
try {
return $this->dbh->exec($query);
} catch (\PDOException $e) {
$this->log->error(
"Cannot execute query",
[
"dsn" => $this->dsn,
"query" => $query,
"PDOException" => $e
]
);
return false;
}
}
// MARK: db query
/**
* Run a simple query and return its statement
*
* @param string $query
* @return \PDOStatement|false
*/
public function dbQuery(string $query): \PDOStatement|false
{
try {
return $this->dbh->query($query, \PDO::FETCH_NAMED);
} catch (\PDOException $e) {
$this->log->error(
"Cannot run query",
[
"dsn" => $this->dsn,
"query" => $query,
"PDOException" => $e
]
);
return false;
}
}
// MARK: db prepare & execute calls
/**
* Execute one query with params
*
* @param string $query
* @param array<mixed> $params
* @return \PDOStatement|false
*/
public function dbExecParams(string $query, array $params): \PDOStatement|false
{
// prepare query
if (($cursor = $this->dbPrepare($query)) === false) {
return false;
}
// execute the query, on failure return false
if ($this->dbCursorExecute($cursor, $params) === false) {
return false;
}
return $cursor;
}
/**
* Prepare query
*
* @param string $query
* @return \PDOStatement|false
*/
public function dbPrepare(string $query): \PDOStatement|false
{
try {
// store query with cursor so we can reference?
return $this->dbh->prepare($query);
} catch (\PDOException $e) {
$this->log->error(
"Cannot open cursor",
[
"dsn" => $this->dsn,
"query" => $query,
"PDOException" => $e
]
);
return false;
}
}
/**
* execute a cursor
*
* @param \PDOStatement $cursor
* @param array<mixed> $params
* @return bool
*/
public function dbCursorExecute(\PDOStatement $cursor, array $params): bool
{
try {
return $cursor->execute($params);
} catch (\PDOException $e) {
// write error log
$this->log->error(
"Cannot execute prepared query",
[
"dsn" => $this->dsn,
"params" => $params,
"DumpParams" => $this->__dbGetCursorDump($cursor),
"PDOException" => $e
]
);
return false;
}
}
// MARK: db return array
/**
* Returns hash for query
* Hash is used in all internal storage systems for return data
*
* @param string $query The query to create the hash from
* @param array<mixed> $params If the query is params type we need params
* data to create a unique call one, optional
* @return string Hash, as set by hash long
*/
public function dbGetQueryHash(string $query, array $params = []): string
{
return Hash::__hashLong(
$query . (
$params !== [] ?
'#' . json_encode($params) : ''
)
);
}
/**
* resets all data stored to this query
* @param string $query The Query whose cache should be cleaned
* @param array<mixed> $params If the query is params type we need params
* data to create a unique call one, optional
* @return bool False if query not found, true if success
*/
public function dbCacheReset(string $query, array $params = []): bool
{
$query_hash = $this->dbGetQueryHash($query, $params);
// clears cache for this query
if (empty($this->cursor_ext[$query_hash]['query'])) {
$this->log->error('Cannot reset cursor_ext with given query and params', [
"query" => $query,
"params" => $params,
]);
return false;
}
unset($this->cursor_ext[$query_hash]);
return true;
}
/**
* return array with data, when finshed return false
* also returns false on error
*
* TODO: This is currently a one time run
* if the same query needs to be run again, the cursor_ext must be reest
* with dbCacheReset
*
* @param string $query
* @param array<mixed> $params
* @return array<mixed>|false
*/
public function dbReturnArray(string $query, array $params = []): array|false
{
$query_hash = $this->dbGetQueryHash($query, $params);
if (!isset($this->cursor_ext[$query_hash])) {
$this->cursor_ext[$query_hash] = [
// cursor null: unset, if set \PDOStatement
'cursor' => null,
// the query used in this call
'query' => $query,
// parameter
'params' => $params,
// how many rows have been read from db
'read_rows' => 0,
// when fetch array or cache read returns false
// in loop read that means dbReturn retuns false without error
'finished' => false,
];
if (!empty($params)) {
if (($cursor = $this->dbExecParams($query, $params)) === false) {
return false;
}
} else {
if (($cursor = $this->dbQuery($query)) === false) {
return false;
}
}
$this->cursor_ext[$query_hash]['cursor'] = $cursor;
}
// flag finished if row is false
$row = $this->__dbFetchArray($this->cursor_ext[$query_hash]['cursor']);
if ($row === false) {
$this->cursor_ext[$query_hash]['finished'] = true;
} else {
$this->cursor_ext[$query_hash]['read_rows']++;
}
return $row;
}
// MARK other interface
/**
* get current db handler
* this is for raw access
*
* @return \PDO
*/
public function getDbh(): \PDO
{
return $this->dbh;
}
}
// __END__

View File

@@ -190,6 +190,7 @@ class GetTextReader
private function loadTables(): void
{
if (
is_array($this->cache_translations) &&
is_array($this->table_originals) &&
is_array($this->table_translations)
) {
@@ -317,7 +318,10 @@ class GetTextReader
if ($this->enable_cache) {
// Caching enabled, get translated string from cache
if (array_key_exists($string, $this->cache_translations)) {
if (
is_array($this->cache_translations) &&
array_key_exists($string, $this->cache_translations)
) {
return $this->cache_translations[$string];
} else {
return $string;
@@ -477,7 +481,7 @@ class GetTextReader
$key = $single . chr(0) . $plural;
if ($this->enable_cache) {
if (!array_key_exists($key, $this->cache_translations)) {
if (is_array($this->cache_translations) && !array_key_exists($key, $this->cache_translations)) {
return ($number != 1) ? $plural : $single;
} else {
$result = $this->cache_translations[$key];

View File

@@ -474,7 +474,7 @@ class Generate
$page_name_camel_case
);
try {
/** @var TableArrays\Interface\TableArraysInterface $class */
/** @var TableArrays\Interface\TableArraysInterface|false $class */
$class = new $class_string($this);
} catch (\Throwable $t) {
$this->log->critical('CLASS LOADING: Failed loading: ' . $class_string . ' => ' . $t->getMessage());
@@ -1757,9 +1757,14 @@ class Generate
$this->dba->setTableArrayEntry($this->dba->getTableArray()[$key]['preset'], $key, 'value');
}
}
reset($this->reference_array);
foreach ($this->reference_array as $key => $value) {
unset($this->reference_array[$key]['selected']);
if (is_array($this->reference_array)) {
if (!is_array($this->reference_array)) {
$this->reference_array = [];
}
reset($this->reference_array);
foreach ($this->reference_array as $key => $value) {
unset($this->reference_array[$key]['selected']);
}
}
$this->warning = 1;
$this->msg = $this->l->__('Cleared for new Dataset!');
@@ -1782,15 +1787,20 @@ class Generate
$this->dba->unsetTableArrayEntry($key, 'input_value');
}
// load each reference_table
reset($this->reference_array);
foreach ($this->reference_array as $key => $value) {
unset($this->reference_array[$key]['selected']);
$q = 'SELECT ' . $this->reference_array[$key]['other_table_pk']
. ' FROM ' . $this->reference_array[$key]['table_name']
. ' WHERE ' . $this->int_pk_name . ' = ' . $this->dba->getTableArray()[$this->int_pk_name]['value'];
while (is_array($res = $this->dba->dbReturn($q))) {
$this->reference_array[$key]['selected'][] = $res[$this->reference_array[$key]['other_table_pk']];
if (is_array($this->reference_array)) {
// load each reference_table
if (!is_array($this->reference_array)) {
$this->reference_array = [];
}
reset($this->reference_array);
foreach ($this->reference_array as $key => $value) {
unset($this->reference_array[$key]['selected']);
$q = 'SELECT ' . $this->reference_array[$key]['other_table_pk']
. ' FROM ' . $this->reference_array[$key]['table_name']
. ' WHERE ' . $this->int_pk_name . ' = ' . $this->dba->getTableArray()[$this->int_pk_name]['value'];
while (is_array($res = $this->dba->dbReturn($q))) {
$this->reference_array[$key]['selected'][] = $res[$this->reference_array[$key]['other_table_pk']];
}
}
}
$this->warning = 1;
@@ -1969,19 +1979,24 @@ class Generate
// write the object
$this->dba->dbWrite($addslashes, [], true);
// write reference array (s) if necessary
reset($this->reference_array);
foreach ($this->reference_array as $reference_array) {
$q = 'DELETE FROM ' . $reference_array['table_name']
. ' WHERE ' . $this->int_pk_name . ' = ' . $this->dba->getTableArray()[$this->int_pk_name]['value'];
$this->dba->dbExec($q);
$q = 'INSERT INTO ' . $reference_array['table_name']
. ' (' . $reference_array['other_table_pk'] . ', ' . $this->int_pk_name . ') VALUES ';
for ($i = 0, $i_max = count($reference_array['selected']); $i < $i_max; $i++) {
$t_q = '(' . $reference_array['selected'][$i] . ', '
. $this->dba->getTableArray()[$this->int_pk_name]['value'] . ')';
$this->dba->dbExec($q . $t_q);
if (is_array($this->reference_array)) {
if (!is_array($this->reference_array)) {
$this->reference_array = [];
}
} // foreach reference arrays
reset($this->reference_array);
foreach ($this->reference_array as $reference_array) {
$q = 'DELETE FROM ' . $reference_array['table_name']
. ' WHERE ' . $this->int_pk_name . ' = ' . $this->dba->getTableArray()[$this->int_pk_name]['value'];
$this->dba->dbExec($q);
$q = 'INSERT INTO ' . $reference_array['table_name']
. ' (' . $reference_array['other_table_pk'] . ', ' . $this->int_pk_name . ') VALUES ';
for ($i = 0, $i_max = count($reference_array['selected']); $i < $i_max; $i++) {
$t_q = '(' . $reference_array['selected'][$i] . ', '
. $this->dba->getTableArray()[$this->int_pk_name]['value'] . ')';
$this->dba->dbExec($q . $t_q);
}
} // foreach reference arrays
} // if reference arrays
// write element list
if (!empty($this->element_list)) {
$type = [];
@@ -2215,11 +2230,16 @@ class Generate
public function formDeleteTableArray()
{
// remove any reference arrays
reset($this->reference_array);
foreach ($this->reference_array as $reference_array) {
$q = 'DELETE FROM ' . $reference_array['table_name']
. ' WHERE ' . $this->int_pk_name . ' = ' . $this->dba->getTableArray()[$this->int_pk_name]['value'];
$this->dba->dbExec($q);
if (is_array($this->reference_array)) {
if (!is_array($this->reference_array)) {
$this->reference_array = [];
}
reset($this->reference_array);
foreach ($this->reference_array as $reference_array) {
$q = 'DELETE FROM ' . $reference_array['table_name']
. ' WHERE ' . $this->int_pk_name . ' = ' . $this->dba->getTableArray()[$this->int_pk_name]['value'];
$this->dba->dbExec($q);
}
}
// remove any element list references
if (!empty($this->element_list)) {

View File

@@ -256,8 +256,8 @@ class Image
}
// check resize parameters
if ($inc_width > $thumb_width || $inc_height > $thumb_height) {
$thumb_width_r = 1;
$thumb_height_r = 1;
$thumb_width_r = 0;
$thumb_height_r = 0;
// we need to keep the aspect ration on longest side
if (
($inc_height > $inc_width &&
@@ -288,12 +288,6 @@ class Image
!file_exists($thumbnail_write_path . $thumbnail)
) {
// image, copy source image, offset in image, source x/y, new size, source image size
if ($thumb_width_r < 1) {
$thumb_width_r = 1;
}
if ($thumb_height_r < 1) {
$thumb_height_r = 1;
}
$thumb = imagecreatetruecolor($thumb_width_r, $thumb_height_r);
if ($thumb === false) {
throw new \RuntimeException(
@@ -386,7 +380,9 @@ class Image
}
}
// add output path
$thumbnail = $thumbnail_web_path . $thumbnail;
if ($thumbnail !== false) {
$thumbnail = $thumbnail_web_path . $thumbnail;
}
} elseif ($create_dummy === true) {
// create dummy image in the thumbnail size
// if one side is missing, use the other side to create a square
@@ -403,10 +399,10 @@ class Image
!file_exists($thumbnail_write_path . $thumbnail)
) {
// if both are unset, set to 250
if ($thumb_height < 1) {
if ($thumb_height == 0) {
$thumb_height = 250;
}
if ($thumb_width < 1) {
if ($thumb_width == 0) {
$thumb_width = 250;
}
$thumb = imagecreatetruecolor($thumb_width, $thumb_height);

View File

@@ -599,7 +599,7 @@ class Curl implements Interface\RequestsInterface
// for post we set POST option
if ($type == "post") {
curl_setopt($handle, CURLOPT_POST, true);
} elseif (!empty($type) && in_array($type, self::CUSTOM_REQUESTS)) {
} elseif (in_array($type, self::CUSTOM_REQUESTS)) {
curl_setopt($handle, CURLOPT_CUSTOMREQUEST, strtoupper($type));
}
// set body data if not null, will send empty [] for empty data
@@ -700,12 +700,12 @@ class Curl implements Interface\RequestsInterface
// if we have a timeout signal
if (!empty($this->config['timeout'])) {
$timeout_requires_no_signal = $this->config['timeout'] < 1;
curl_setopt($handle, CURLOPT_TIMEOUT_MS, (int)round($this->config['timeout'] * 1000));
curl_setopt($handle, CURLOPT_TIMEOUT_MS, $this->config['timeout'] * 1000);
}
if (!empty($this->config['connection_timeout'])) {
$timeout_requires_no_signal = $timeout_requires_no_signal ||
$this->config['connection_timeout'] < 1;
curl_setopt($handle, CURLOPT_CONNECTTIMEOUT_MS, (int)round($this->config['connection_timeout'] * 1000, 1));
curl_setopt($handle, CURLOPT_CONNECTTIMEOUT_MS, $this->config['connection_timeout'] * 1000);
}
if ($timeout_requires_no_signal && strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
curl_setopt($handle, CURLOPT_NOSIGNAL, true);