Merge pull request 'feature/recode-genericdb-php8' (#44) from feature/recode-genericdb-php8 into dev_php82

Reviewed-on: #44
This commit is contained in:
Ortwin Pinke 2023-10-11 15:29:53 +00:00
commit 6a28bd3eaf
235 changed files with 24165 additions and 2201 deletions

View file

@ -25,6 +25,9 @@
<excludeFolder url="file://$MODULE_DIR$/conlite/vendor/rector/rector" />
<excludeFolder url="file://$MODULE_DIR$/vendor/composer" />
<excludeFolder url="file://$MODULE_DIR$/vendor/phpmailer/phpmailer" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-ctype" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-mbstring" />
<excludeFolder url="file://$MODULE_DIR$/vendor/twig/twig" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />

View file

@ -12,6 +12,12 @@
<Configuration>
<option name="path" value="$PROJECT_DIR$/tests" />
</Configuration>
<Configuration>
<option name="path" value="$PROJECT_DIR$/tests" />
</Configuration>
<Configuration>
<option name="path" value="$PROJECT_DIR$/tests" />
</Configuration>
</list>
</option>
</component>

View file

@ -16,6 +16,9 @@
<path value="$PROJECT_DIR$/conlite/external/phpqrcode/tools" />
<path value="$PROJECT_DIR$/vendor/composer" />
<path value="$PROJECT_DIR$/vendor/phpmailer/phpmailer" />
<path value="$PROJECT_DIR$/vendor/twig/twig" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-ctype" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-mbstring" />
</include_path>
</component>
<component name="PhpProjectSharedConfiguration" php_language_level="8.0">
@ -31,7 +34,7 @@
</component>
<component name="PhpUnit">
<phpunit_settings>
<PhpUnitSettings custom_loader_path="$PROJECT_DIR$/conlite/external/autoload.php" />
<PhpUnitSettings custom_loader_path="$PROJECT_DIR$/vendor/autoload.php" />
</phpunit_settings>
</component>
<component name="PsalmOptionsConfiguration">

View file

@ -11,6 +11,12 @@
<PhpSpecSuiteConfiguration>
<option name="myPath" value="$PROJECT_DIR$" />
</PhpSpecSuiteConfiguration>
<PhpSpecSuiteConfiguration>
<option name="myPath" value="$PROJECT_DIR$" />
</PhpSpecSuiteConfiguration>
<PhpSpecSuiteConfiguration>
<option name="myPath" value="$PROJECT_DIR$" />
</PhpSpecSuiteConfiguration>
</suites>
</component>
</project>

View file

@ -6,7 +6,6 @@
<option value="$PROJECT_DIR$/conlite/external/endroid/qr-code/tests" />
<option value="$PROJECT_DIR$/conlite/external/phpmailer/phpmailer/tests" />
<option value="$PROJECT_DIR$/tests" />
<option value="$PROJECT_DIR$/tests" />
</list>
</option>
</component>

View file

@ -10,7 +10,8 @@
],
"require": {
"php": "^8.0",
"phpmailer/phpmailer": "v6.8.0"
"phpmailer/phpmailer": "v6.8.0",
"twig/twig": "^3.0"
},
"require-dev": {
"phpstan/phpstan": "^1.10",

238
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "9677dc377e531a46fc52edb0594aa6c8",
"content-hash": "e2e5a5a59b3e9cdbc2023d399f119469",
"packages": [
{
"name": "phpmailer/phpmailer",
@ -85,6 +85,242 @@
}
],
"time": "2023-03-06T14:43:22+00:00"
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.27.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a",
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"provide": {
"ext-ctype": "*"
},
"suggest": {
"ext-ctype": "For best performance"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Ctype\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Gert de Pagter",
"email": "BackEndTea@gmail.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for ctype functions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"ctype",
"polyfill",
"portable"
],
"support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2022-11-03T14:55:06+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.27.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"provide": {
"ext-mbstring": "*"
},
"suggest": {
"ext-mbstring": "For best performance"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Mbstring\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for the Mbstring extension",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"mbstring",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2022-11-03T14:55:06+00:00"
},
{
"name": "twig/twig",
"version": "v3.7.0",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
"reference": "5cf942bbab3df42afa918caeba947f1b690af64b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/5cf942bbab3df42afa918caeba947f1b690af64b",
"reference": "5cf942bbab3df42afa918caeba947f1b690af64b",
"shasum": ""
},
"require": {
"php": ">=7.2.5",
"symfony/polyfill-ctype": "^1.8",
"symfony/polyfill-mbstring": "^1.3"
},
"require-dev": {
"psr/container": "^1.0|^2.0",
"symfony/phpunit-bridge": "^4.4.9|^5.0.9|^6.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Twig\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com",
"homepage": "http://fabien.potencier.org",
"role": "Lead Developer"
},
{
"name": "Twig Team",
"role": "Contributors"
},
{
"name": "Armin Ronacher",
"email": "armin.ronacher@active-4.com",
"role": "Project Founder"
}
],
"description": "Twig, the flexible, fast, and secure template language for PHP",
"homepage": "https://twig.symfony.com",
"keywords": [
"templating"
],
"support": {
"issues": "https://github.com/twigphp/Twig/issues",
"source": "https://github.com/twigphp/Twig/tree/v3.7.0"
},
"funding": [
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/twig/twig",
"type": "tidelift"
}
],
"time": "2023-07-26T07:16:09+00:00"
}
],
"packages-dev": [

View file

@ -59,13 +59,13 @@ class DB_ConLite extends DB_Sql {
* - $options['enableProfiling'] (bool) Optional, flag to enable profiling
* @return void
*/
public function __construct(array $options = array()) {
public function __construct(array $options = []) {
global $cachemeta;
parent::__construct($options);
if (!is_array($cachemeta)) {
$cachemeta = array();
$cachemeta = [];
}
// TODO check this out
@ -109,7 +109,7 @@ class DB_ConLite extends DB_Sql {
*/
public function copyResultToArray($sTable = '') {
$aValues = array();
$aValues = [];
$aMetadata = $this->metadata($sTable);
@ -132,17 +132,8 @@ class DB_ConLite extends DB_Sql {
*
* @deprecated since version 2.0.0, use DB_ConLite instead
*/
class DB_Contenido extends DB_ConLite {
/**
*
* @deprecated since version 2.0.0
* @param array $options
*/
public function __construct(array $options = array()) {
parent::__construct($options);
}
class DB_Contenido extends DB_ConLite
{
}
class Contenido_CT_Sql extends CT_Sql {
@ -176,17 +167,12 @@ class Contenido_CT_Sql extends CT_Sql {
* @param string $id The session id (hash)
* @param string $name Name of the session
* @param string $str The value to store
* @return bool
*/
public function ac_store($id, $name, $str) {
switch ($this->encoding_mode) {
case 'slashes':
$str = addslashes($name . ':' . $str);
break;
case 'base64':
default:
$str = base64_encode($name . ':' . $str);
}
public function ac_store($id, $name, $str): bool {
$str = match ($this->encoding_mode) {
'slashes' => addslashes($name . ':' . $str),
default => base64_encode($name . ':' . $str),
};
$name = addslashes($name);
$now = date('YmdHis', time());
@ -195,7 +181,7 @@ class Contenido_CT_Sql extends CT_Sql {
"REPLACE INTO %s (sid, name, val, changed) VALUES ('%s', '%s', '%s', '%s')", $this->database_table, $id, $name, $str, $now
);
return ($this->db->query($iquery)) ? true : false;
return (bool) $this->db->query($iquery);
}
}
@ -280,14 +266,12 @@ class Contenido_CT_Shm extends CT_Shm {
class Contenido_CT_Session extends CT_Session {
public function __construct() {
$this->ac_start(array(
$this->ac_start([
'namespace' => 'contenido_ct_session_ns',
'session.hash_function' => '1', // use sha-1 function
'session.hash_bits_per_character' => '5', // and set 5 character to achieve 32 chars
# 'session.save_path' => 'your path',
# 'session.name' => 'your session name',
# 'session.gc_maxlifetime' => 'your lifetime in seconds',
));
'session.hash_function' => '1',
// use sha-1 function
'session.hash_bits_per_character' => '5',
]);
}
}
@ -321,8 +305,8 @@ class Contenido_Session extends Session {
}
public function delete() {
$oCol = new InUseCollection();
$oCol->removeSessionMarks($this->id);
$inUseCollection = new InUseCollection();
$inUseCollection->removeSessionMarks($this->id);
parent::delete();
}
@ -436,6 +420,8 @@ class Contenido_Challenge_Auth extends Auth {
}
public function auth_validatelogin() {
$pass = null;
$uid = null;
global $username, $password, $challenge, $response, $timestamp;
if ($password == '') {
@ -523,7 +509,7 @@ class Contenido_Challenge_Crypt_Auth extends Auth {
public function auth_loglogin($uid) {
global $cfg, $client, $lang, $auth, $sess, $saveLoginTime;
$perm = new Contenido_Perm();
$contenidoPerm = new Contenido_Perm();
$timestamp = date('Y-m-d H:i:s');
$idcatart = '0';
@ -540,7 +526,7 @@ class Contenido_Challenge_Crypt_Auth extends Auth {
$iTmpClient = $this->db->f('idclient');
$iTmpLang = $this->db->f('idlang');
if ($perm->have_perm_client_lang($iTmpClient, $iTmpLang)) {
if ($contenidoPerm->have_perm_client_lang($iTmpClient, $iTmpLang)) {
$client = $iTmpClient;
$lang = $iTmpLang;
$bFound = true;
@ -565,7 +551,7 @@ class Contenido_Challenge_Crypt_Auth extends Auth {
return;
}
$idaction = $perm->getIDForAction('login');
$idaction = $contenidoPerm->getIDForAction('login');
$lastentry = $this->db->nextid($cfg['tab']['actionlog']);
$sql = "INSERT INTO
@ -585,9 +571,12 @@ class Contenido_Challenge_Crypt_Auth extends Auth {
}
public function auth_validatelogin() {
$uid = null;
$perm = null;
$pass = null;
global $username, $password, $challenge, $response, $formtimestamp, $auth_handlers;
$gperm = array();
$gperm = [];
if ($password == '') {
return false;
@ -622,11 +611,9 @@ class Contenido_Challenge_Crypt_Auth extends Auth {
$pass = $this->db->f('password'); ## Password is stored as a md5 hash
$bInMaintenance = false;
if ($sMaintenanceMode == 'enabled') {
#sysadmins are allowed to login every time
if (!preg_match('/sysadmin/', $perm)) {
$bInMaintenance = true;
}
#sysadmins are allowed to login every time
if ($sMaintenanceMode == 'enabled' && !preg_match('/sysadmin/', $perm)) {
$bInMaintenance = true;
}
if ($bInMaintenance) {
@ -635,14 +622,11 @@ class Contenido_Challenge_Crypt_Auth extends Auth {
unset($pass);
}
if (is_array($auth_handlers) && !$bInMaintenance) {
if (array_key_exists($pass, $auth_handlers)) {
$success = call_user_func($auth_handlers[$pass], $username, $password);
if ($success) {
$uid = md5($username);
$pass = md5($password);
}
if (is_array($auth_handlers) && !$bInMaintenance && array_key_exists($pass, $auth_handlers)) {
$success = call_user_func($auth_handlers[$pass], $username, $password);
if ($success) {
$uid = md5($username);
$pass = md5($password);
}
}
}
@ -664,9 +648,7 @@ class Contenido_Challenge_Crypt_Auth extends Auth {
$gperm[] = $this->db->f('perms');
}
if (is_array($gperm)) {
$perm = implode(',', $gperm);
}
$perm = implode(',', $gperm);
if ($response == '') { ## True when JS is disabled
if (md5($password) != $pass) { ## md5 hash for non-JavaScript browsers
@ -718,8 +700,6 @@ class Contenido_Frontend_Challenge_Crypt_Auth extends Auth {
global $password;
if ($password == '') {
/* Stay as nobody when an empty password is passed */
$uid = $this->auth['uname'] = $this->auth['uid'] = 'nobody';
return false;
}
@ -736,13 +716,18 @@ class Contenido_Frontend_Challenge_Crypt_Auth extends Auth {
}
public function auth_validatelogin() {
$perm = null;
$gperm = [];
$pass = null;
global $username, $password, $challenge, $response, $auth_handlers, $client;
$client = (int) $client;
if (isset($username)) {
$this->auth['uname'] = $username; ## This provides access for 'loginform.ihtml'
} else if ($this->nobody) { ## provides for 'default login cancel'
$this->auth['uname'] = $username;
## This provides access for 'loginform.ihtml'
} elseif ($this->nobody) {
## provides for 'default login cancel'
$uid = $this->auth['uname'] = $this->auth['uid'] = 'nobody';
return $uid;
}
@ -768,13 +753,11 @@ class Contenido_Frontend_Challenge_Crypt_Auth extends Auth {
$perm = $this->db->f('perms');
$pass = $this->db->f('password'); ## Password is stored as a md5 hash
if (is_array($auth_handlers)) {
if (array_key_exists($pass, $auth_handlers)) {
$success = call_user_func($auth_handlers[$pass], $username, $password);
if ($success) {
$uid = md5($username);
$pass = md5($password);
}
if (is_array($auth_handlers) && array_key_exists($pass, $auth_handlers)) {
$success = call_user_func($auth_handlers[$pass], $username, $password);
if ($success) {
$uid = md5($username);
$pass = md5($password);
}
}
}
@ -796,9 +779,7 @@ class Contenido_Frontend_Challenge_Crypt_Auth extends Auth {
$gperm[] = $this->db->f('perms');
}
if (is_array($gperm)) {
$perm = implode(',', $gperm);
}
$perm = implode(',', $gperm);
}
}
@ -837,16 +818,16 @@ function register_auth_handler($aHandlers) {
global $auth_handlers;
if (!is_array($auth_handlers)) {
$auth_handlers = array();
$auth_handlers = [];
}
if (!is_array($aHandlers)) {
$aHandlers = Array($aHandlers);
$aHandlers = [$aHandlers];
}
foreach ($aHandlers as $sHandler) {
if (!in_array($sHandler, $auth_handlers)) {
$auth_handlers[md5($sHandler)] = $sHandler;
foreach ($aHandlers as $aHandler) {
if (!in_array($aHandler, $auth_handlers)) {
$auth_handlers[md5($aHandler)] = $aHandler;
}
}
}

View file

@ -35,8 +35,8 @@ if (!defined('CON_FRAMEWORK')) {
die('Illegal call');
}
$_PHPLIB = array();
$_PHPLIB['libdir'] = str_replace ('\\', '/', dirname(__FILE__) . '/');
$_PHPLIB = [];
$_PHPLIB['libdir'] = str_replace ('\\', '/', __DIR__ . '/');
global $cfg;

View file

@ -0,0 +1,29 @@
<?php
namespace ConLite\GenericDb\Driver;
class GenericDbDriver
{
public $_sEncoding;
public $_oItemClassInstance;
public function setEncoding($sEncoding)
{
$this->_sEncoding = $sEncoding;
}
public function setItemClassInstance($oInstance)
{
$this->_oItemClassInstance = $oInstance;
}
public function buildJoinQuery($destinationTable, $destinationClass, $destinationPrimaryKey, $sourceClass, $primaryKey)
{
}
public function buildOperator($sField, $sOperator, $sRestriction)
{
}
}

View file

@ -1,51 +1,32 @@
<?php
/**
* Project:
* Contenido Content Management System
*
* Description:
* MySQL Driver for GenericDB
*
* Requirements:
* @con_php_req 5.0
*
*
* @package Contenido Backend classes
* @version 1.12
* @author Bjoern Behrens
* @copyright four for business AG <www.4fb.de>
* @license http://www.contenido.org/license/LIZENZ.txt
* @link http://www.4fb.de
* @link http://www.contenido.org
*
* {@internal
* created 2006-05-10
* modified 2008-05-23 Added Debug_DevNull and Debug_VisibleAdv
*
* $Id$
* }}
*
*/
if (!defined('CON_FRAMEWORK')) {
die('Illegal call');
}
namespace ConLite\GenericDb\Driver\MySql;
class gdbMySQL extends gdbDriver {
use cCharacterConverter;
use ConLite\GenericDb\Driver\GenericDbDriver;
use Contenido_Security;
function buildJoinQuery($destinationTable, $destinationClass, $destinationPrimaryKey, $sourceClass, $primaryKey) {
class GenericDbDriverMySql extends GenericDbDriver
{
public $_oItemClassInstance;
public $_sEncoding;
function buildJoinQuery($destinationTable, $destinationClass, $destinationPrimaryKey, $sourceClass, $primaryKey)
{
// Build a regular LEFT JOIN
$field = "$destinationClass.$destinationPrimaryKey";
$tables = "";
$join = "LEFT JOIN $destinationTable AS $destinationClass ON " .
Contenido_Security::toString($sourceClass . "." . $primaryKey) . " = " .
Contenido_Security::toString($destinationClass . "." . $primaryKey);
Contenido_Security::toString($sourceClass . "." . $primaryKey) . " = " .
Contenido_Security::toString($destinationClass . "." . $primaryKey);
$where = "";
return array("field" => $field, "table" => $tables, "join" => $join, "where" => $where);
return ["field" => $field, "table" => $tables, "join" => $join, "where" => $where];
}
function buildOperator($sField, $sOperator, $sRestriction) {
function buildOperator($sField, $sOperator, $sRestriction)
{
$sOperator = strtolower($sOperator);
$sWhereStatement = "";
@ -88,14 +69,14 @@ class gdbMySQL extends gdbDriver {
$GLOBALS["_cCharTable"] = new cCharacterConverter;
}
$aliasSearch = array();
$aliasSearch = [];
$metaCharacters = array("*", "[", "]", "^", '$', "\\", "*", "'", '"', '+');
$metaCharacters = ["*", "[", "]", "^", '$', "\\", "*", "'", '"', '+'];
for ($i = 0; $i < strlen($sRestriction); $i ++) {
for ($i = 0; $i < strlen($sRestriction); $i++) {
$char = substr($sRestriction, $i, 1);
$aliases = array();
$aliases = [];
$aliases = array_merge($aliases, $GLOBALS["_cCharTable"]->fetchDiacriticCharactersForNormalizedChar($this->_sEncoding, $char));
$normalizedChars = $GLOBALS["_cCharTable"]->fetchNormalizedCharsForDiacriticCharacter($this->_sEncoding, $char);
@ -106,9 +87,9 @@ class gdbMySQL extends gdbDriver {
$aliases = array_merge($aliases, $normalizedChars);
if (count($aliases) > 0) {
if ($aliases !== []) {
$aliases[] = $char;
$allAliases = array();
$allAliases = [];
foreach ($aliases as $alias) {
$alias1 = $this->_oItemClassInstance->_inFilter($alias);
@ -119,8 +100,7 @@ class gdbMySQL extends gdbDriver {
$allAliases = array_unique($allAliases);
$aliasSearch[] = "(" . implode("|", $allAliases) . ")";
} else {
$addChars = array();
$addChars = [];
if (in_array($char, $metaCharacters)) {
@ -131,11 +111,7 @@ class gdbMySQL extends gdbDriver {
$vChar = $this->_oItemClassInstance->_inFilter($char);
if ($char != $vChar) {
if (in_array($vChar, $metaCharacters)) {
$addChars[] = "\\\\" . $vChar;
} else {
$addChars[] = $vChar;
}
$addChars[] = in_array($vChar, $metaCharacters) ? "\\\\" . $vChar : $vChar;
}
}
@ -144,7 +120,7 @@ class gdbMySQL extends gdbDriver {
}
$restriction = "'" . implode("", $aliasSearch) . "'";
$sWhereStatement = implode(" ", array($sField, "REGEXP", $restriction));
$sWhereStatement = implode(" ", [$sField, "REGEXP", $restriction]);
break;
case "fulltext":
@ -152,9 +128,9 @@ class gdbMySQL extends gdbDriver {
break;
case "in":
if (is_array($sRestriction)) {
$items = array();
$items = [];
foreach ($sRestriction as $key => $sRestrictionItem) {
foreach ($sRestriction as $sRestrictionItem) {
$items[] = "'" . $this->_oItemClassInstance->_inFilter($sRestrictionItem) . "'";
}
@ -163,14 +139,14 @@ class gdbMySQL extends gdbDriver {
$sRestriction = "'" . $sRestriction . "'";
}
$sWhereStatement = implode(" ", array($sField, "IN (", $sRestriction, ")"));
$sWhereStatement = implode(" ", [$sField, "IN (", $sRestriction, ")"]);
break;
case "notin":
if (is_array($sRestriction)) {
$items = array();
$items = [];
foreach ($sRestriction as $key => $sRestrictionItem) {
$items[] = "'" . $this->_oItemClassInstance->_inFilter($sRestrictionItem) . "'";
foreach ($sRestriction as $Restriction) {
$items[] = "'" . $this->_oItemClassInstance->_inFilter($Restriction) . "'";
}
$sRestriction = implode(", ", $items);
@ -178,17 +154,15 @@ class gdbMySQL extends gdbDriver {
$sRestriction = "'" . $sRestriction . "'";
}
$sWhereStatement = implode(" ", array($sField, "NOT IN (", $sRestriction, ")"));
$sWhereStatement = implode(" ", [$sField, "NOT IN (", $sRestriction, ")"]);
break;
default :
$sRestriction = "'" . $this->_oItemClassInstance->_inFilter($sRestriction) . "'";
$sWhereStatement = implode(" ", array($sField, $sOperator, $sRestriction));
$sWhereStatement = implode(" ", [$sField, $sOperator, $sRestriction]);
}
return $sWhereStatement;
}
}
?>
}

View file

@ -0,0 +1,515 @@
<?php
namespace ConLite\GenericDb;
use stdClass;
abstract class Item extends ItemBaseAbstract
{
/**
* @var string
*/
public $_lastSQL;
/**
* Storage of the source table to use for the user informations
* @var array
*/
public $values;
/**
* Storage of the fields which were modified, where the keys are the
* fieldnames and the values just simple booleans.
* @var array
*/
protected $modifiedValues;
/**
* Stores the old primary key, just in case somebody wants to change it
* @var string
*/
protected $oldPrimaryKey;
/**
* List of funcion names of the filters used when data is stored to the db.
* @var array
*/
protected $_arrInFilters = ['urlencode', 'clHtmlSpecialChars', 'addslashes'];
/**
* List of funcion names of the filtersused when data is retrieved from the db
* @var array
*/
protected $_arrOutFilters = ['stripslashes', 'htmldecode', 'urldecode'];
/**
* Class name of meta object
* @var string
*/
protected $_metaObject;
/**
* Constructor function
*
* @param string $sTable The table to use as information source
* @param string $sPrimaryKey The primary key to use
* @param int $iLifetime
*/
public function __construct($sTable = '', $sPrimaryKey = '', $iLifetime = 10)
{
parent::__construct($sTable, $sPrimaryKey, get_parent_class($this), $iLifetime);
}
function __destruct()
{
//print_r(self::$_oCache);
}
/**
* Loads an item by colum/field from the database.
*
* @param string $sField Specifies the field
* @param mixed $mValue Specifies the value
* @param bool $bSafe Use inFilter or not
* @return bool True if the load was successful
*/
public function loadBy($sField, mixed $mValue, $bSafe = true): bool
{
if ($bSafe) {
$mValue = $this->_inFilter($mValue);
}
if ($sField === $this->primaryKey) {
$aRecordSet = self::$_oCache->getItem($this->table . "_" . $mValue);
} else {
$aRecordSet = self::$_oCache->getItemByProperty($this->table . "_" . $sField, $mValue);
}
if ($aRecordSet) {
// entry in cache found, load entry from cache
$this->loadByRecordSet($aRecordSet);
return true;
}
// SQL-Statement to select by field
$sql = sprintf("SELECT * FROM `%s` WHERE %s = '%s'", $this->table, $sField, $mValue);
//$sql = $this->db->prepare($sql, $this->table, $sField, $mValue);
// Query the database
$this->db->query($sql);
$this->_lastSQL = $sql;
if ($this->db->num_rows() > 1) {
$sMsg = "Tried to load a single line with field $sField and value $mValue from "
. $this->table . " but found more than one row";
cWarning(__FILE__, __LINE__, $sMsg);
}
// Advance to the next record, return false if nothing found
if (!$this->db->next_record()) {
return false;
}
$this->loadByRecordSet($this->db->toArray());
return true;
}
/**
* Loads an item by passed where clause from the database.
* This function is expensive, since it executes allways a query to the database
* to retrieve the primary key, even if the record set is aleady cached.
* NOTE: Passed value has to be escaped before. This will not be done by this function.
*
* @param string $sWhere The where clause like 'idart = 123 AND idlang = 1'
* @return bool True if the load was successful
*/
protected function _loadByWhereClause($sWhere)
{
// SQL-Statement to select by whee clause
$sql = sprintf("SELECT %s AS pk FROM `%s` WHERE ", $this->primaryKey, $this->table) . $sWhere;
//$sql = $this->db->prepare($sql, $this->primaryKey, $this->table);
// Query the database
$this->db->query($sql);
$this->_lastSQL = $sql;
if ($this->db->num_rows() > 1) {
$sMsg = "Tried to load a single line with where clause '" . $sWhere . "' from "
. $this->table . " but found more than one row";
cWarning(__FILE__, __LINE__, $sMsg);
}
// Advance to the next record, return false if nothing found
if (!$this->db->next_record()) {
return false;
}
$id = $this->db->f('pk');
return $this->loadByPrimaryKey($id);
}
/**
* Loads an item by ID from the database.
*
* @param string $mValue Specifies the primary key value
* @return bool True if the load was successful
*/
public function loadByPrimaryKey($mValue)
{
$bSuccess = $this->loadBy($this->primaryKey, $mValue);
if (($bSuccess == true) && method_exists($this, '_onLoad')) {
$this->_onLoad();
}
return $bSuccess;
}
/**
* Loads an item by it's recordset.
*
* @param array $aRecordSet The recordset of the item
*/
public function loadByRecordSet(array $aRecordSet)
{
$this->values = $aRecordSet;
$this->oldPrimaryKey = $this->values[$this->primaryKey];
$this->virgin = false;
self::$_oCache->addItem($this->table . "_" . $this->oldPrimaryKey, $this->values);
}
/**
* Checks if a the item is already loaded.
* @return boolean
*/
public function isLoaded()
{
return !$this->virgin;
}
/**
* Function which is called whenever an item is loaded.
* Inherited classes should override this function if desired.
*
* @return void
*/
protected function _onLoad()
{
}
/**
* Gets the value of a specific field.
*
* @param string $sField Specifies the field to retrieve
* @return mixed Value of the field
*/
public function getField($sField)
{
if ($this->virgin == true) {
$this->lasterror = 'No item loaded';
return false;
}
return $this->_outFilter($this->values[$sField]);
}
/**
* Wrapper for getField (less to type).
*
* @param string $sField Specifies the field to retrieve
* @return mixed Value of the field
*/
public function get($sField)
{
return $this->getField($sField);
}
/**
* Sets the value of a specific field.
*
* @param string $sField Field name
* @param string $mValue Value to set
* @param bool $bSafe Flag to run defined inFilter on passed value
*/
public function setField($sField, $mValue, $bSafe = true): bool
{
if ($this->virgin == true) {
$this->lasterror = 'No item loaded';
return false;
}
$this->modifiedValues[$sField] = true;
if ($sField == $this->primaryKey) {
$this->oldPrimaryKey = $this->values[$sField];
}
$this->values[$sField] = $bSafe == true ? $this->_inFilter($mValue) : $mValue;
return true;
}
/**
* Shortcut to setField.
*
* @param string $sField Field name
* @param string $mValue Value to set
* @param bool $bSafe Flag to run defined inFilter on passed value
*/
public function set($sField, $mValue, $bSafe = true)
{
return $this->setField($sField, $mValue, $bSafe);
}
/**
* Stores the loaded and modified item to the database.
*
* @return bool
*/
public function store()
{
if (!$this->isLoaded()) {
$this->lasterror = 'No item loaded';
return false;
}
$sql = 'UPDATE `' . $this->table . '` SET ';
$first = true;
if (!is_array($this->modifiedValues)) {
return true;
}
foreach (array_keys($this->modifiedValues) as $key) {
if ($first == true) {
$sql .= "`$key` = '" . $this->values[$key] . "'";
$first = false;
} else {
$sql .= ", `$key` = '" . $this->values[$key] . "'";
}
}
$sql .= " WHERE " . $this->primaryKey . " = '" . $this->oldPrimaryKey . "'";
$this->db->query($sql);
$this->_lastSQL = $sql;
if ($this->db->affected_rows() > 0) {
self::$_oCache->addItem($this->table . "_" . $this->oldPrimaryKey, $this->values);
}
return $this->db->affected_rows() >= 1;
}
/**
* Returns current item data as an assoziative array.
*/
public function toArray(): array|false
{
if ($this->virgin == true) {
$this->lasterror = 'No item loaded';
return false;
}
$aReturn = [];
foreach (array_keys($this->values) as $field) {
$aReturn[$field] = $this->getField($field);
}
return $aReturn;
}
/**
* Returns current item data as an object.
*/
public function toObject(): stdClass|false
{
$return = $this->toArray();
return (false !== $return) ? (object)$return : $return;
}
/**
* Sets a custom property.
*
* @param string $sType Specifies the type
* @param string $sName Specifies the name
* @param mixed $mValue Specifies the value
* @return bool
*/
public function setProperty($sType, $sName, mixed $mValue)
{
// If this object wasn't loaded before, return false
if ($this->virgin == true) {
$this->lasterror = 'No item loaded';
return false;
}
// Set the value
$oProperties = $this->_getPropertiesCollectionInstance();
return $oProperties->setValue(
$this->primaryKey, $this->get($this->primaryKey), $sType, $sName, $mValue
);
}
/**
* Returns a custom property.
*
* @param string $sType Specifies the type
* @param string $sName Specifies the name
* @return mixed Value of the given property or false
*/
public function getProperty($sType, $sName)
{
// If this object wasn't loaded before, return false
if ($this->virgin == true) {
$this->lasterror = 'No item loaded';
return false;
}
// Return the value
$oProperties = $this->_getPropertiesCollectionInstance();
return $oProperties->getValue(
$this->primaryKey, $this->get($this->primaryKey), $sType, $sName
);
}
/**
* Deletes a custom property.
*
* @param string $sType Specifies the type
* @param string $sName Specifies the name
* @return bool
*/
public function deleteProperty($sType, $sName)
{
// If this object wasn't loaded before, return false
if ($this->virgin == true) {
$this->lasterror = 'No item loaded';
return false;
}
// Delete the value
$oProperties = $this->_getPropertiesCollectionInstance();
return $oProperties->deleteValue(
$this->primaryKey, $this->get($this->primaryKey), $sType, $sName
);
}
/**
* Deletes a custom property by its id.
*
* @param int $idprop Id of property
* @return bool
*/
public function deletePropertyById($idprop)
{
$oProperties = $this->_getPropertiesCollectionInstance();
return $oProperties->delete($idprop);
}
/**
* Deletes the current item
*
* @return void
*/
// Method doesn't work, remove in future versions
// function delete()
// {
// $this->_collectionInstance->delete($item->get($this->primaryKey));
//}
/**
* Define the filter functions used when data is being stored or retrieved
* from the database.
*
* Examples:
* <pre>
* $obj->setFilters(array('addslashes'), array('stripslashes'));
* $obj->setFilters(array('htmlencode', 'addslashes'), array('stripslashes', 'htmlencode'));
* </pre>
*
* @param array $aInFilters Array with function names
* @param array $aOutFilters Array with function names
*
* @return void
*/
public function setFilters($aInFilters = [], $aOutFilters = [])
{
$this->_arrInFilters = $aInFilters;
$this->_arrOutFilters = $aOutFilters;
}
/**
* Filters the passed data using the functions defines in the _arrInFilters array.
*
* @param mixed $mData Data to filter
* @return mixed Filtered data
* @see setFilters
*
* @todo This method is used from public scope, but it should be protected
*
*/
public function _inFilter(mixed $mData)
{
if (is_numeric($mData) || is_array($mData)) {
return $mData;
}
if (is_null($mData)) {
$mData = '';
}
foreach ($this->_arrInFilters as $_arrInFilter) {
if (function_exists($_arrInFilter)) {
$mData = $_arrInFilter($mData);
}
}
return $mData;
}
/**
* Filters the passed data using the functions defines in the _arrOutFilters array.
*
* @param mixed $mData Data to filter
* @return mixed Filtered data
* @see setFilters
*
*/
protected function _outFilter(mixed $mData)
{
if (is_numeric($mData))
return $mData;
foreach ($this->_arrOutFilters as $_arrOutFilter) {
if (function_exists($_arrOutFilter)) {
$mData = $_arrOutFilter($mData);
}
}
return $mData;
}
protected function _setMetaObject($sObjectName)
{
$this->_metaObject = $sObjectName;
}
public function getMetaObject()
{
global $_metaObjectCache;
if (!is_array($_metaObjectCache)) {
$_metaObjectCache = [];
}
$sClassName = $this->_metaObject;
$qclassname = strtolower($sClassName);
if (array_key_exists($qclassname, $_metaObjectCache) && is_object($_metaObjectCache[$qclassname])) {
if (strtolower($_metaObjectCache[$qclassname]::class) === $qclassname) {
$_metaObjectCache[$qclassname]->setPayloadObject($this);
return $_metaObjectCache[$qclassname];
}
}
if (class_exists($sClassName)) {
$_metaObjectCache[$qclassname] = new $sClassName($this);
return $_metaObjectCache[$qclassname];
}
}
}

View file

@ -1,12 +1,16 @@
<?php
/**
*
*/
namespace ConLite\GenericDb;
// security check
defined('CON_FRAMEWORK') or die('Illegal call');
abstract class cItemBaseAbstract {
use DB_ConLite;
use PropertyCollection;
abstract class ItemBaseAbstract
{
/**
* Database instance, contains the database object
@ -29,9 +33,9 @@ abstract class cItemBaseAbstract {
/**
* Item cache instance
* @var Contenido_ItemCache
* @var ItemCache
*/
protected static $_oCache;
protected static ItemCache $_oCache;
/**
* GenericDB settings, see $cfg['sql']
@ -85,17 +89,17 @@ abstract class cItemBaseAbstract {
* @var string
*/
protected $_className;
protected $_bDebug;
/**
* Sets some common properties
*
* @param string $sTable Name of table
* @param string $sPrimaryKey Primary key of table
* @param string $sClassName Name of parent class
* @param int $iLifetime Lifetime of the object in seconds (NOT USED!)
* @throws Contenido_ItemException If table name or primary key is not set
* @param string $sTable Name of table
* @param string $sPrimaryKey Primary key of table