diff --git a/branches/php7/conlib/auth.inc b/branches/php7/conlib/auth.inc new file mode 100644 index 0000000..a6ede02 --- /dev/null +++ b/branches/php7/conlib/auth.inc @@ -0,0 +1,338 @@ + + * @con_notice + * + * + * @package ContenidoBackendArea + * @version + * @author Boris Erdmann, Kristian Koehntopp, Massimiliano Masserelli + * @copyright four for business AG + * @license http://www.contenido.org/license/LIZENZ.txt + * @link http://www.4fb.de + * @link http://www.contenido.org + * @since file available since contenido release + * @deprecated file deprecated in contenido release + * + * {@internal + * created 2002-07-21 + * modified 2008-07-03, bilal arslan, added security fix + * + * $Id: auth.inc 1315 2011-03-03 00:02:52Z xmurrix $: + * }} + * + */ +if(!defined('CON_FRAMEWORK')) { + die('Illegal call'); +} + +class Auth { + var $classname = "Auth"; + var $persistent_slots = array("auth"); + + var $lifetime = 15; ## Max allowed idle time before + ## reauthentication is necessary. + ## If set to 0, auth never expires. + + var $refresh = 0; ## Refresh interval in minutes. + ## When expires auth data is refreshed + ## from db using auth_refreshlogin() + ## method. Set to 0 to disable refresh + + var $mode = "log"; ## "log" for login only systems, + ## "reg" for user self registration + + var $magic = ""; ## Used in uniqid() generation + + var $nobody = false; ## If true, a default auth is created... + + var $cancel_login = "cancel_login"; ## The name of a button that can be + ## used to cancel a login form + + ## End of user qualifiable settings. + + var $auth = array(); ## Data array + var $in = false; + var $db; + + ## + ## Initialization + ## + function start() { + $cl = $this->cancel_login; + global $sess, $$cl; + + ## This is for performance, I guess but I'm not sure if it could + ## be safely removed -- negro + if (! $this->in) { + $sess->register("auth"); + $this->in = true; + } + + ## back compatibility: if d_c is set, create db object + if(isset($this->database_class)) { + $class = $this->database_class; + $this->db = new $class; + } + + # Check current auth state. Should be one of + # 1) Not logged in (no valid auth info or auth expired) + # 2) Logged in (valid auth info) + # 3) Login in progress (if $$cl, revert to state 1) + if ($this->is_authenticated()) { + $uid = $this->auth["uid"]; + switch ($uid) { + case "form": + # Login in progress + if ($$cl) { + # If $$cl is set, delete all auth info + # and set state to "Not logged in", so eventually + # default or automatic authentication may take place + $this->unauth(); + $state = 1; + } else { + # Set state to "Login in progress" + $state = 3; + } + break; + default: + # User is authenticated and auth not expired + $state = 2; + break; + } + } else { + # User is not (yet) authenticated + $this->unauth(); + $state = 1; + } + + switch ($state) { + case 1: + # No valid auth info or auth is expired + + # Check for user supplied automatic login procedure + if ( $uid = $this->auth_preauth() ) { + $this->auth["uid"] = $uid; + $this->auth["exp"] = time() + (60 * $this->lifetime); + $this->auth["refresh"] = time() + (60 * $this->refresh); + return true; + } + + # Check for "log" vs. "reg" mode + switch ($this->mode) { + case "yes": + case "log": + if ($this->nobody) { + # Authenticate as nobody + $this->auth["uid"] = "nobody"; + # $this->auth["uname"] = "nobody"; + $this->auth["exp"] = 0x7fffffff; + $this->auth["refresh"] = 0x7fffffff; + return true; + } else { + # Show the login form + $this->auth_loginform(); + $this->auth["uid"] = "form"; + $this->auth["exp"] = 0x7fffffff; + $this->auth["refresh"] = 0x7fffffff; + $sess->freeze(); + exit; + } + break; + case "reg": + if ($this->nobody) { + # Authenticate as nobody + $this->auth["uid"] = "nobody"; + # $this->auth["uname"] = "nobody"; + $this->auth["exp"] = 0x7fffffff; + $this->auth["refresh"] = 0x7fffffff; + return true; + } else { + # Show the registration form + $this->auth_registerform(); + $this->auth["uid"] = "form"; + $this->auth["exp"] = 0x7fffffff; + $this->auth["refresh"] = 0x7fffffff; + $sess->freeze(); + exit; + } + break; + default: + # This should never happen. Complain. + echo "Error in auth handling: no valid mode specified.\n"; + $sess->freeze(); + exit; + } + break; + case 2: + # Valid auth info + # Refresh expire info + ## DEFAUTH handling: do not update exp for nobody. + if ($uid != "nobody") + $this->auth["exp"] = time() + (60 * $this->lifetime); + break; + case 3: + # Login in progress, check results and act accordingly + switch ($this->mode) { + case "yes": + case "log": + #if ( $uid = $this->auth_preauth() ) { + # $this->auth["uid"] = $uid; + # $this->auth["exp"] = time() + (60 * $this->lifetime); + # $this->auth["refresh"] = time() + (60 * $this->refresh); + # return true; + #} + + if ( $uid = $this->auth_validatelogin() ) { + $this->auth["uid"] = $uid; + $this->auth["exp"] = time() + (60 * $this->lifetime); + $this->auth["refresh"] = time() + (60 * $this->refresh); + return true; + } else { + $this->auth_loginform(); + $this->auth["uid"] = "form"; + $this->auth["exp"] = 0x7fffffff; + $this->auth["refresh"] = 0x7fffffff; + $sess->freeze(); + exit; + } + break; + case "reg": + if ($uid = $this->auth_doregister()) { + $this->auth["uid"] = $uid; + $this->auth["exp"] = time() + (60 * $this->lifetime); + $this->auth["refresh"] = time() + (60 * $this->refresh); + return true; + } else { + $this->auth_registerform(); + $this->auth["uid"] = "form"; + $this->auth["exp"] = 0x7fffffff; + $this->auth["refresh"] = 0x7fffffff; + $sess->freeze(); + exit; + } + break; + default: + # This should never happen. Complain. + echo "Error in auth handling: no valid mode specified.\n"; + $sess->freeze(); + exit; + break; + } + break; + default: + # This should never happen. Complain. + echo "Error in auth handling: invalid state reached.\n"; + $sess->freeze(); + exit; + break; + } + } + + function login_if( $t ) { + if ( $t ) { + $this->unauth(); # We have to relogin, so clear current auth info + $this->nobody = false; # We are forcing login, so default auth is + # disabled + $this->start(); # Call authentication code + } + } + + function unauth($nobody = false) { + $this->auth["uid"] = ""; + $this->auth["perm"] = ""; + $this->auth["exp"] = 0; + + ## Back compatibility: passing $nobody to this method is + ## deprecated + if ($nobody) { + $this->auth["uid"] = "nobody"; + $this->auth["perm"] = ""; + $this->auth["exp"] = 0x7fffffff; + } + } + + + function logout($nobody = "") { + global $sess; + $sess->unregister("auth"); + unset($this->auth["uname"]); + $this->unauth($nobody == "" ? $this->nobody : $nobody); + $sess->freeze(); + return true; + } + + function is_authenticated() { + if ( + isset($this->auth["uid"]) + && + $this->auth["uid"] + && + (($this->lifetime <= 0) || (time() < $this->auth["exp"])) + ) { + # If more than $this->refresh minutes are passed since last check, + # perform auth data refreshing. Refresh is only done when current + # session is valid (registered, not expired). + if ( + ($this->refresh > 0) + && + ($this->auth["refresh"]) + && + ($this->auth["refresh"] < time()) + ) { + if ( $this->auth_refreshlogin() ) { + $this->auth["refresh"] = time() + (60 * $this->refresh); + } else { + return false; + } + } + + return $this->auth["uid"]; + } else { + return false; + } + } + + ######################################################################## + ## + ## Helper functions + ## + function url() { + return $GLOBALS["sess"]->self_url(); + } + + function purl() { + print $GLOBALS["sess"]->self_url(); + } + + ## This method can authenticate a user before the loginform + ## is being displayed. If it does, it must set a valid uid + ## (i.e. nobody IS NOT a valid uid) just like auth_validatelogin, + ## else it shall return false. + + function auth_preauth() { return false; } + + ## + ## Authentication dummies. Must be overridden by user. + ## + + function auth_loginform() { ; } + + function auth_validatelogin() { ; } + + function auth_refreshlogin() { ; } + + function auth_registerform() { ; } + + function auth_doregister() { ; } +} +?> diff --git a/branches/php7/conlib/ct_file.inc b/branches/php7/conlib/ct_file.inc new file mode 100644 index 0000000..de2b236 --- /dev/null +++ b/branches/php7/conlib/ct_file.inc @@ -0,0 +1,107 @@ + + * @con_notice + * + * + * @package ContenidoBackendArea + * @version 1.1 + * @author Oliver Teuber + * @copyright four for business AG + * @license http://www.contenido.org/license/LIZENZ.txt + * @link http://www.4fb.de + * @link http://www.contenido.org + * @since file available since contenido release + * @deprecated file deprecated in contenido release + * + * {@internal + * created 2000-01-01 + * modified 2008-07-03, bilal arslan, added security fix + * + * $Id: ct_file.inc 740 2008-08-27 10:45:04Z timo.trautmann $: + * }} + * + */ + +if(!defined('CON_FRAMEWORK')) { + die('Illegal call'); +} + +class CT_File { + ## + ## Define these parameters by overwriting or by + ## deriving your own class from it (recommened) + ## + + var $file_path = ""; ## Path where to store the session files + ## writable by the web server UID + + ## end of configuration + + function ac_start() { + # Not needed in this instance + } + + function ac_get_lock() { + # Not needed in this instance + } + + function ac_release_lock() { + # Not needed in this instance + } + + function ac_newid($str, $name) { + return $str; + } + + function ac_store($id, $name, $str) { + + $f=fopen($this->file_path . "$id$name",'w+'); + if($f<0) + { + return false; + } + fputs($f,urlencode($str)); + fclose($f); + + return true; + } + + function ac_delete($id, $name) { + unlink($this->file_path."$id$name"); + } + + function ac_gc($gc_time, $name) { + } + + function ac_halt($s) { + echo "$s"; + exit; + } + + function ac_get_value($id, $name) { + if(file_exists($this->file_path."$id$name")) + { + + $f=fopen($this->file_path."$id$name",'r'); + if($f<0) + return ''; + + $s=fgets($f,10240); + fclose($f); + return urldecode($s); + } + else + return ''; + } +} +?> diff --git a/branches/php7/conlib/ct_ldap.inc b/branches/php7/conlib/ct_ldap.inc new file mode 100644 index 0000000..c478cf5 --- /dev/null +++ b/branches/php7/conlib/ct_ldap.inc @@ -0,0 +1,118 @@ + + * @copyright four for business AG + * @license http://www.contenido.org/license/LIZENZ.txt + * @link http://www.4fb.de + * @link http://www.contenido.org + * @since file available since contenido release + * @deprecated file deprecated in contenido release + * + * {@internal + * created 2000-01-01 + * modified 2008-07-03, bilal arslan, added security fix + * + * $Id: ct_ldap.inc 1315 2011-03-03 00:02:52Z xmurrix $: + * }} + * + */ + +if(!defined('CON_FRAMEWORK')) { + die('Illegal call'); +} + +class CT_Ldap { + ## + ## Configurable parameters + ## + var $ldap_host = "localhost"; + var $ldap_port = 389; + var $basedn = "dc=your-domain, dc=com"; + var $rootdn = "cn=root, dc=your-domain, dc=com"; + var $rootpw = "secret"; + var $objclass = "phplibdata"; + + ## end of configuration + + var $ds; + + function ac_start() { + $this->ds = ldap_connect($this->ldap_host, $this->ldap_port); + if(!$this->ds) { + $this->ac_halt("LDAP connect failed"); + } + if(!ldap_bind($this->ds, $this->rootdn, $this->rootpw)) { + $this->ac_halt("LDAP bind failed"); + } + } + + function ac_halt($msg="") { + echo "Session_ldap failed: ".htmlentities($msg)."

\n"; + exit; + } + + function ac_store($id, $name, $str) { + $dn = "cn=$id_$name, ".$this->basedn; + $entry = array( + "cn" => "$id_$name", + "str" => $str, + "objectclass" => $this->objclass + ); + if(!@ldap_modify($this->ds, $dn, $entry)) { + if(!ldap_add($this->ds, $dn, $entry)) { + $this->ac_halt("LDAP add failed"); + } + } + } + + function ac_delete($id, $name) { + ldap_delete($this->ds, "cn=$id_$name, ".$this->basedn); + } + + function ac_get_value($id, $name) { + $sr = ldap_search($this->ds, $this->basedn, "cn=$id_$name"); + $inf = ldap_get_entries($this->ds, $sr); + $str = $inf[0]["str"][0]; + ldap_free_result($sr); + return $str; + } + + function ac_release_lock() { + + } + + function ac_get_lock() { + + } + + function ac_newid($str, $name) { + return $str; + } + + function ac_auth($username, $password) { + ## we need a username and a md5() encrypted password + $sr = ldap_search($this->ds, $this->basedn, "username=$username"); + if(ldap_count_entries($this->ds, $sr) > 0) { + $inf = ldap_get_entries($this->ds, $sr); + $passmd5 = $inf[0]["password"][0]; + if(md5($password) == $passmd5) { + return array($inf[0]["uid"][0], + $inf[0]["perms"][0]); + } + } + return array(); + } +}; +?> diff --git a/branches/php7/conlib/ct_null.inc b/branches/php7/conlib/ct_null.inc new file mode 100644 index 0000000..668d33e --- /dev/null +++ b/branches/php7/conlib/ct_null.inc @@ -0,0 +1,72 @@ + + * @author Sascha Schumann + * @copyright four for business AG + * @license http://www.contenido.org/license/LIZENZ.txt + * @link http://www.4fb.de + * @link http://www.contenido.org + * @since file available since contenido release + * @deprecated file deprecated in contenido release + * + * {@internal + * created 2000-01-01 + * modified 2008-07-03, bilal arslan, added security fix + * + * $Id: ct_null.inc 1315 2011-03-03 00:02:52Z xmurrix $: + * }} + * + */ + if(!defined('CON_FRAMEWORK')) { + die('Illegal call'); +} + +class CT_Null { + function ac_start() { + } + + function ac_get_lock() { + } + + function ac_release_lock() { + } + + function ac_newid($str, $name) { + return $str; + } + + function ac_store($id, $name, $str) { + return true; + } + + function ac_delete($id, $name) { + } + + function ac_gc($gc_time, $name) { + } + + function ac_halt($s) { + echo "$s"; + exit; + } + + function ac_get_value($id, $name) { + return ""; + } +} +?> diff --git a/branches/php7/conlib/ct_session.inc b/branches/php7/conlib/ct_session.inc new file mode 100644 index 0000000..691e214 --- /dev/null +++ b/branches/php7/conlib/ct_session.inc @@ -0,0 +1,122 @@ + + * @copyright four for business AG + * @license http://www.contenido.org/license/LIZENZ.txt + * @link http://www.4fb.de + * @link http://www.contenido.org + * @since file available since contenido release 4.8.15 + * + * {@internal + * created 2011-03-18 + * + * $Id: $: + * }} + * + */ + +if (!defined('CON_FRAMEWORK')) { + die('Illegal call'); +} + + +class CT_Session +{ + /** + * Namespace in superglobal $_SESSION + * @var string + */ + protected $_sNameSpace = 'ct_session_ns'; + + /** + * Session container's intialize method, configures PHP session and starts + * it, if not done before. + * + * @param array $aOptions Session container configuration as follows: + * - $aOptions['namespace'] (string) Namespace to use + * - $aOptions['session.*'] (string) Each possible session configuration + * see php.ini + */ + public function ac_start(array $aOptions = array()) + { + // set namespace + if (isset($aOptions['namespace'])) { + $this->_sNameSpace = $aOptions['namespace']; + } + + // configure session + foreach ($aOptions as $k => $v) { + if (strpos($k, 'session.') === 0) { + @ini_set($k, $v); + } + } + + if (!isset($_SESSION)) { + session_start(); + } + + if (!isset($_SESSION[$this->_sNameSpace])) { + $_SESSION[$this->_sNameSpace] = array(); + } + } + + public function ac_get_lock() + { + // no need to lock session + } + + public function ac_release_lock() + { + // no need to release lock session + } + + public function ac_gc($gc_time, $name) + { + // no need for garbace collection, will be done by PHP's gc + } + + public function ac_store($id, $name, $str) + { + $_SESSION[$this->_sNameSpace][$name] = $str; + return true; + } + + public function ac_get_value($id, $name) + { + return isset($_SESSION[$this->_sNameSpace][$name]) ? $_SESSION[$this->_sNameSpace][$name] : ''; + } + + public function ac_delete($id, $name) + { + // don't destroy session, untill backend and frontend uses it + #session_destroy(); + if (isset($_SESSION[$this->_sNameSpace][$name])) { + $_SESSION[$this->_sNameSpace][$name] = ''; + } + } + + public function ac_newid($str, $name) + { + session_regenerate_id(false); + return session_id(); + } + + public function ac_halt($s) + { + die($s); + } +} + +?> \ No newline at end of file diff --git a/branches/php7/conlib/ct_shm.inc b/branches/php7/conlib/ct_shm.inc new file mode 100644 index 0000000..c0c7b19 --- /dev/null +++ b/branches/php7/conlib/ct_shm.inc @@ -0,0 +1,117 @@ + + * @con_notice + * + * + * @package ContenidoBackendArea + * @version 1.2 + * @author Sascha Schumann + * @copyright four for business AG + * @license http://www.contenido.org/license/LIZENZ.txt + * @link http://www.4fb.de + * @link http://www.contenido.org + * @since file available since contenido release + * @deprecated file deprecated in contenido release + * + * {@internal + * created 2000-01-01 + * modified 2008-07-03, bilal arslan, added security fix + * + * $Id: ct_shm.inc 1315 2011-03-03 00:02:52Z xmurrix $: + * }} + * + */ + + if(!defined('CON_FRAMEWORK')) { + die('Illegal call'); +} + +class CT_Shm { + ## + ## Define these parameters by overwriting or by + ## deriving your own class from it (recommened) + ## + + var $max_sessions = 500; ## maximum supported sessions + var $shm_key = 900000; ## key of shared memory segment (unique) + var $shm_size = 64000; ## size in bytes + + ## end of configuration + + var $shmid; ## our shared memory handle + var $semid; ## our semaphore handle + + function extract($id) { + return substr($id, 0, strpos($id, "_")); + } + + function ac_start() { + $this->shmid = shm_attach($this->shm_key, $this->shm_size, 0600); + } + + function ac_get_lock() { + $this->semid = sem_get($this->shm_key + 1); + sem_acquire($this->semid); + } + + function ac_release_lock() { + shm_detach($this->shmid); + sem_release($this->semid); + } + + function ac_newid($str, $name) { + for($i = 1; $i <= $this->max_sessions && + (@shm_get_var($this->shmid, $i) != false); $i++); + $id = $i."_".$str; + $this->ac_store($id, $name, ""); + return $id; + } + + function ac_store($id, $name, $str) { + $val = "$id;".urlencode($name).";".urlencode($str).";".time(); + shm_put_var($this->shmid, $this->extract($id), $val); + return true; + } + + function ac_delete($id, $name) { + shm_remove_var($this->shmid, $this->extract($id)); + } + + function ac_gc($gc_time, $name) { + $cmp = time() - $gc_time * 60; + for($i = 1; $i <= $this->max_sessions; $i++) { + if(($val = @shm_get_var($this->shmid, $i)) != false) { + $dat = explode(";", $val); + if($name == $dat[1] && intval($dat[3]) < $cmp) { + shm_remove_var($this->shmid, $i); + } + } + } + } + + function ac_halt($s) { + echo "$s"; + exit; + } + + function ac_get_value($id, $name) { + $i = $this->extract($id); + $var = shm_get_var($this->shmid, $i); + if($var == "") return(""); + $dat = explode(";", $var); + ## if classname or md5 id does not match... + if($name != urldecode($dat[1]) || $dat[0] != $id) + $this->ac_halt("security stop"); + return urldecode($dat[2]); + } +} +?> diff --git a/branches/php7/conlib/ct_sql.inc b/branches/php7/conlib/ct_sql.inc new file mode 100644 index 0000000..60b73d0 --- /dev/null +++ b/branches/php7/conlib/ct_sql.inc @@ -0,0 +1,204 @@ + + * @copyright four for business AG + * @license http://www.contenido.org/license/LIZENZ.txt + * @link http://www.4fb.de + * @link http://www.contenido.org + * @since file available since contenido release + * @deprecated file deprecated in contenido release + * + * {@internal + * created 2002-07-21 + * modified 2008-07-03, bilal arslan, added security fix + * modified 2009-11-06, Murat Purc, replaced deprecated functions (PHP 5.3 ready) + * + * $Id: ct_sql.inc 1094 2009-11-06 01:22:13Z xmurrix $: + * }} + * + */ + + if(!defined('CON_FRAMEWORK')) { + die('Illegal call'); +} + +class CT_Sql { + ## + ## Define these parameters by overwriting or by + ## deriving your own class from it (recommened) + ## + + + var $database_lock_semaphore = ""; + + var $encoding_mode = "base64"; + + ## end of configuration + + var $db; + + function ac_start() { + $name = $this->database_class; + $this->db = new $name; + } + + function ac_get_lock() { + if ( "" != $this->database_lock_semaphore ) { + $query = sprintf("SELECT get_lock('%s')", $this->database_lock_semaphore); + while ( ! $this->db->query($query)) { + $t = 1 + time(); while ( $t > time() ) { ; } + } + } + } + + function ac_release_lock() { + if ( "" != $this->database_lock_semaphore ) { + $query = sprintf("SELECT release_lock('%s')", $this->database_lock_semaphore); + $this->db->query($query); + } + } + + function ac_gc($gc_time, $name) { + +// Security Fix + $timeout = time(); + $sqldate = date("YmdHis", $timeout - (Contenido_Security::escapeDB($gc_time, $this->db) * 60)); + $this->db->query(sprintf("DELETE FROM %s WHERE changed < '%s' AND name = '%s'", + $this->database_table, + $sqldate, + Contenido_Security::escapeDB($name, $this->db))); + } + + function ac_store($id, $name, $str) { + +// Security Fix + $ret = true; + + switch ( $this->encoding_mode ) { + case "slashes": + $str = addslashes($name . ":" . $str); + break; + + case "base64": + default: + $str = base64_encode($name . ":" . $str); + }; + + $name = addslashes($name); + + ## update duration of visit + global $HTTP_REFERER, $HTTP_USER_AGENT, $REMOTE_ADDR; + + $now = date("YmdHis", time()); + $uquery = sprintf("update %s set val='%s', changed='%s' where sid='%s' and name='%s'", + $this->database_table, + $str, + $now, + Contenido_Security::escapeDB($id, $this->db), + Contenido_Security::escapeDB($name, $this->db)); + $squery = sprintf("select count(*) from %s where val='%s' and changed='%s' and sid='%s' and name='%s'", + $this->database_table, + $str, + $now, + Contenido_Security::escapeDB($id, $this->db), + Contenido_Security::escapeDB($name, $this->db)); + $iquery = sprintf("insert into %s ( sid, name, val, changed ) values ('%s', '%s', '%s', '%s')", + $this->database_table, + Contenido_Security::escapeDB($id, $this->db), + Contenido_Security::escapeDB($name, $this->db), + $str, + $now); + + $this->db->lock($this->database_table); + $this->db->query($uquery); + + # FIRST test to see if any rows were affected. + # Zero rows affected could mean either there were no matching rows + # whatsoever, OR that the update statement did match a row but made + # no changes to the table data (i.e. UPDATE tbl SET col = 'x', when + # "col" is _already_ set to 'x') so then, + # SECOND, query(SELECT...) on the sid to determine if the row is in + # fact there, + # THIRD, verify that there is at least one row present, and if there + # is not, then + # FOURTH, insert the row as we've determined that it does not exist. + + if ( $this->db->affected_rows() == 0 + && $this->db->query($squery) + && $this->db->next_record() && $this->db->f(0) == 0 + && !$this->db->query($iquery)) { + + $ret = false; + } + + $this->db->unlock(); + + return $ret; + } + + function ac_delete($id, $name) { +// Security Fix + $this->db->query(sprintf("delete from %s where name = '%s' and sid = '%s'", + $this->database_table, + Contenido_Security::escapeDB($name, $this->db), + Contenido_Security::escapeDB($id, $this->db))); + } + + function ac_get_value($id, $name) { + +// Security Fix + $this->db->query(sprintf("select val from %s where sid = '%s' and name = '%s'", + $this->database_table, + Contenido_Security::escapeDB($id, $this->db), + Contenido_Security::escapeDB($name, $this->db))); + + if ($this->db->next_record()) { + $str = $this->db->f("val"); + $str2 = base64_decode( $str ); + + if (preg_match('/^' . $name . ':.*/', $str2)) { + $str = preg_replace('/^' . $name . ':/', '', $str2); + } else { + + $str3 = stripslashes( $str ); + + if (preg_match('/^' . $name . ':.*/', $str3)) { + $str = preg_replace('/^' . $name . ':/', '', $str3); + } else { + + switch ( $this->encoding_mode ) { + case "slashes": + $str = stripslashes($str); + break; + + case "base64": + default: + $str = base64_decode($str); + } + } + }; + return $str; + }; + return ""; + } + + function ac_newid($str, $name) { + return $str; + } + + function ac_halt($s) { + $this->db->halt($s); + } +} +?> \ No newline at end of file diff --git a/branches/php7/conlib/db_mysql.inc b/branches/php7/conlib/db_mysql.inc new file mode 100644 index 0000000..8a192cc --- /dev/null +++ b/branches/php7/conlib/db_mysql.inc @@ -0,0 +1,436 @@ + + * @license http://www.contenido.org/license/LIZENZ.txt + * @link http://www.4fb.de + * @link http://www.contenido.org + * @since file available since contenido release + * + * {@internal + * created 2002-07-21 + * modified 2008-07-04, bilal arslan, added security fix + * modified 2009-10-29, Murat Purc, removed deprecated functions (PHP 5.3 ready) extended DB_Sql_Abstract, added/optimized some functioms and some formatting + * modified 2009-12-18, Murat Purc, Replaced mysql_list_fields() against a SQL statement, see [#CON-262] + * modified 2011-03-03, Murat Purc, Some redesign and improvements (partial adaption to PHP 5 and extending DB_Sql_Abstract). + * modified 2011-03-13, Murat Purc, Cleanup and documentation. + * modified 2011-04-22, Murat Purc, Connect to DB server without database and more + * readable connection settings. + * modified 2011-05-17, Ortwin Pinke, bugfix in methode nextid(). + * + * $Id: db_mysql.inc 1359 2011-05-17 13:24:24Z oldperl $: + * }} + * + */ +if (!defined('CON_FRAMEWORK')) { + die('Illegal call'); +} + +class DB_Sql extends DB_Sql_Abstract { + + /** + * Constructor. + * + * @param array $options Optional assoziative options + */ + public function __construct(array $options = array()) { + $options = array_merge($options, array( + 'type' => 'mysql' + )); + parent::__construct($options); + } + + /** + * @see DB_Sql_Abstract::_connect() + */ + protected function _connect() { + $aCon = $this->_aDbCfg['connection']; + if (!isset($aCon['host']) || !isset($aCon['user']) || !isset($aCon['password'])) { + $this->halt('MySQL _connect() Connection settings not complete'); + return null; + } + + // establish connection, select database + $dbh = @mysql_connect($aCon['host'], $aCon['user'], $aCon['password']); + if (!$dbh || !is_resource($dbh)) { + $this->halt('MySQL _connect() Failed'); + return null; + } + + // set charset, default utf8 + if (isset($aCon['charset'])) { + @mysql_set_charset($aCon['charset'], $dbh); + } else { + @mysql_set_charset($aCon['charset'], 'utf8'); + } + //echo mysql_client_encoding($dbh); + + if (isset($aCon['database'])) { + if (!@mysql_select_db($aCon['database'], $dbh)) { + $this->halt('MySQL _connect() Cannot use database ' . $aCon['database']); + return null; + } + $this->Database = $aCon['database']; + } + + $this->User = $aCon['user']; + + return $dbh; + } + + /** + * Discard the query result + */ + public function free() { + @mysql_free_result($this->Query_ID); + $this->Query_ID = 0; + } + + /** + * @see DB_Sql_Abstract::_query() + */ + protected function _query($sQuery) { + $this->Query_ID = @mysql_query($sQuery, $this->Link_ID); + $this->Row = 0; + $this->Error = $this->_getErrorMessage(); + $this->Errno = $this->_getErrorNumber(); + if (!$this->Query_ID) { + $this->halt($sQuery); + } + } + + /** + * @see DB_Sql_Abstract::next_record() + */ + public function next_record() { + $this->Record = @mysql_fetch_array($this->Query_ID); + $this->Row += 1; + $this->Error = $this->_getErrorMessage(); + $this->Errno = $this->_getErrorNumber(); + + $stat = is_array($this->Record); + if (!$stat && $this->Auto_Free) { + $this->free(); + } + return $stat; + } + + /** + * @see DB_Sql_Abstract::seek() + */ + public function seek($pos = 0) { + $status = @mysql_data_seek($this->Query_ID, $pos); + if ($status) { + $this->Row = $pos; + } else { + $this->halt("seek($pos) failed: result has " . $this->num_rows() . " rows."); + // half assed attempt to save the day, but do not consider this + // documented or even desireable behaviour. + @mysql_data_seek($this->Query_ID, $this->num_rows()); + $this->Row = $this->num_rows(); + return 0; + } + + return 1; + } + + /** + * @see DB_Sql_Abstract::lock() + */ + public function lock($table, $mode = 'write') { + if ($this->_bNolock == true) { + return true; + } + $query = 'LOCK TABLES '; + if (is_array($table)) { + while (list($key, $value) = each($table)) { + if (!is_int($key)) { + // texts key are "read", "read local", "write", "low priority write" + $query .= "$value $key, "; + } else { + $query .= "$value $mode, "; + } + } + $query = substr($query, 0, -2); + } else { + $query .= "$table $mode"; + } + $res = $this->query($query); + if (!$res) { + $this->halt('lock() failed.'); + return 0; + } + return $res; + } + + /** + * @see DB_Sql_Abstract::unlock() + */ + public function unlock() { + if ($this->_bNolock == true) { + return true; + } + + $res = $this->query('UNLOCK TABLES'); + if (!$res) { + $this->halt('unlock() failed.'); + } + return $res; + } + + /** + * @see DB_Sql_Abstract::affected_rows() + */ + public function affected_rows() { + return ($this->Link_ID) ? mysql_affected_rows($this->Link_ID) : 0; + } + + /** + * @see DB_Sql_Abstract::num_rows() + */ + public function num_rows() { + return ($this->Query_ID) ? mysql_num_rows($this->Query_ID) : 0; + } + + /** + * @see DB_Sql_Abstract::num_fields() + */ + public function num_fields() { + return ($this->Query_ID) ? mysql_num_fields($this->Query_ID) : 0; + } + + /** + * get next possible id for requested db-table and update sequence table + * + * @param string $seq_name name of db-table to get nextid + * @return int nextid for requested table or 0 if an error occured + */ + public function nextid($seq_name) { + $this->connect(); + + if ($this->lock($this->Seq_Table)) { + /* get sequence number (locked) and increment */ + $q = sprintf("SELECT nextid FROM `%s` WHERE seq_name = '%s'", $this->Seq_Table, $seq_name); + $id = @mysql_query($q, $this->Link_ID); + $res = @mysql_fetch_array($id); + + /* No current value, make one */ + if (!is_array($res)) { + $currentid = 0; + $q = sprintf("INSERT INTO `%s` VALUES('%s', %s)", $this->Seq_Table, $seq_name, $currentid); + $id = @mysql_query($q, $this->Link_ID); + } else { + $currentid = $res['nextid']; + } + $nextid = $currentid + 1; + $q = sprintf("UPDATE `%s` SET nextid = '%s' WHERE seq_name = '%s'", $this->Seq_Table, $nextid, $seq_name); + $id = @mysql_query($q, $this->Link_ID); + $this->unlock(); + } else { + $this->halt('Cannot lock ' . $this->Seq_Table . ' - has it been created?'); + return 0; + } + return $nextid; + } + + /** + * @see DB_Sql_Abstract::disconnect() + */ + public function disconnect() { + $this->_debug("Debug: Disconnecting $this->Link_ID..."); + if (is_resource($this->Link_ID)) { + mysql_close($this->Link_ID); + $this->_removeConnection($this->Link_ID); + } + $this->Link_ID = 0; + $this->Query_ID = 0; + } + + /** + * @see DB_Sql_Abstract::_metaData() + */ + protected function _metaData($table = '', $full = false) { + $count = 0; + $id = 0; + $res = array(); + + /* + * Due to compatibility problems with Table we changed the behavior + * of metadata(); + * depending on $full, metadata returns the following values: + * + * - full is false (default): + * $result[]: + * [0]["table"] table name + * [0]["name"] field name + * [0]["type"] field type + * [0]["len"] field length + * [0]["flags"] field flags + * + * - full is true + * $result[]: + * ["num_fields"] number of metadata records + * [0]["table"] table name + * [0]["name"] field name + * [0]["type"] field type + * [0]["len"] field length + * [0]["flags"] field flags + * ["meta"][field name] index of field named "field name" + * This last one could be used if you have a field name, but no index. + * Test: if (isset($result['meta']['myfield'])) { ... + */ + + // if no $table specified, assume that we are working with a query + // result + if (!empty($table)) { + $this->connect(); + $id = mysql_query(sprintf('SELECT * FROM `%s` LIMIT 1', $table), $this->Link_ID); // PHP 5.3 fix 07.2009 O.Pinke, PHP 5.3 crashes with deprecated mysql_list_fields() + if (!$id) { + $this->halt('Metadata query failed.'); + return false; + } + } else { + $id = $this->Query_ID; + if (!$id) { + $this->halt('No query specified.'); + return false; + } + } + + $count = @mysql_num_fields($id); + + // made this IF due to performance (one if is faster than $count if's) + for ($i = 0; $i < $count; $i++) { + $res[$i]['table'] = @mysql_field_table($id, $i); + $res[$i]['name'] = @mysql_field_name($id, $i); + $res[$i]['type'] = @mysql_field_type($id, $i); + $res[$i]['len'] = @mysql_field_len($id, $i); + $res[$i]['flags'] = @mysql_field_flags($id, $i); + if ($full) { + $res['meta'][$res[$i]['name']] = $i; + } + } + if ($full) { + $res['num_fields'] = $count; + } + + // free the result only if we were called on a table + if ($table) { + @mysql_free_result($id); + } + return $res; + } + + /** + * @see DB_Sql_Abstract::_tableNames() + */ + protected function _tableNames() { + $return = array(); + $this->connect(); + $h = @mysql_query('SHOW TABLES', $this->Link_ID); + $i = 0; + if (isset($h) && @mysql_num_rows($h) > 0) { + while ($info = @mysql_fetch_row($h)) { + $return[$i]['table_name'] = $info[0]; + $return[$i]['tablespace_name'] = $this->Database; + $return[$i]['database'] = $this->Database; + $i++; + } + @mysql_free_result($h); + } + return $return; + } + + /** + * @see DB_Sql_Abstract::escape() + */ + public function escape($sString) { + if (!is_string($sString)) + return $sString; + $sResult = ''; + if (is_resource($this->Link_ID) || $this->connect()) { + $sResult = mysql_real_escape_string($sString, $this->Link_ID); + } + return $sResult; + } + + /** + * @see DB_Sql_Abstract::_serverInfo() + */ + protected function _serverInfo() { + $arr['description'] = mysql_get_server_info($this->Link_ID); + return $arr; + } + + /** + * @see DB_Sql_Abstract::_getErrorMessage() + */ + protected function _getErrorMessage() { + if (is_resource($this->Link_ID)) { + return mysql_error($this->Link_ID); + } else { + return mysql_error(); + } + } + + /** + * @see DB_Sql_Abstract::_getErrorNumber() + */ + protected function _getErrorNumber() { + if (is_resource($this->Link_ID)) { + return mysql_errno($this->Link_ID); + } else { + return mysql_errno(); + } + } + + /** + * This method equates to mysql_fetch_object(). It returns the current + * result set as object or null if no result set is left. If optional + * param $sClassName is set, the result object is an instance of class + * $sClassName. + * + * @return object + * + * @author Holger Librenz + * @version 1.0 + */ + public function getResultObject($sClassName = null) { + $oResult = null; + + if (is_resource($this->Link_ID) && is_resource($this->Query_ID)) { + if ($sClassName == null) { + $oResult = mysql_fetch_object($this->Query_ID); + } else { + $oResult = mysql_fetch_object($this->Query_ID, $sClassName); + } + } + + return $oResult; + } + + public function getServerInfo() { + return mysql_get_server_info($this->Link_ID); + } + + public function getClientEncoding() { + return mysql_client_encoding($this->Link_ID); + } + + public function getClientInfo() { + return mysql_get_client_info(); + } +} diff --git a/branches/php7/conlib/db_mysqli.inc b/branches/php7/conlib/db_mysqli.inc new file mode 100644 index 0000000..ae21dc1 --- /dev/null +++ b/branches/php7/conlib/db_mysqli.inc @@ -0,0 +1,500 @@ + + * @license http://www.contenido.org/license/LIZENZ.txt + * @link http://www.4fb.de + * @link http://www.contenido.org + * @since file available since contenido release + * + * {@internal + * created 2000-01-01 + * modified 2008-07-04, bilal arslan, added security fix + * modified 2009-10-29, Murat Purc, removed deprecated functions (PHP 5.3 ready) extended DB_Sql_Abstract, added/optimized some functioms and some formatting + * modified 2009-12-29, Murat Purc, replaced is_resource() against mysqli compatible check [#CON-290] + * modified 2011-03-03, Murat Purc, Some redesign and improvements (partial adaption to PHP 5 and extending DB_Sql_Abstract). + * modified 2011-03-13, Murat Purc, Cleanup and documentation. + * modified 2011-04-22, Murat Purc, Connect to DB server without database and more + * readable connection settings. + * + * $Id: db_mysqli.inc 1350 2011-04-22 15:53:39Z xmurrix $: + * }} + * + */ +if (!defined('CON_FRAMEWORK')) { + die('Illegal call'); +} + +class DB_Sql extends DB_Sql_Abstract { + + protected $_aDataTypes = array( + 0 => 'decimal', + 1 => 'tinyint', + 2 => 'smallint', + 3 => 'int', + 4 => 'float', + 5 => 'double', + 7 => 'timestamp', + 8 => 'bigint', + 9 => 'mediumint', + 10 => 'date', + 11 => 'time', + 12 => 'datetime', + 13 => 'year', + 252 => 'blob', // text, blob, tinyblob,mediumblob, etc... + 253 => 'string', // varchar and char + 254 => 'enum', + ); + + /** + * Constructor. + * + * @param array $options Optional assoziative options + */ + public function __construct(array $options = array()) { + $options = array_merge($options, array( + 'type' => 'mysqli', + )); + parent::__construct($options); + } + + /** + * @see DB_Sql_Abstract::_connect() + */ + protected function _connect() { + // feasible connection values are: + // - $options['connection']['host'] (string) Hostname or ip + // - $options['connection']['database'] (string) Database name + // - $options['connection']['user'] (string) User name + // - $options['connection']['password'] (string) User password + // - $options['connection']['options'] (array) Optional, MySQLi options array + // - $options['connection']['socket'] (int) Optional, socket + // - $options['connection']['port'] (int) Optional, port + // - $options['connection']['flags'] (int) Optional, flags + // see http://www.php.net/manual/en/mysqli.real-connect.php +// extract($this->_aDbCfg['connection']); + + if (!extension_loaded('mysqli')) { + $this->halt('MySQLi _connect() extension not loaded!'); + return null; + } + + $dbh = mysqli_init(); + //print_r($dbh); + if (!$dbh) { + $this->halt('MySQLi _connect() Init failed'); + return null; + } + + $aCon = $this->_aDbCfg['connection']; + if (!isset($aCon['host']) || !isset($aCon['user']) || !isset($aCon['password'])) { + $this->halt('MySQLi _connect() Connection settings not complete'); + return null; + } + + + // set existing option flags + if (isset($aCon['options']) && is_array($aCon['options'])) { + foreach ($aCon['options'] as $optKey => $optVal) { + mysqli_options($dbh, $optKey, $optVal); + } + } + + if (($iPos = strpos($aCon['host'], ':')) !== false) { + list($aCon['host'], $aCon['port']) = explode(':', $aCon['host']); + } else { + $aCon['port'] = null; + } + + if (!isset($aCon['socket'])) { + $aCon['socket'] = null; + } + if (!isset($aCon['flags'])) { + $aCon['flags'] = null; + } + if (!isset($aCon['database'])) { + $aCon['database'] = null; + } + + $res = mysqli_real_connect( + $dbh, $aCon['host'], $aCon['user'], $aCon['password'], $aCon['database'], $aCon['port'], $aCon['socket'], $aCon['flags'] + ); + + + if (isset($aCon['charset'])) { + @mysqli_set_charset($dbh, $aCon['charset']); + } else { + @mysqli_set_charset($dbh, 'utf8'); + } + + //echo mysqli_character_set_name($dbh); + + if ($res && $dbh && $aCon['database']) { + if (!@mysqli_select_db($dbh, $aCon['database'])) { + $this->halt('MySQLi _connect() Cannot use database ' . $aCon['database']); + return null; + } + $this->Database = $aCon['database']; + } + + $this->User = $aCon['user']; + + return $dbh; + } + + /** + * Discard the query result + */ + public function free() { + if (is_object($this->Query_ID)) { + mysqli_free_result($this->Query_ID); + } + $this->Query_ID = 0; + } + + /** + * @see DB_Sql_Abstract::_query() + */ + protected function _query($sQuery) { + $this->Query_ID = mysqli_query($this->Link_ID, $sQuery); + $this->Row = 0; + $this->Errno = $this->_getErrorNumber(); + $this->Error = $this->_getErrorMessage(); + if (!$this->Query_ID) { + $this->halt($sQuery); + } + } + + /** + * @see DB_Sql_Abstract::next_record() + */ + public function next_record() { + $this->Record = mysqli_fetch_array($this->Query_ID, MYSQLI_BOTH); + $this->Row += 1; + $this->Errno = $this->_getErrorNumber(); + $this->Error = $this->_getErrorMessage(); + + $stat = is_array($this->Record); + if (!$stat && $this->Auto_Free) { + $this->free(); + } + return $stat; + } + + /** + * @see DB_Sql_Abstract::seek() + */ + public function seek($pos = 0) { + $status = mysqli_data_seek($this->Query_ID, $pos); + if ($status) { + $this->Row = $pos; + } else { + $this->halt("seek($pos) failed: result has " . $this->num_rows() . " rows."); + // half assed attempt to save the day, but do not consider this + // documented or even desireable behaviour. + mysqli_data_seek($this->Query_ID, $this->num_rows()); + $this->Row = $this->num_rows(); + return 0; + } + + return 1; + } + + /** + * @see DB_Sql_Abstract::lock() + */ + public function lock($table, $mode = 'write') { + if ($this->_bNolock == true) { + return true; + } + $query = 'LOCK TABLES '; + if (is_array($table)) { + while (list ($key, $value) = each($table)) { + if (!is_int($key)) { + // texts key are "read", "read local", "write", "low priority write" + $query .= "$value $key, "; + } else { + $query .= "$value $mode, "; + } + } + $query = substr($query, 0, -2); + } else { + $query .= "$table $mode"; + } + $res = $this->query($query); + if (!$res) { + $this->halt('lock() failed.'); + return 0; + } + return $res; + } + + /** + * @see DB_Sql_Abstract::unlock() + */ + public function unlock() { + if ($this->_bNolock == true) { + return true; + } + + $res = $this->query('UNLOCK TABLES'); + if (!$res) { + $this->halt('unlock() failed.'); + } + return $res; + } + + /** + * @see DB_Sql_Abstract::affected_rows() + */ + public function affected_rows() { + return ($this->Link_ID) ? mysqli_affected_rows($this->Link_ID) : 0; + } + + /** + * @see DB_Sql_Abstract::num_rows() + */ + public function num_rows() { + return ($this->Query_ID) ? mysqli_num_rows($this->Query_ID) : 0; + } + + /** + * @see DB_Sql_Abstract::num_fields() + */ + public function num_fields() { + return ($this->Query_ID) ? mysqli_num_fields($this->Query_ID) : 0; + } + + /** + * @see DB_Sql_Abstract::nextid() + */ + public function nextid($seq_name) { + $this->connect(); + + if ($this->lock($this->Seq_Table)) { + /* get sequence number (locked) and increment */ + $q = sprintf("SELECT nextid FROM `%s` WHERE seq_name = '%s'", $this->Seq_Table, $seq_name); + $id = mysqli_query($this->Link_ID, $q); + $res = mysqli_fetch_array($id, MYSQLI_BOTH); + + /* No current value, make one */ + if (!is_array($res)) { + $currentid = 0; + $q = sprintf("INSERT INTO `%s` VALUES('%s', %s)", $this->Seq_Table, $seq_name, $currentid); + $id = mysqli_query($this->Link_ID, $q); + } else { + $currentid = $res["nextid"]; + } + $nextid = $currentid + 1; + $q = sprintf("UPDATE `%s` set nextid = '%s' WHERE seq_name = '%s'", $this->Seq_Table, $nextid, $seq_name); + $id = mysqli_query($this->Link_ID, $q); + $this->unlock(); + } else { + $this->halt('Cannot lock ' . $this->Seq_Table . ' - has it been created?'); + return 0; + } + return $nextid; + } + + /** + * @see DB_Sql_Abstract::disconnect() + */ + public function disconnect() { + //$this->_debug("Debug: Disconnecting $this->Link_ID..."); + if (is_resource($this->Link_ID)) { + mysqli_close($this->Link_ID); + $this->_removeConnection($this->Link_ID); + } + $this->Link_ID = 0; + $this->Query_ID = 0; + } + + /** + * @see DB_Sql_Abstract::_metaData() + */ + protected function _metaData($table = '', $full = false) { + $count = 0; + $id = 0; + $res = array(); + + /* + * Due to compatibility problems with Table we changed the behavior + * of metadata(); + * depending on $full, metadata returns the following values: + * + * - full is false (default): + * $result[]: + * [0]["table"] table name + * [0]["name"] field name + * [0]["type"] field type + * [0]["len"] field length + * [0]["flags"] field flags + * + * - full is true + * $result[]: + * ["num_fields"] number of metadata records + * [0]["table"] table name + * [0]["name"] field name + * [0]["type"] field type + * [0]["len"] field length + * [0]["flags"] field flags + * ["meta"][field name] index of field named "field name" + * This last one could be used if you have a field name, but no index. + * Test: if (isset($result['meta']['myfield'])) { ... + */ + + // if no $table specified, assume that we are working with a query + // result + if ($table) { + $this->connect(); + $id = mysqli_query($this->Link_ID, sprintf("SELECT * FROM `%s` LIMIT 1", $table)); + if (!$id) { + $this->halt('Metadata query failed.'); + return false; + } + } else { + $id = $this->Query_ID; + if (!$id) { + $this->halt('No query specified.'); + return false; + } + } + + $count = mysqli_num_fields($id); + + // made this IF due to performance (one if is faster than $count if's) + for ($i = 0; $i < $count; $i ++) { + $finfo = mysqli_fetch_field($id); + $res[$i]['table'] = $finfo->table; + $res[$i]['name'] = $finfo->name; + $res[$i]['type'] = $this->_aDataTypes[$finfo->type]; + $res[$i]['len'] = $finfo->max_length; + $res[$i]['flags'] = $finfo->flags; + if ($full) { + $res['meta'][$res[$i]['name']] = $i; + } + } + if ($full) { + $res['num_fields'] = $count; + } + + // free the result only if we were called on a table + if ($table) { + mysqli_free_result($id); + } + return $res; + } + + /** + * @see DB_Sql_Abstract::escape() + */ + public function escape($sString) { + $sResult = ''; + if (is_resource($this->Link_ID) || $this->connect()) { + $sResult = mysqli_real_escape_string($this->Link_ID, $sString); + }; + return $sResult; + } + + /** + * @see DB_Sql_Abstract::_tableNames() + */ + protected function _tableNames() { + $return = array(); + $this->connect(); + $h = @mysqli_query($this->Link_ID, 'SHOW TABLES'); + $i = 0; + if (isset($h) && @mysqli_num_rows($h) > 0) { + while ($info = mysqli_fetch_row($h)) { + $return[$i]['table_name'] = $info[0]; + $return[$i]['tablespace_name'] = $this->Database; + $return[$i]['database'] = $this->Database; + $i ++; + } + + mysqli_free_result($h); + } + return $return; + } + + /** + * @see DB_Sql_Abstract::_serverInfo() + */ + protected function _serverInfo() { + $arr['description'] = mysqli_get_server_info($this->Link_ID); + return $arr; + } + + /** + * @see DB_Sql_Abstract::_getErrorMessage() + */ + protected function _getErrorMessage() { + if ($this->Link_ID) { + return @mysqli_error($this->Link_ID); + } else { + return @mysqli_connect_error(); + } + } + + /** + * @see DB_Sql_Abstract::_getErrorNumber() + */ + protected function _getErrorNumber() { + if ($this->Link_ID) { + return @mysqli_errno($this->Link_ID); + } else { + return @mysqli_connect_errno(); + } + } + + /** + * This method equates to mysqli_fetch_object(). It returns the current + * result set as object or null if no result set is left. If optional + * param $sClassName is set, the result object is an instance of class + * $sClassName. + * + * @return object|null + * + * @author Holger Librenz + * @version 1.0 + */ + public function getResultObject($sClassName = null) { + $oResult = null; + + if (is_resource($this->Link_ID) && is_resource($this->Query_ID)) { + if ($sClassName == null) { + $oResult = mysqli_fetch_object($this->Query_ID); + } else { + $oResult = mysqli_fetch_object($this->Query_ID, $sClassName); + } + } + + return $oResult; + } + + public function getServerInfo() { + return mysqli_get_server_info($this->Link_ID); + } + + public function getClientEncoding() { + $oCharSet = mysqli_get_charset($this->Link_ID); + return $oCharSet->charset; + } + + public function getClientInfo() { + return mysqli_get_client_info(); + } +} \ No newline at end of file diff --git a/branches/php7/conlib/db_pdo_mysql.inc b/branches/php7/conlib/db_pdo_mysql.inc new file mode 100644 index 0000000..6b758d4 --- /dev/null +++ b/branches/php7/conlib/db_pdo_mysql.inc @@ -0,0 +1,513 @@ + + * @copyright four for business AG + * @license http://www.contenido.org/license/LIZENZ.txt + * @link http://www.4fb.de + * @link http://www.contenido.org + * @since file available since contenido release 4.8.15 + * + * {@internal + * created 2011-02-28 + * modified 2011-03-13, Murat Purc, Cleanup and documentation. + * modified 2011-04-22, Murat Purc, Connect to DB server without database and more + * readable connection settings. + * + * $Id: $: + * }} + * + */ + +if (!defined('CON_FRAMEWORK')) { + die('Illegal call'); +} + + +class DB_Sql extends DB_Sql_Abstract +{ + + /** + * PDO connection + * @var PDO + */ + public $Query_ID; + + /** + * PDO statement + * @var PDOStatement + */ + public $Link_ID; + + protected $_aDataTypes = array( + PDO::PARAM_BOOL => 'bool', + PDO::PARAM_NULL => 'null', + PDO::PARAM_INT => 'int', + PDO::PARAM_STR => 'string', + PDO::PARAM_LOB => 'blob', + PDO::PARAM_STMT => 'statement' + ); + + + /** + * Constructor. + * + * @param array $options Optional assoziative options + */ + public function __construct(array $options = array()) + { + $options = array_merge($options, array( + 'type' => 'pdo_mysql', + )); + parent::__construct($options); + } + + + /** + * @see DB_Sql_Abstract::_connect() + */ + protected function _connect() + { + $aCon = $this->_aDbCfg['connection']; + if (!isset($aCon['host']) || !isset($aCon['user']) || !isset($aCon['password'])) { + $this->halt('MySQL _connect() Connection settings not complete'); + return null; + } + + $dsn = 'mysql:'; + if (isset($aCon['database'])) { + $dsn .= 'dbname=' . $aCon['database'] . ';'; + } + $dsn .= 'host=' . $aCon['host']; + + if (!isset($aCon['driver_options']) || !is_array($aCon['driver_options'])) { + $aCon['driver_options'] = array(); + } + + try { + // Create a new PDO connection + $dbh = new PDO($dsn, $aCon['user'], $aCon['password'], $aCon['driver_options']); + } catch (PDOException $e) { + $this->Errno = $e->getCode(); + $this->Error = $e->getMessage(); + } + + if (!$dbh) { + $this->halt('PDO_MySQL _connect() Failed'); + return null; + } + + if (isset($aCon['database'])) { + $this->Database = $aCon['database']; + } + $this->User = $aCon['user']; + + return $dbh; + } + + + /** + * Discard the query result + */ + public function free() + { + if ($this->Query_ID) { + $this->Query_ID->closeCursor(); + unset($this->Query_ID); + } + } + + + /** + * @see DB_Sql_Abstract::_query() + */ + protected function _query($sQuery) + { + $this->Query_ID = $this->Link_ID->query($sQuery); + $this->Row = 0; + $this->Errno = $this->_getErrorNumber(); + $this->Error = $this->_getErrorMessage(); + if (!$this->Query_ID) { + $this->halt($sQuery); + } + } + + + /** + * @see DB_Sql_Abstract::next_record() + */ + public function next_record() + { + $this->Record = $this->Query_ID->fetch(PDO::FETCH_BOTH); + $this->Row += 1; + $this->Errno = $this->_getErrorNumber(); + $this->Error = $this->_getErrorMessage(); + $stat = is_array($this->Record); + if (!$stat && $this->Auto_Free) { + $this->free(); + } + return $stat; + } + + + /** + * @see DB_Sql_Abstract::seek() + */ + public function seek($pos = 0) + { + throw new Exception('seek not supported'); + } + + + /** + * @see DB_Sql_Abstract::lock() + */ + public function lock($table, $mode = 'write') + { + if ($this->_bNolock == true) { + return true; + } + $query = 'LOCK TABLES '; + if (is_array($table)) { + while (list ($key, $value) = each($table)) { + if (!is_int($key)) { + // texts key are "read", "read local", "write", "low priority write" + $query .= "$value $key, "; + } else { + $query .= "$value $mode, "; + } + } + $query = substr($query, 0, -2); + } else { + $query .= "$table $mode"; + } + $res = $this->query($query); + if (!$res) { + $this->halt('lock() failed.'); + return 0; + } + return $res; + } + + + /** + * @see DB_Sql_Abstract::unlock() + */ + public function unlock() + { + if ($this->_bNolock == true) { + return true; + } + + $res = $this->query('UNLOCK TABLES'); + if (!$res) { + $this->halt('unlock() failed.'); + } + return $res; + } + + + /** + * @see DB_Sql_Abstract::affected_rows() + */ + public function affected_rows() + { + return ($this->Query_ID) ? $this->Query_ID->rowCount() : 0; + } + + + /** + * @see DB_Sql_Abstract::num_rows() + */ + public function num_rows() + { + if ($this->Query_ID) { + // clone statement and get count by using fetchAll + $stmt = clone $this->Query_ID; + $res = $stmt->fetchAll(); + return (is_array($res)) ? count($stmt->fetchAll()) : 0; + } else { + return 0; + } + } + + + /** + * @see DB_Sql_Abstract::num_fields() + */ + public function num_fields() + { + return count($this->Record / 2); + } + + + /** + * @see DB_Sql_Abstract::nextid() + */ + public function nextid($seq_name) + { + $this->connect(); + + if ($this->lock($this->Seq_Table)) { + /* get sequence number (locked) and increment */ + $q = sprintf("SELECT nextid FROM `%s` WHERE seq_name = '%s'", $this->Seq_Table, $seq_name); + $stmt = $this->Link_ID->query($q); + $res = ($stmt) ? $stmt->fetch(PDO::FETCH_BOTH) : null; + + /* No current value, make one */ + if (!is_array($res)) { + $currentid = 0; + $q = sprintf("INSERT INTO `%s` VALUES('%s', %s)", $this->Seq_Table, $seq_name, $currentid); + $stmt = $this->Link_ID->query($q); + } else { + $currentid = $res['nextid']; + } + $nextid = $currentid + 1; + $q = sprintf("UPDATE `%s` set nextid = '%s' WHERE seq_name = '%s'", $this->Seq_Table, $nextid, $seq_name); + $stmt = $this->Link_ID->query($q); + $this->unlock(); + } else { + $this->halt('Cannot lock ' . $this->Seq_Table . ' - has it been created?'); + return 0; + } + return $nextid; + } + + + /** + * @see DB_Sql_Abstract::disconnect() + */ + public function disconnect() + { + $this->_debug("Debug: Disconnecting $this->Link_ID..."); + // Destroy the PDO and PDOStatement object + $this->_removeConnection($this->Link_ID); + $this->Link_ID = null; + $this->Query_ID = null; + } + + + /** + * @see DB_Sql_Abstract::_metaData() + */ + protected function _metaData($table = '', $full = false) + { + $count = 0; + $id = 0; + $res = array(); + + /* + * Due to compatibility problems with Table we changed the behavior + * of metadata(); + * depending on $full, metadata returns the following values: + * + * - full is false (default): + * $result[]: + * [0]["table"] table name + * [0]["name"] field name + * [0]["type"] field type + * [0]["len"] field length + * [0]["flags"] field flags + * + * - full is true + * $result[]: + * ["num_fields"] number of metadata records + * [0]["table"] table name + * [0]["name"] field name + * [0]["type"] field type + * [0]["len"] field length + * [0]["flags"] field flags + * ["meta"][field name] index of field named "field name" + * This last one could be used if you have a field name, but no index. + * Test: if (isset($result['meta']['myfield'])) { ... + */ + + // if no $table specified, assume that we are working with a query + // result + if ($table) { + $this->connect(); + $stmt = $this->Link_ID->query(sprintf("DESCRIBE `%s`", $table)); + if (!$stmt) { + $this->halt('Metadata query failed.'); + return false; + } + } else { + $stmt = $this->Query_ID; + if (!$stmt) { + $this->halt('No query specified.'); + return false; + } + } + + // loop thru the result and collect meta data + $res = array(); + while ($rs = $stmt->fetch(PDO::FETCH_ASSOC)) { + $field = $this->_getFieldTypeDetails($rs['Type']); + $item = array(); + $item['table'] = $table; + $item['name'] = $rs['Field']; + $item['type'] = $field['type']; + $item['len'] = $field['size']; + $item['flags'] = null; // @todo detect field flags + $res[$count] = $item; + if ($full) { + $res['meta'][$item['name']] = $count; + } + $count++; + } + if ($full) { + $res['num_fields'] = $count; + } + + unset($stmt); + + return $res; + } + + + /** + * @see DB_Sql_Abstract::escape() + */ + public function escape($sString) + { + $sResult = ''; + $sResult = str_replace("'", "''", $sString); + // @todo adapt pdo quote method to own requirements +# if ($this->connect()) { +# $sResult = $this->Link_ID->quote($sString); +# } + return $sResult; + } + + + /** + * @see DB_Sql_Abstract::_tableNames() + */ + protected function _tableNames() + { + $return = array(); + + $stmt = $this->Link_ID->query('SHOW TABLES'); + $i = 0; + while ($rs = $stmt->fetch(PDO::FETCH_NUM)) { + $return[$i]['table_name'] = $rs[0]; + $return[$i]['tablespace_name'] = $this->Database; + $return[$i]['database'] = $this->Database; + $i ++; + } + + unset($stmt); + + return $return; + } + + + /** + * @see DB_Sql_Abstract::_serverInfo() + */ + protected function _serverInfo() + { + $arr['description'] = $this->Link_ID->getAttribute(PDO::ATTR_SERVER_INFO); + $arr['version'] = $this->Link_ID->getAttribute(PDO::ATTR_SERVER_VERSION); + return $arr; + } + + + /** + * @see DB_Sql_Abstract::_getErrorMessage() + */ + protected function _getErrorMessage() + { + $err = null; + if ($this->Query_ID) { + $err = $this->Query_ID->errorInfo(); + } elseif ($this->Link_ID) { + $err = $this->Link_ID->errorInfo(); + } + if (null !== $err && (int) $err[0] > 0) { + return $err[2]; + } + } + + + /** + * @see DB_Sql_Abstract::_getErrorNumber() + */ + protected function _getErrorNumber() + { + $err = null; + if ($this->Query_ID) { + $err = $this->Query_ID->errorCode(); + } elseif ($this->Link_ID) { + $err = $this->Link_ID->errorCode(); + } + if (null !== $err && (int) $err[0] > 0) { + return $err[0]; + } + } + + + protected function _getFieldTypeDetails($field) + { + $ret = array('type' => null, 'size' => null); + if (!$field) { + return $ret; + } + if (preg_match('/^([a-z].*)\(([0-9].*)\)/', $field, $matches)) { + $ret = array('type' => $matches[1], 'size' => (int) $matches[2]); + } else { + $ret['type'] = $field; + } + return $ret; + } + + /** + * This method festches the current result set and returns the it as object or + * null if no result set is left. If optional param $sClassName is set, the + * result object is an instance of class $sClassName. + * + * @param string sClassName Optional the classname to instantiate. + * @return object|null + */ + public function getResultObject($sClassName = null) + { + $oResult = null; + + if ($this->Link_ID && $this->Query_ID) { + if ($rs = $this->Query_ID->fetch(PDO::FETCH_ASSOC)) { + if ($sClassName == null) { + $oResult = (object) $rs; + } else { + $oResult = new $sClassName(); + foreach ($rs as $key => $value) { + $oResult->{$key} = $value; + } + } + } + } + + return $oResult; + } + + public function getServerInfo() { + return ''; + } + + public function getClientEncoding() { + return ''; + } + +} diff --git a/branches/php7/conlib/db_sql_abstract.inc b/branches/php7/conlib/db_sql_abstract.inc new file mode 100644 index 0000000..8ea766e --- /dev/null +++ b/branches/php7/conlib/db_sql_abstract.inc @@ -0,0 +1,804 @@ + + * @copyright four for business AG + * @license http://www.contenido.org/license/LIZENZ.txt + * @link http://www.4fb.de + * @link http://www.contenido.org + * @since file available since Contenido release 4.8.15 + * + * {@internal + * created 2011-03-03 + * modified 2011-03-13, Murat Purc, Added FETCH_* constants, extended toArray(), + * moved close(), table_names() and server_info() + * from child implementations. + * + * $Id:$: + * }} + * + */ +if (!defined('CON_FRAMEWORK')) { + die('Illegal call'); +} + +abstract class DB_Sql_Abstract { + + const HALT_YES = 'yes'; + const HALT_NO = 'no'; + const HALT_REPORT = 'report'; + const FETCH_NUMERIC = 'numeric'; + const FETCH_ASSOC = 'assoc'; + const FETCH_BOTH = 'both'; + + /** + * Assoziative list of database connections + * @array + */ + protected static $_connectionCache = array(); + + /** + * Assoziative list of database tables metadata + * @array + */ + protected static $_metaCache = array(); + + /** + * Sequence table name + * @var string + */ + public $Seq_Table = ''; + + /** + * Flag to print debug messages + * @var bool + */ + public $Debug = false; + + /** + * Database name + * @var string + */ + public $Database = ''; + + /** + * Database connection user name + * @var string + */ + public $User = ''; + + /** + * Database connection password + * @var string + */ + public $Password = ''; + + /** + * Database connection resource + * @var resource|int + */ + public $Link_ID = 0; + + /** + * Resource identifier of last executed query + * @var resource + */ + public $Query_ID = 0; + + /** + * Recordset data array. Could contain either indexed or assoziative result set (or both) + * @var array + */ + public $Record = array(); + + /** + * The row position inside last executed select result + * @var int + */ + public $Row; + + /** + * Database error number + * @var int + */ + public $Errno = 0; + + /** + * Database error message + * @var string + */ + public $Error = ''; + + /** + * Flag to automatic free results + * @var int + */ + public $Auto_Free = 0; + + /** + * Database identification string. + * @var string + */ + public $type = ''; + + /** + * Revision. This is an api revision, not a CVS revision + * @var string + */ + public $revision = '1.3'; + + /** + * Halt status during occured errors. Feasible values are + * - "yes" (halt with message) + * - "no" (ignore errors quietly) + * - "report" (ignore errror, but spit a warning) + * @var string + */ + public $Halt_On_Error = 'no'; + + /** + * Text to prepend to the halt message + * @var string + */ + protected $_sHaltMsgPrefix = ''; + + /** + * Default database connection for all instances + * @var array + */ + protected static $_aDefaultDbCfg = array(); + + /** + * Database connection configuration for current instance + * @var array + */ + protected $_aDbCfg; + + /** + * Enable profiling + * @var bool + */ + protected $_bProfile = false; + + /** + * Don't lock tables + * @var bool + */ + protected $_bNolock = false; + + /** + * Profile data array + * @var array + */ + protected static $_aProfileData = array(); + // @todo intended to map new protected properties against old public + // properties by using magic __call method + protected $_oldProperties = array( + 'Seq_Table' => '_sSeqTable', + 'Debug' => '_bDebug', + 'Database' => '_sDatabase', + 'User' => '_sUser', + 'Password' => '_sPassword', + 'Link_ID' => '_mLinkId', + 'Query_ID' => '_mQueryId', + 'Auto_Free' => '_iAutoFree', + 'type' => '_sType', + 'revision' => '_sRevision', + 'Halt_On_Error' => '_sHaltOnError', + ); + + /** + * Constructor, sets passed options and connects to the DBMS, if not done before. + * + * Uses default connection settings, passed $options['db_connection'] settings + * will overwrite connection settings for current instance. + * + * @param array $options Assoziative options as follows: + * - $options['sequenceTable'] (string) Optional, the sequence table name + * - $options['nolock'] (bool) Optional, not lock table + * - $options['haltBehavior'] (string) Optional, halt behavior on occured errors + * - $options['haltMsgPrefix'] (string) Optional, Text to prepend to the halt message + * - $options['type'] (string) Database driver name + * - $options['enableProfiling'] (bool) Optional, flag to enable profiling + * - $options['connection'] (array) Optional, assoziative connection settings + * @return void + */ + protected function __construct(array $options) { + // use default connection configuration, but overwrite it by passed options + $this->_aDbCfg = array_merge(self::$_aDefaultDbCfg, $options); + + if (isset($this->_aDbCfg['sequenceTable']) && is_string($this->_aDbCfg['sequenceTable'])) { + $this->Seq_Table = $this->_aDbCfg['sequenceTable']; + } + + if (isset($this->_aDbCfg['haltBehavior'])) { + switch ($this->_aDbCfg['haltBehavior']) { + case self::HALT_YES: + $this->Halt_On_Error = self::HALT_YES; + break; + case self::HALT_NO: + $this->Halt_On_Error = self::HALT_NO; + break; + case self::HALT_REPORT: + $this->Halt_On_Error = self::HALT_REPORT; + break; + } + } + + if (isset($this->_aDbCfg['haltMsgPrefix']) && is_string($this->_aDbCfg['haltMsgPrefix'])) { + $this->_sHaltMsgPrefix = $this->_aDbCfg['haltMsgPrefix']; + } + + if (isset($this->_aDbCfg['type']) && is_string($this->_aDbCfg['type'])) { + $this->type = $this->_aDbCfg['type']; + } + + if (isset($this->_aDbCfg['nolock']) && is_bool($this->_aDbCfg['nolock'])) { + $this->_bNolock = (bool) $this->_aDbCfg['nolock']; + } + if (isset($this->_aDbCfg['enableProfiling']) && is_bool($this->_aDbCfg['enableProfiling'])) { + $this->_bProfile = (bool) $this->_aDbCfg['enableProfiling']; + } + + $this->connect(); + } + + /** + * Setter for default database configuration, the connection values. + * + * @param array $defaultDbCfg + */ + public static function setDefaultConfiguration(array $defaultDbCfg) { + self::$_aDefaultDbCfg = $defaultDbCfg; + } + + /** + * Establishes a connection to the database server. + * + * @return object|resource|int|null Connection handler. Return value depends on + * used driver and is null in case of an error. + */ + public function connect() { + if ($this->Link_ID = $this->_getConnection($this->_aDbCfg['connection'])) { + return $this->Link_ID; + } else { + if ($this->Link_ID = $this->_connect()) { + $this->_setConnection($this->_aDbCfg['connection'], $this->Link_ID); + return $this->Link_ID; + } + } + return null; + } + + /** + * Resource id/object of current connection + * + * @return mixed The resource id/object of current connection + */ + public function link_id() { + return $this->Link_ID; + } + + /** + * Returns connection from connection cache + * + * @param mixed $data Connection data array + * @return mixed Either The connection (object, resource, integer) or null + */ + protected function _getConnection($data) { + $hash = md5($this->type . '-' . (is_array($data) ? implode('-', $data) : (string) $data)); + return (isset(self::$_connectionCache[$hash])) ? self::$_connectionCache[$hash] : null; + } + + /** + * Stores connection in connection cache + * + * @param mixed $data Connection data array + * @param mixed $connection The connection to store in cache + * @return void + */ + protected function _setConnection($data, $connection) { + $hash = md5($this->type . '-' . (is_array($data) ? implode('-', $data) : (string) $data)); + self::$_connectionCache[$hash] = $connection; + } + + /** + * Removes connection from cache + * + * @param mixed $connection The connection to remove in cache + * @return void + */ + protected function _removeConnection($connection) { + foreach (self::$_connectionCache as $hash => $res) { + if ($res == $connection) { + unset(self::$_connectionCache[$hash]); + return; + } + } + } + + /** + * Returns the current cursor + * + * @return resource Current cursor + */ + public function query_id() { + return $this->Query_ID; + } + + /** + * Connects to the database. + * + * @return object|resource|int|null Connection handler. Return value depends on + * used driver and is null in case of an error. + */ + abstract protected function _connect(); + + /** + * Executes the query. + * + * @param string $sQuery The query to execute. + * @param mixed Accepts additional unlimited parameter, where the parameter + * will be replaced against format definitions in query. + * @return resource|int|object|bool Depends on used database driver, false on error + */ + public function query($sQuery) { + // No empty queries, please, since PHP4 chokes on them + if ($sQuery == '') { + // The empty query string is passed on from the constructor, when calling + // the class without a query, e.g. in situations '$db = new DB_Sql_Subclass;' + return false; + } + + $aArgs = func_get_args(); + if (count($aArgs) > 1) { + array_shift($aArgs); + $sQuery = $this->_prepareQueryf($sQuery, $aArgs); + } + + if (!$this->connect()) { + return false; + } + + // new query, discard previous result + if ($this->Query_ID) { + $this->free(); + } + + $this->_debug('Debug: query = ' . $sQuery); + + if ($this->_bProfile) { + $fStart = microtime(true); + } + + $this->_query($sQuery); + + if ($this->_bProfile) { + $fEnd = microtime(true); + $this->_addProfileData($fStart, $fEnd, $sQuery); + } + + // Will return nada if it fails. That's fine. + return $this->Query_ID; + } + + /** + * Executes the query. + * + * @param string $sQuery The query to execute + * @return void + */ + abstract protected function _query($sQuery); + + /** + * Prepares a query with parameter for execution. + * + * @param string $sQuery + * @param array $aArgs Arguments array containing the query with formatting + * signs and the entries. + * Examples: + *

+     *                          $obj->_prepareQueryf('SELECT * FROM `%s` WHERE id = %d', 'tablename', 123);
+     *                          $obj->_prepareQueryf('SELECT * FROM `%s` WHERE id = %d AND user = %d', 'tablename', 123, 3);
+     *                          
+ * @return string + */ + protected function _prepareQueryf($sQuery, array $aArgs) { + if (count($aArgs) > 0) { + $aArgs = array_map(array($this, 'escape'), $aArgs); + array_unshift($aArgs, $sQuery); + $sQuery = call_user_func_array('sprintf', $aArgs); + } + return $sQuery; + } + + /** + * Moves the result to the next record, if exists and returns the status of the movement + * + * @return int Flag about move status 1 on success or 0 + */ + abstract public function next_record(); + + /** + * Moves the cursor (position inside current result sets). + * + * @param int $pos The positon to move to inside the current result set + * @return void + */ + abstract public function seek($pos = 0); + + /** + * Locks the desired table. + * + * @param string $table The table to lock + * @param string $mode The lock mode. Only mode 'write' is supported! + * @return int Status of lock success (1 or 0) + */ + abstract public function lock($table, $mode = 'write'); + + /** + * Frees a previous locked result. + * + * @return int Status of lock success (1 or 0) + */ + abstract public function unlock(); + + /** + * Parses te table structure and generates a metadata from it. + * + * @param string $table The table to get metadata or empty string to retrieve + * metadata of all tables + * @param bool $full Flag to load full metada + * @return array Depends on used database and on parameter $full + */ + public function metadata($table = '', $full = false) { + $key = (string) $this->Database . '_' . $table . '_' . (($full) ? '1' : '0'); + + if (!isset(self::$_metaCache[$key])) { + // get meta data + self::$_metaCache[$key] = $this->_metaData($table, $full); + } + + return self::$_metaCache[$key]; + } + + /** + * Parses te table structure and generates a metadata from it. + * + * @param string $table The table to get metadata or empty string to retrieve + * metadata of all tables + * @param bool $full Flag to load full metada + * @return array Depends on used database and on parameter $full + */ + abstract protected function _metaData($table = '', $full = false); + + /** + * Returns number of affected rows from last executed query (update, delete) + * + * @return int Number of affected rows + */ + abstract public function affected_rows(); + + /** + * Returns the number of rows from last executed select query. + * + * @return int The number of rows from last select query result + */ + abstract public function num_rows(); + + /** + * Returns the number of fields (colums) from current record set + * + * @return int Number of fields + */ + abstract public function num_fields(); + + /** + * Returns the number of rows (record set). + * Shortcut for function num_rows(). + * + * @return int Number of rows + */ + public function nf() { + return $this->num_rows(); + } + + /** + * Displays the number of rows (record set) using print. + * + * @return void + */ + public function np() { + print $this->num_rows(); + } + + /** + * Returns the desired field value from current record set. + * + * @param mixed The field name or index position + * @param mixed The default value to return + * @return mixed The value of field + */ + public function f($Name, $default = null) { + return (isset($this->Record[$Name])) ? $this->Record[$Name] : $default; + } + + /** + * Displays the desired field value from current record set using print. + * + * @param mixed The field name or index position + * @return void + */ + public function p($Name) { + if (isset($this->Record[$Name])) { + print $this->Record[$Name]; + } + } + + /** + * Returns current recordset as a assoziative and/or indexed array. + * + * @param string $fetchMode One of DB_SQL_Abstract::FETCH_* constants + * @return array + */ + public function toArray($fetchMode = DB_SQL_Abstract::FETCH_ASSOC) { + switch ($fetchMode) { + case self::FETCH_NUMERIC: + case self::FETCH_ASSOC: + case self::FETCH_BOTH: + // donut + break; + default: + $fetchMode = DB_SQL_Abstract::FETCH_ASSOC; + break; + } + + $aResult = array(); + if (is_array($this->Record)) { + foreach ($this->Record as $key => $value) { + if ($fetchMode == self::FETCH_ASSOC && !is_numeric($key)) { + $aResult[$key] = $value; + } elseif ($fetchMode == self::FETCH_NUMERIC && is_numeric($key)) { + $aResult[$key] = $value; + } else { + $aResult[$key] = $value; + } + } + } + return $aResult; + } + + /** + * Returns current recordset as a object + * + * @return stdClass + */ + public function toObject() { + return (object) $this->toArray(self::FETCH_ASSOC); + } + + /** + * Returns the next id (sequence number). + * + * @param string $seq_name The sequence name to get the next id from + * @return int The next id or 0 on error + */ + abstract public function nextid($seq_name); + + /** + * Wrapper method for disconnect() + * @see DB_Sql_Abstract::disconnect() + */ + public function close() { + $this->disconnect(); + } + + /** + * Closes the connection and frees the query id. + * + * @return void + */ + abstract public function disconnect(); + + /** + * Error handling + * + * Error handler function, delegates passed message to the function haltmsg() if propery + * $this->Halt_On_Error is not set to self::HALT_REPORT. + * + * Terminates further script execution if $this->Halt_On_Error is set to self::HALT_YES + * + * @param string $sMsg The message to use for error handling + * @return void + */ + public function halt($sMsg) { + if ($this->Halt_On_Error == self::HALT_REPORT) { + $this->haltmsg($this->_sHaltMsgPrefix . $sMsg); + } + + if ($this->Halt_On_Error == self::HALT_YES) { + die('Session halted.'); + } + } + + /** + * Logs passed message, basically the last db error to the error log. + * Concatenates a detailed error message and invokey PHP's error_log() method. + * + * @param string $sMsg + * @return void + */ + public function haltmsg($sMsg) { + $sName = 'ConLite DB'; + if (!$this->Error) { + $this->Error = $this->_getErrorMessage(); + } + if (!$this->Errno) { + $this->Errno = $this->_getErrorNumber(); + } + + $sMsg = sprintf("%s error: %s (%s) - info: %s\n", $sName, $this->Errno, $this->Error, $sMsg); + error_log($sMsg); + } + + /** + * Returns names of existing tables. + * + * @return array|null Indexed array containing assoziative table data as + * follows or null: + * - $info[$i]['table_name'] + * - $info[$i]['tablespace_name'] + * - $info[$i]['database'] + */ + public function table_names() { + if (!$this->connect()) { + return null; + } + if (method_exists($this, '_tableNames')) { + return $this->_tableNames(); + } + return null; + } + + /** + * Implemetation for table_names() in child classes + * @see DB_Sql_Abstract::table_names() + */ + abstract protected function _tableNames(); + + /** + * Escape string for using in SQL-Statement. + * + * @param string $sString The string to escape + * @return string Escaped string + */ + abstract public function escape($sString); + + /** + * Returns information about DB server. The return value depends allways on + * used DBMS. + * + * @return array|null Assoziative array as follows or null: + * - $arr['description'] (string) Optional, server description + * - $arr['version'] (string) Optional, server version + */ + public function server_info() { + if (!$this->connect()) { + return null; + } + if (method_exists($this, '_serverInfo')) { + return $this->_serverInfo(); + } + return null; + } + + /** + * Implemetation for server_info() in child classes. + * @see DB_Sql_Abstract::server_info() + */ + abstract protected function _serverInfo(); + + /** + * Returns error message of last occured error. + * + * @return string + */ + public function getErrorMessage() { + return $this->Error; + } + + /** + * Returns error message of last occured error by using databases interface. + * + * @return string + */ + abstract protected function _getErrorMessage(); + + /** + * Returns error code of last occured error by using databases interface. + * + * @return int + */ + public function getErrorNumber() { + return $this->Errno; + } + + /** + * Returns error code of last occured error by using databases interface. + * + * @return int + */ + abstract protected function _getErrorNumber(); + + /** + * Adds a entry to the profile data. + * + * @param float $fStartTime + * @param float $fEndTime + * @param string $sQuery + * @return void + */ + protected static function _addProfileData($fStartTime, $fEndTime, $sQuery) { + self::$_aProfileData[] = array( + 'time' => $fEndTime - $fStartTime, + 'query' => $sQuery + ); + } + + /** + * Returns collected profile data. + * + * @return array Profile data array like: + * - $arr[$i]['time'] (float) Elapsed time to execute the query + * - $arr[$i]['query'] (string) The query itself + */ + public static function getProfileData() { + return self::$_aProfileData; + } + + /** + * Displays the passed message, if debug is enabled (see $this->Debug) + * + * @param string $sMsg The message to display + * @return void + */ + protected function _debug($sMsg) { + if ($this->Debug) { + printf("
" . $sMsg . "
\n"); + } + } + + /** + * returns info about db-server + * + * return string + */ + abstract public function getServerInfo(); + + /** + * returns client encoding + * + * return string + */ + abstract public function getClientEncoding(); + + /** + * returns client info + * + * return string + */ + abstract public function getClientInfo(); +} diff --git a/branches/php7/conlib/index.php b/branches/php7/conlib/index.php new file mode 100644 index 0000000..ef8b776 --- /dev/null +++ b/branches/php7/conlib/index.php @@ -0,0 +1,4 @@ + diff --git a/branches/php7/conlib/local.php b/branches/php7/conlib/local.php new file mode 100644 index 0000000..22d1145 --- /dev/null +++ b/branches/php7/conlib/local.php @@ -0,0 +1,896 @@ + + * @license http://www.contenido.org/license/LIZENZ.txt + * @link http://www.4fb.de + * @link http://www.contenido.org + * + * + * {@internal + * created 2000-01-01 + * modified 2008-07-04, bilal arslan, added security fix + * modified 2010-02-02, Ingo van Peeren, added local method connect() in order + * to allow only one database connection, see [CON-300] + * modified 2010-02-17, Ingo van Peeren, only one connection for mysqli too + * modified 2011-03-03, Murat Purc, some redesign/improvements (partial adaption to PHP 5) + * modified 2011-03-18, Murat Purc, Fixed occuring "Duplicated entry" errors by using CT_Sql, see [CON-370] + * modified 2011-03-21, Murat Purc, added Contenido_CT_Session to uses PHP's session implementation + * + * $Id: local.php 300 2014-01-30 14:28:53Z oldperl $: + * }} + * + */ + +if (!defined('CON_FRAMEWORK')) { + die('Illegal call'); +} + +/** + * DB-class for all DB handling + */ +class DB_ConLite extends DB_Sql +{ + /** + * Constructor of database class. + * + * @param array $options Optional assoziative options. The value depends + * on used DBMS, but is generally as follows: + * - $options['connection']['host'] (string) Hostname or ip + * - $options['connection']['database'] (string) Database name + * - $options['connection']['user'] (string) User name + * - $options['connection']['password'] (string) User password + * - $options['nolock'] (bool) Optional, not lock table + * - $options['sequenceTable'] (string) Optional, sequesnce table + * - $options['haltBehavior'] (string) Optional, halt behavior on occured errors + * - $options['haltMsgPrefix'] (string) Optional, Text to prepend to the halt message + * - $options['enableProfiling'] (bool) Optional, flag to enable profiling + * @return void + */ + public function __construct(array $options = array()) + { + global $cachemeta; + + parent::__construct($options); + + if (!is_array($cachemeta)) { + $cachemeta = array(); + } + + // TODO check this out + // HerrB: Checked and disabled. Kills umlauts, if tables are latin1_general. + + // try to use the new connection and get the needed encryption + //$this->query("SET NAMES 'utf8'"); + } + + + /** + * Fetches the next recordset from result set + * + * @param bool + */ + public function next_record() + { + global $cCurrentModule; + // FIXME For what reason is NoRecord used??? + $this->NoRecord = false; + if (!$this->Query_ID) { + $this->NoRecord = true; + if ($cCurrentModule > 0) { + $this->halt("next_record called with no query pending in Module ID $cCurrentModule."); + } else { + $this->halt("next_record called with no query pending."); + } + return false; + } + + return parent::next_record(); + } + + + /** + * Returns the metada of passed table + * + * @param string $sTable The tablename of empty string to retrieve metadata of all tables! + * @return array|bool Assoziative metadata array (result depends on used db driver) + * or false in case of an error + * @deprecated Use db drivers toArray() method instead + */ + public function copyResultToArray($sTable = '') + { + global $cachemeta; + + $aValues = array(); + + if ($sTable != '') { + if (array_key_exists($sTable, $cachemeta)) { + $aMetadata = $cachemeta[$sTable]; + } else { + $cachemeta[$sTable] = $this->metadata($sTable); + $aMetadata = $cachemeta[$sTable]; + } + } else { + $aMetadata = $this->metadata($sTable); + } + + if (!is_array($aMetadata) || count($aMetadata) == 0) { + return false; + } + + foreach ($aMetadata as $entry) { + $aValues[$entry['name']] = $this->f($entry['name']); + } + + return $aValues; + } +} + +/** + * Wrapper class for old contenido class + * + * @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 Contenido_CT_Sql extends CT_Sql +{ + /** + * Database class name + * @var string + */ + public $database_class = 'DB_Contenido'; + + /** + * And find our session data in this table. + * @var string + */ + public $database_table = ''; + + public function __construct() + { + global $cfg; + $this->database_table = $cfg['tab']['phplib_active_sessions']; + } + + /** + * Stores the session data in database table. + * + * Overwrites parents and uses MySQLs REPLACE statement, to prevent race + * conditions while executing INSERT statements by multiple frames in backend. + * + * - Existing entry will be overwritten + * - Non existing entry will be added + * + * @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); + } + + $name = addslashes($name); + $now = date('YmdHis', time()); + + $iquery = sprintf( + "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; + } +} + + +/** + * Implements the interface class for storing session data to disk using file + * session container of phplib. + */ +class Contenido_CT_File extends CT_File +{ + /** + * The maximum length for one line in session file. + * @var int + */ + public $iLineLength = 999999; + + /** + * Overrides standard constructor for setting up file path to the one which is + * configured in php.ini + * + * @return Contenido_CT_File + * + * @author Holger Librenz + */ + public function __construct() + { + global $cfg; + + if (isset($cfg['session_line_length']) && !empty($cfg['session_line_length'])) { + $this->iLineLength = (int) $cfg['session_line_length']; + } + + // get php.ini value for session path + $this->file_path = session_save_path() . '/'; + } + + /** + * Overrides get method, because standard byte count is not really senseful for + * contenido! + * + * @param string $sId + * @param string $sName + * @return mixed + */ + public function ac_get_value($sId, $sName) + { + if (file_exists($this->file_path . "$sId$sName")) { + $f = fopen($this->file_path . "$sId$sName", 'r'); + if ($f<0) { + return ''; + } + + $s = fgets($f, $this->iLineLength); + fclose($f); + + return urldecode($s); + } else { + return ''; + } + } +} + +class Contenido_CT_Shm extends CT_Shm +{ + public function __construct() + { + $this->ac_start(); + } +} + + +/** + * Contenido session container, uses PHP's session implementation. + * + * NOTE: Is experimental, so don't use this in a production environment. + * + * To use this, set session container in contenido/includes/config.misc.php to + * $cfg["session_container"] = 'session'; + * + * @todo Make session container configurable + * + * @author Murat Purc + */ +class Contenido_CT_Session extends CT_Session +{ + public function __construct() + { + $this->ac_start(array( + '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', + )); + } +} + +class Contenido_Session extends Session +{ + public $classname = 'Contenido_Session'; + public $cookiename = 'contenido'; ## defaults to classname + public $magic = '934ComeOnEileen'; ## ID seed + public $mode = 'get'; ## We propagate session IDs with cookies + public $fallback_mode = 'cookie'; + public $lifetime = 0; ## 0 = do session cookies, else minutes + public $that_class = 'Contenido_CT_Sql'; ## name of data storage container + public $gc_probability = 5; + + public function __construct() + { + global $cfg; + + $sFallback = 'sql'; + $sClassPrefix = 'Contenido_CT_'; + + $sStorageContainer = strtolower($cfg['session_container']); + + if (class_exists ($sClassPrefix . ucfirst($sStorageContainer))) { + $sClass = $sClassPrefix . ucfirst($sStorageContainer); + } else { + $sClass = $sClassPrefix . ucfirst($sFallback); + } + + $this->that_class = $sClass; + } + + public function delete() + { + $oCol = new InUseCollection(); + $oCol->removeSessionMarks($this->id); + parent::delete(); + } +} + + +class Contenido_Frontend_Session extends Session +{ + public $classname = 'Contenido_Frontend_Session'; + public $cookiename = 'sid'; ## defaults to classname + public $magic = 'Phillipip'; ## ID seed + public $mode = 'cookie'; ## We propagate session IDs with cookies + public $fallback_mode = 'cookie'; + public $lifetime = 0; ## 0 = do session cookies, else minutes + public $that_class = 'Contenido_CT_Sql'; ## name of data storage container + public $gc_probability = 5; + + public function __construct() + { + global $load_lang, $load_client, $cfg; + + $this->cookiename = 'sid_' . $load_client . '_' . $load_lang; + + $this->setExpires(time()+3600); + + // added 2007-10-11, H. Librenz + // bugfix (found by dodger77): we need alternative session containers + // also in frontend + $sFallback = 'sql'; + $sClassPrefix = 'Contenido_CT_'; + + $sStorageContainer = strtolower($cfg['session_container']); + + if (class_exists($sClassPrefix . ucfirst($sStorageContainer))) { + $sClass = $sClassPrefix . ucfirst($sStorageContainer); + } else { + $sClass = $sClassPrefix . ucfirst($sFallback); + } + + $this->that_class = $sClass; + } +} + +class Contenido_Auth extends Auth +{ + public $classname = 'Contenido_Auth'; + public $lifetime = 15; + public $database_class = 'DB_Contenido'; + public $database_table = 'con_phplib_auth_user'; + + public function auth_loginform() + { + global $sess, $_PHPLIB; + include($_PHPLIB['libdir'] . 'loginform.ihtml'); + } + + public function auth_validatelogin() + { + global $username, $password; + + if ($password == '') { + return false; + } + + if (isset($username)) { + $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; + } + $uid = false; + + $this->db->query( + sprintf("SELECT user_id, perms FROM %s WHERE username = '%s' AND password = '%s'", + $this->database_table, addslashes($username), addslashes($password)) + ); + + while ($this->db->next_record()) { + $uid = $this->db->f('user_id'); + $this->auth['perm'] = $this->db->f('perms'); + } + return $uid; + } +} + + +class Contenido_Default_Auth extends Contenido_Auth +{ + public $classname = 'Contenido_Default_Auth'; + public $lifetime = 1; + public $nobody = true; + + public function auth_loginform() + { + global $sess, $_PHPLIB; + include($_PHPLIB['libdir'] . 'defloginform.ihtml'); + } +} + + +class Contenido_Challenge_Auth extends Auth +{ + public $classname = 'Contenido_Challenge_Auth'; + public $lifetime = 1; + public $magic = 'Simsalabim'; ## Challenge seed + public $database_class = 'DB_Contenido'; + public $database_table = 'con_phplib_auth_user'; + + public function auth_loginform() + { + global $sess, $challenge, $_PHPLIB; + + $challenge = md5(uniqid($this->magic)); + $sess->register('challenge'); + + include($_PHPLIB['libdir'] . 'crloginform.ihtml'); + } + + public function auth_validatelogin() + { + global $username, $password, $challenge, $response, $timestamp; + + if ($password == '') { + return false; + } + + if (isset($username)) { + // This provides access for 'loginform.ihtml' + $this->auth['uname'] = $username; + } + + // Sanity check: If the user presses 'reload', don't allow a login with the data + // again. Instead, prompt again. + if ($timestamp < (time() - 60 * 15)) { + return false; + } + $this->db->query( + sprintf("SELECT user_id, perms, password FROM %s WHERE username = '%s'", + $this->database_table, addslashes($username)) + ); + + while ($this->db->next_record()) { + $uid = $this->db->f('user_id'); + $perm = $this->db->f('perms'); + $pass = $this->db->f('password'); + } + $exspected_response = md5("$username:$pass:$challenge"); + + // True when JS is disabled + if ($response == '') { + if ($password != $pass) { + return false; + } else { + $this->auth['perm'] = $perm; + return $uid; + } + } + + // Response is set, JS is enabled + if ($exspected_response != $response) { + return false; + } else { + $this->auth['perm'] = $perm; + return $uid; + } + } +} + +## +## Contenido_Challenge_Crypt_Auth: Keep passwords in md5 hashes rather +## than cleartext in database +## Author: Jim Zajkowski + +class Contenido_Challenge_Crypt_Auth extends Auth +{ + public $classname = 'Contenido_Challenge_Crypt_Auth'; + public $lifetime = 15; + public $magic = 'Frrobo123xxica'; ## Challenge seed + public $database_class = 'DB_Contenido'; + public $database_table = ''; + public $group_table = ''; + public $member_table = ''; + + public function __construct() + { + global $cfg; + $this->database_table = $cfg['tab']['phplib_auth_user_md5']; + $this->group_table = $cfg['tab']['groups']; + $this->member_table = $cfg['tab']['groupmembers']; + $this->lifetime = $cfg['backend']['timeout']; + + if ($this->lifetime == 0) { + $this->lifetime = 15; + } + } + + public function auth_loginform() + { + global $sess, $challenge, $_PHPLIB, $cfg; + + $challenge = md5(uniqid($this->magic)); + $sess->register('challenge'); + + include($cfg['path']['contenido'] . 'main.loginform.php'); + } + + public function auth_loglogin($uid) + { + global $cfg, $client, $lang, $auth, $sess, $saveLoginTime; + + $perm = new Contenido_Perm(); + $timestamp = date('Y-m-d H:i:s'); + $idcatart = '0'; + + /* Find the first accessible client and language for the user */ + // All the needed information should be available in clients_lang - but the previous code was designed with a + // reference to the clients table. Maybe fail-safe technology, who knows... + $sql = 'SELECT tblClientsLang.idclient, tblClientsLang.idlang FROM ' . + $cfg['tab']['clients'] . ' AS tblClients, ' . $cfg['tab']['clients_lang'] . ' AS tblClientsLang ' . + 'WHERE tblClients.idclient = tblClientsLang.idclient ORDER BY idclient ASC, idlang ASC'; + $this->db->query($sql); + + $bFound = false; + while ($this->db->next_record() && !$bFound) { + $iTmpClient = $this->db->f('idclient'); + $iTmpLang = $this->db->f('idlang'); + + if ($perm->have_perm_client_lang($iTmpClient, $iTmpLang)) { + $client = $iTmpClient; + $lang = $iTmpLang; + $bFound = true; + } + } + + if (isset($idcat) && isset($idart)) { + // SECURITY FIX + $sql = "SELECT idcatart + FROM + ". $cfg['tab']['cat_art'] ." + WHERE + idcat = '".Contenido_Security::toInteger($idcat)."' AND + idart = '".Contenido_Security::toInteger($idart)."'"; + + $this->db->query($sql); + $this->db->next_record(); + $idcatart = $this->db->f('idcatart'); + } + + if (!is_numeric($client) || !is_numeric($lang)) { + return; + } + + $idaction = $perm->getIDForAction('login'); + $lastentry = $this->db->nextid($cfg['tab']['actionlog']); + + $sql = "INSERT INTO + ". $cfg['tab']['actionlog']." + SET + idlog = $lastentry, + user_id = '" . $uid . "', + idclient = '".Contenido_Security::toInteger($client)."', + idlang = '".Contenido_Security::toInteger($lang)."', + idaction = $idaction, + idcatart = $idcatart, + logtimestamp = '$timestamp'"; + + $this->db->query($sql); + $sess->register('saveLoginTime'); + $saveLoginTime = true; + } + + public function auth_validatelogin() + { + global $username, $password, $challenge, $response, $formtimestamp, $auth_handlers; + + $gperm = array(); + + if ($password == '') { + return false; + } + + if (($formtimestamp + (60*15)) < time()) { + return false; + } + + if (isset($username)) { + $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; + } + + $uid = false; + $perm = false; + $pass = false; + + $sDate = date('Y-m-d'); + + $this->db->query(sprintf("SELECT user_id, perms, password FROM %s WHERE username = '%s' AND + (valid_from <= '".$sDate."' OR valid_from = '0000-00-00' OR valid_from is NULL) AND + (valid_to >= '".$sDate."' OR valid_to = '0000-00-00' OR valid_to is NULL)", + $this->database_table, + Contenido_Security::escapeDB($username, $this->db) + )); + + $sMaintenanceMode = getSystemProperty('maintenance', 'mode'); + while($this->db->next_record()) { + $uid = $this->db->f('user_id'); + $perm = $this->db->f('perms'); + $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; + } + } + + if ($bInMaintenance) { + unset($uid); + unset($perm); + 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 ($uid == false) { + ## No user found, sleep and exit + sleep(5); + return false; + } else { + $this->db->query(sprintf("SELECT a.group_id AS group_id, a.perms AS perms ". + "FROM %s AS a, %s AS b WHERE a.group_id = b.group_id AND b.user_id = '%s'", + $this->group_table, + $this->member_table, + $uid + )); + + if ($perm != '') { + $gperm[] = $perm; + } + + while ($this->db->next_record()) { + $gperm[] = $this->db->f('perms'); + } + + if (is_array($gperm)) { + $perm = implode(',',$gperm); + } + + if ($response == '') { ## True when JS is disabled + if (md5($password) != $pass) { ## md5 hash for non-JavaScript browsers + sleep(5); + return false; + } else { + $this->auth['perm'] = $perm; + $this->auth_loglogin($uid); + return $uid; + } + } + + $expected_response = md5("$username:$pass:$challenge"); + + if ($expected_response != $response) { ## Response is set, JS is enabled + sleep(5); + return false; + } else { + $this->auth['perm'] = $perm; + $this->auth_loglogin($uid); + return $uid; + } + } + } +} + +class Contenido_Frontend_Challenge_Crypt_Auth extends Auth +{ + public $classname = 'Contenido_Frontend_Challenge_Crypt_Auth'; + public $lifetime = 15; + public $magic = 'Frrobo123xxica'; ## Challenge seed + public $database_class = 'DB_Contenido'; + public $database_table = ''; + public $fe_database_table = ''; + public $group_table = ''; + public $member_table = ''; + public $nobody = true; + + public function __construct() + { + global $cfg; + $this->database_table = $cfg['tab']['phplib_auth_user_md5']; + $this->fe_database_table = $cfg['tab']['frontendusers']; + $this->group_table = $cfg['tab']['groups']; + $this->member_table = $cfg['tab']['groupmembers']; + } + + public function auth_preauth() + { + global $password; + + if ($password == '') { + /* Stay as nobody when an empty password is passed */ + $uid = $this->auth['uname'] = $this->auth['uid'] = 'nobody'; + return false; + } + + return $this->auth_validatelogin(); + } + + public function auth_loginform() + { + global $sess, $challenge, $_PHPLIB, $client, $cfgClient; + + $challenge = md5(uniqid($this->magic)); + $sess->register('challenge'); + + include($cfgClient[$client]['path']['frontend'].'front_crcloginform.inc.php'); + } + + public function auth_validatelogin() + { + 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' + $uid = $this->auth['uname'] = $this->auth['uid'] = 'nobody'; + return $uid; + } + + $uid = false; + + /* Authentification via frontend users */ + $this->db->query(sprintf("SELECT idfrontenduser, password FROM %s WHERE username = '%s' AND idclient='$client' AND active='1'", + $this->fe_database_table, + Contenido_Security::escapeDB(urlencode($username), $this->db) + )); + + if ($this->db->next_record()) { + $uid = $this->db->f('idfrontenduser'); + $perm = 'frontend'; + $pass = $this->db->f('password'); + } + + if ($uid == false) { + /* Authentification via backend users */ + $this->db->query(sprintf("SELECT user_id, perms, password FROM %s WHERE username = '%s'", + $this->database_table, + Contenido_Security::escapeDB($username, $this->db) )); + + while($this->db->next_record()) { + $uid = $this->db->f('user_id'); + $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 ($uid !== false) { + $this->db->query(sprintf("SELECT a.group_id AS group_id, a.perms AS perms ". + "FROM %s AS a, %s AS b WHERE a.group_id = b.group_id AND ". + "b.user_id = '%s'", + $this->group_table, + $this->member_table, + $uid + )); + + /* Deactivated: Backend user would be sysadmin when logged on as frontend user + * (and perms would be checked), see http://www.contenido.org/forum/viewtopic.php?p=85666#85666 + $perm = 'sysadmin'; */ + if ($perm != '') { + $gperm[] = $perm; + } + + while ($this->db->next_record()) { + $gperm[] = $this->db->f('perms'); + } + + if (is_array($gperm)) { + $perm = implode(',',$gperm); + } + } + } + + if ($uid == false) { + ## User not found, sleep and exit + sleep(5); + return false; + } else { + if ($response == '') { ## True when JS is disabled + if (md5($password) != $pass) { ## md5 hash for non-JavaScript browsers + sleep(5); + return false; + } else { + $this->auth['perm'] = $perm; + return $uid; + } + } + + $expected_response = md5("$username:$pass:$challenge"); + if ($expected_response != $response) { ## Response is set, JS is enabled + sleep(5); + return false; + } else { + $this->auth['perm'] = $perm; + return $uid; + } + } + } +} + +/** + * Registers an external auth handler + */ +function register_auth_handler($aHandlers) +{ + global $auth_handlers; + + if (!is_array($auth_handlers)) { + $auth_handlers = array(); + } + + if (!is_array($aHandlers)) { + $aHandlers = Array($aHandlers); + } + + foreach ($aHandlers as $sHandler) { + if (!in_array($sHandler, $auth_handlers)) { + $auth_handlers[md5($sHandler)] = $sHandler; + } + } +} + +?> \ No newline at end of file diff --git a/branches/php7/conlib/page.inc b/branches/php7/conlib/page.inc new file mode 100644 index 0000000..81b74dd --- /dev/null +++ b/branches/php7/conlib/page.inc @@ -0,0 +1,110 @@ + + * @license http://www.contenido.org/license/LIZENZ.txt + * @link http://www.4fb.de + * @link http://www.contenido.org + * @since file available since contenido release + * @deprecated file deprecated in contenido release + * + * {@internal + * created 2002-07-21 + * modified 2008-07-04, bilal arslan, added security fix + * + * $Id: page.inc 1315 2011-03-03 00:02:52Z xmurrix $: + * }} + * + */ + if(!defined('CON_FRAMEWORK')) { + die('Illegal call'); +} + + +function page_open($feature) { + global $_PHPLIB; + + # enable sess and all dependent features. + if (isset($feature["sess"])) { + global $sess; + $sess = new $feature["sess"]; + $sess->start(); + + # the auth feature depends on sess + if (isset($feature["auth"])) { + global $auth; + + if (!isset($auth)) { + $auth = new $feature["auth"]; + } + $auth->start(); + + + # the perm feature depends on auth and sess + if (isset($feature["perm"])) { + global $perm; + + if (!isset($perm)) { + $perm = new $feature["perm"]; + } + } + + # the user feature depends on auth and sess + if (isset($feature["user"])) { + global $user; + + if (!isset($user)) { + $user = new $feature["user"]; + } + $user->start($auth->auth["uid"]); + } + } + + ## Load the auto_init-File, if one is specified. + if (($sess->auto_init != "") && !$sess->in) { + $sess->in = 1; + include($_PHPLIB["libdir"] . $sess->auto_init); + if ($sess->secure_auto_init != "") { + $sess->freeze(); + } + } + } +} + +function page_close() { + global $sess, $user; + + if (isset($sess)) { + $sess->freeze(); + if (isset($user) && method_exists($user, "freeze")) { + $user->freeze(); + } + } +} + +function sess_load($session) { + reset($session); + while (list($k,$v) = each($session)) { + $GLOBALS[$k] = new $v; + $GLOBALS[$k]->start(); + } +} + +function sess_save($session) { + reset($session); + while (list(,$v) = each($session)) { + $GLOBALS[$v]->freeze(); + } +} +?> diff --git a/branches/php7/conlib/perm.inc b/branches/php7/conlib/perm.inc new file mode 100644 index 0000000..f8b6f17 --- /dev/null +++ b/branches/php7/conlib/perm.inc @@ -0,0 +1,678 @@ + + * @license http://www.contenido.org/license/LIZENZ.txt + * @link http://www.4fb.de + * @link http://www.contenido.org + * @since file available since contenido release + * @deprecated file deprecated in contenido release + * + * {@internal + * created 2002-08-16 + * modified 2008-07-04, bilal arslan, added security fix + * modified 2009-10-29, Murat Purc, replaced deprecated functions (PHP 5.3 ready) and some formatting + * + * $Id: perm.inc 1315 2011-03-03 00:02:52Z xmurrix $: + * }} + * + */ +if (!defined('CON_FRAMEWORK')) { + die('Illegal call'); +} + +class Contenido_Perm { + + var $classname = "Contenido_Perm"; + var $areacache = array(); + var $actioncache = array(); + var $db; + var $db_perm; + + function getGroupsForUser($user) { + global $cfg; + + if (!is_object($this->db)) { + $this->db = new DB_Contenido; + } + + $sql = "SELECT group_id FROM + " . $cfg["tab"]["groupmembers"] . " + WHERE user_id = '" . Contenido_Security::escapeDB($user, $this->db) . "'"; + $this->db->query($sql); + + $groups = array(); + + while ($this->db->next_record()) { + $groups[] = $this->db->f("group_id"); + } + + return $groups; + } + + function getIDForArea($area) { + global $cfg; + + if (!is_object($this->db_perm)) { + $this->db_perm = new DB_Contenido; + } + + if (!is_numeric($area)) { + if (!@ array_key_exists($area, $this->areacache)) { + $sql = "SELECT idarea + FROM + " . $cfg["tab"]["area"] . " + WHERE + name = \"" . Contenido_Security::escapeDB($area, $this->db_perm) . "\""; + $this->db_perm->query($sql); + + $this->db_perm->next_record(); + $this->areacache[$area] = $this->db_perm->f("idarea"); + $area = $this->db_perm->f(0); + } else { + $area = $this->areacache[$area]; + } + + return ($area); + } + + return $area; + } + + function getIDForAction($action) { + + global $cfg; + + if (!is_object($this->db_perm)) { + $this->db_perm = new DB_Contenido; + } + + if (!is_numeric($action)) { + if (!@ array_key_exists($action, $this->actioncache)) { + $sql = "SELECT idaction + FROM + " . $cfg["tab"]["actions"] . " + WHERE + name = \"" . Contenido_Security::escapeDB($action, $this->db_perm) . "\""; + + $this->db_perm->query($sql); + $this->db_perm->next_record(); + + $this->actioncache[$action] = $this->db_perm->f("idaction"); + $action = $this->db_perm->f(0); + } else { + $action = $this->actioncache[$action]; + } + return ($action); + } + + return $action; + } + + function load_permissions($force = false) { + + global $sess, $area_rights, $item_rights, $db, $client, $lang, $auth, $cfg, $changelang, $changeclient; + + $return = "1"; + //if not admin or sysadmin + if (!$this->have_perm()) { + $return = isset($area_rights); + + if (!isset($area_rights) || !isset($item_rights) || isset($changeclient) || isset($changelang) || $force) { + $return = "3"; + //register variables + $sess->register("area_rights"); + $sess->register("item_rights"); + $item_rights = array(); + + $groups = $this->getGroupsForUser($auth->auth["uid"]); + + if (is_array($groups)) { + foreach ($groups as $group) { + $this->load_permissions_for_user($group); + } + } + + $this->load_permissions_for_user($auth->auth["uid"]); + } + } + + return $return; + } + + function load_permissions_for_user($user) { + global $db, $client, $lang, $cfg; + global $area_rights, $item_rights; + $sql = "SELECT * + FROM " . $cfg["tab"]["rights"] . " + WHERE user_id='" . Contenido_Security::escapeDB($user, $db) . "' AND idcat='0' AND idclient='" . Contenido_Security::toInteger($client) . "' AND idlang='" . Contenido_Security::toInteger($lang) . "'"; + $db->query($sql); + + if (!is_array($area_rights)) { + $area_rights = array(); + } + while ($db->next_record()) { + $area_rights[$db->f("idarea")][$db->f("idaction")] = true; + } + + // Select Rights for Article and Sructure Atention Hard code Areas + $sql = "SELECT + idarea + FROM + " . $cfg["tab"]["area"]; + $db->query($sql); + + $tmp_area = array(); + while ($db->next_record()) { + array_push($tmp_area, $db->f("idarea")); + } + + $tmp_area_string = implode("','", array_keys($tmp_area)); + $sql = "SELECT + idarea, idaction, idcat + FROM " . $cfg["tab"]["rights"] . " + WHERE user_id='" . Contenido_Security::escapeDB($user, $db) . "' AND idclient='" . Contenido_Security::toInteger($client) . "' AND idlang='" . Contenido_Security::toInteger($lang) . "' AND idarea IN ('$tmp_area_string') AND idcat != '0'"; + $db->query($sql); + + while ($db->next_record()) { + $item_rights[$db->f(0)][$db->f(1)][$db->f(2)] = $db->f(2); + } + } + + function have_perm_area_action_anyitem($area, $action = 0) { + + if ($this->have_perm_area_action($area, $action)) { + return true; + } + + $area = $this->getIDForArea($area); + $action = $this->getIDForAction($action); + + global $item_rights; + + if (isset($item_rights[$area][$action])) { + return true; + } else { + return false; + } + } + + function have_perm_area_action_item($area, $action, $itemid) { + global $item_rights, $auth, $client, $lang, $cfg; + + if (!is_object($this->db)) { + $this->db = new DB_Contenido; + } + + $area = $this->getIDForArea($area); + $action = $this->getIDForAction($action); + + if ($this->have_perm()) { + return true; + } else { + //if the user has a right on this action in this area check for the items + if ($this->have_perm_area_action($area, $action)) { + return true; + } + //check rights for the action in this area at this item + if (isset($item_rights[$area][$action][$itemid])) { + //if have action for area + action +item check right for client and lang + return true; + } elseif ($item_rights[$area] != "noright") { + + $groupsForUser = $this->getGroupsForUser($auth->auth[uid]); + $groupsForUser[] = $auth->auth[uid]; + + $tmp_userstring = implode("','", $groupsForUser); + + $sql = "SELECT * + FROM " . $cfg["tab"]["rights"] . " + WHERE user_id IN ('" . $tmp_userstring . "') AND idclient = '" . Contenido_Security::toInteger($client) . "' AND idlang = '" . Contenido_Security::toInteger($lang) . "' AND idarea = '$area' AND idcat != '0'"; + $this->db->query($sql); + + //if there are no rights for this area set the flag norights + if ($this->db->nf() == 0) { + $item_rights[$area] = "noright"; + return false; + } + + while ($this->db->next_record()) { + $item_rights[$this->db->f("idarea")][$this->db->f("idaction")][$this->db->f("idcat")] = $this->db->f("idcat"); + } + + //check + if (isset($item_rights[$area][$action][$itemid])) { + //if have action for area + action +item check right for client and lang + return true; + } + } + return false; + } + } + + function getParentAreaId($area) { + + global $client, $lang, $cfg, $sess; + + if (!is_object($this->db)) { + $this->db = new DB_Contenido; + } + + if (is_numeric($area)) { + $sql = "SELECT + b.name + FROM + " . $cfg["tab"]["area"] . " AS a, + " . $cfg["tab"]["area"] . " AS b + WHERE + a.idarea = '" . Contenido_Security::toInteger($area) . "' AND + b.name = a.parent_id"; + } else { + $sql = "SELECT + b.name + FROM + " . $cfg["tab"]["area"] . " AS a, + " . $cfg["tab"]["area"] . " AS b + WHERE + a.name = '" . Contenido_Security::escapeDB($area, $this->db) . "' AND + b.name = a.parent_id"; + } + $this->db->query($sql); + + if ($this->db->next_record()) { + return $this->db->f(0); + } else { + return $area; + } + } + + function have_perm_area_action($area, $action = 0) { + global $area_rights, $client, $lang, $cfg; + //if not admin or sysadmin + if (!is_object($this->db_perm)) { + $this->db_perm = new DB_Contenido; + } + + $area = $this->getIDForArea($area); + $action = $this->getIDForAction($action); + + if ($action == 0) { + $area = $this->getParentAreaId($area); + } + + $area = $this->getIDForArea($area); + + if (!$this->have_perm()) { + + if ($action == 0 && $area_rights[$area]) { + //if have action for area + action check right for client and lang + return ($this->have_perm_client_lang($client, $lang)); + } + + //check rights for the action in this area + if ($area_rights[$area][$action]) { + //if have action for area + action check right for client and lang + return $this->have_perm_client_lang($client, $lang); + } + + return false; + } + return true; + } + + function have_perm_client_lang($client, $lang) { + // Changed back to a full featured function, as have_perm + // needs $client as global variable - not provided by this + // function + //return ($this->have_perm("client[$client],lang[$lang]")); + + global $auth; + + if (!isset($auth->auth['perm'])) { + $auth->auth['perm'] = ''; + } + + // Split the permissions of the user + $userperm = explode(',', $auth->auth['perm']); + + if (in_array('sysadmin', $userperm)) { + return true; // User is sysadmin + } elseif (in_array("admin[$client]", $userperm)) { + return true; // User is admin + } else { + // Check rights for the client and the language + $pageperm = explode(',', "client[$client],lang[$lang]"); + foreach ($pageperm as $value) { + if (!in_array($value, $userperm)) { + return false; + } + } + } + return true; + } + + /** + * hasClientPermission + * Checks if a user has access rights for a specific client. + * + * @param integer $iClient idclient to check, or false for the current client + * @param object $oUser User object to check against, or false for the current user + */ + function hasClientPermission($iClient = false, $oUser = false) { + global $auth; + + if ($iClient === false) { + global $client; + $iClient = $client; + } + + $oUser = $this->_checkUserObject($oUser); + + if ($this->isSysadmin($oUser) || $this->isClientAdmin($iClient, $oUser) || $this->isClientUser($iClient, $oUser)) { + return true; + } else { + return false; + } + /* Commented out Timo Trautmann, because here only client access is checked, possibility for admin or sysadmin access was ignored + functions isSysadmin isClientAdmin isClientUser also handles permission for groups + #Check clients' rights of users' group(s) + $aGroups = $this->getGroupsForUser($auth->auth["uid"]); + if (is_array($aGroups)) + { + foreach ($aGroups as $group) + { + $oGroup = new Group; + $oGroup->loadGroupByGroupID ($group); + + if ($this->isClientGroup($iClient, $oGroup)) + { + return true; + } + } + } + + return false; + } */ + } + + /** + * isClientUser + * Checks if the given user has access permission for a client + * + * @param integer $iClient idclient to check + * @param object $oUser User object to check against + */ + function isClientUser($iClient, $oUser) { + $oUser = $this->_checkUserObject($oUser); + + $aPermissions = explode(",", $oUser->getEffectiveUserPerms()); + + if (in_array("client[$iClient]", $aPermissions)) { + return true; + } + + return false; + } + + /** + * isClientGroup + * Checks if the given group has access permission for a client + * + * @param integer $iClient idclient to check + * @param object $oGroup Group object to check against + */ + function isClientGroup($iClient, $oGroup) { + $aPermissions = explode(",", $oGroup->getField("perms")); + + if (in_array("client[$iClient]", $aPermissions)) { + return true; + } + + return false; + } + + /** + * isClientAdmin + * Checks if the given user has an admin permission + * + * @param integer $iClient idclient to check + * @param object $oUser User object to check against + */ + function isClientAdmin($iClient, $oUser) { + $oUser = $this->_checkUserObject($oUser); + + $aPermissions = explode(",", $oUser->getEffectiveUserPerms()); + if (in_array("admin[$iClient]", $aPermissions)) { + return true; + } + + return false; + } + + /** + * Checks if the given user has sysadmin permission + * + * @param User $oUser userobject or false (default) + * @return boolean true if user is sysadmin + */ + public function isSysadmin($oUser = FALSE) { + $oUser2Check = $this->_checkUserObject($oUser); + if(!is_object($oUser2Check)) { + return false; + } + $aPermissions = explode(",", $oUser2Check->getEffectiveUserPerms()); + if (in_array("sysadmin", $aPermissions)) { + return true; + } + return false; + } + + /** + * _checkUserObject + * + * Checks if the given object is a user object. + * + * If oUser is false, initialize the object from the currently logged in user. If oUser is not + * a object of the class User, issue a warning. + * + * @parameter object oUser User object + * @access private + */ + private function _checkUserObject($oUser) { + if ($oUser === false) { + global $currentuser; + $oUser = $currentuser; + } + + if (!is_object($oUser)) { + global $auth; + $oUser = new User; + $oUser->loadUserByUserID($auth->auth["uid"]); + } + + if (strtolower(get_class($oUser)) != "user") { + cWarning(__FILE__, __LINE__, "oUser parameter is not of type User"); + } + + return $oUser; + } + + /** + * @deprecated + */ + function have_perm_client($p = 'x') { + global $auth, $client; + + if (!isset($auth->auth['perm'])) { + $auth->auth['perm'] = ''; + } + + //split the permissions of the user + $userperm = explode(',', $auth->auth['perm']); + + //if User is sysadmin or admin at this client return true + if (in_array('sysadmin', $userperm)) { + return true; + } + + //if there are more permissions to ask split them + $pageperm = explode(',', $p); + foreach ($pageperm as $value) { + if (!in_array($value, $userperm)) { + return false; + } + } + return true; + } + + function have_perm($p = 'x') { + global $auth, $client; + + if (!isset($auth->auth['perm'])) { + $auth->auth['perm'] = ''; + } + + //split the permissions of the user + $userperm = explode(',', $auth->auth['perm']); + + //if User is sysadmin or admin at this client return true + if (in_array('sysadmin', $userperm)) { + return true; + } elseif (in_array("admin[$client]", $userperm)) { + return true; + //else check rights for the client and the language + } else { + //if there are more permissions to ask split them + $pageperm = explode(',', $p); + foreach ($pageperm as $value) { + if (!in_array($value, $userperm)) { + return false; + } + } + } + return true; + } + + //checks if an item have any perms + function have_perm_item($mainarea, $itemid) { + + global $cfg, $item_rights, $cfg, $client, $lang, $auth, $area_tree, $sess; + + $mainarea = $this->getIDForArea($mainarea); + + //if is not admin or sysadmin + if (!$this->have_perm()) { + + if (!is_object($this->db)) { + $this->db = new DB_Contenido; + } + + $this->showareas($mainarea); + + $flg = false; + //check if there are any rights for this areas + foreach ($area_tree[$mainarea] as $value) { + // if the flag noright is set there are no rights in this area + if ($item_rights[$value] == "noright") { + continue; + } elseif (is_array($item_rights[$value])) { + //if there are any rights + foreach ($item_rights[$value] as $value2) { + if (in_array($itemid, $value2)) { + return true; + } + } + } elseif ($item_rights[$value] != "noright") { + + $groupsForUser = $this->getGroupsForUser($auth->auth[uid]); + $groupsForUser[] = $auth->auth[uid]; + + //else search for rights for this user in this area + $sql = "SELECT + * + FROM + " . $cfg["tab"]["rights"] . " + WHERE + user_id IN ('" . implode("','", $groupsForUser) . "') AND + idclient = '" . Contenido_Security::toInteger($client) . "' AND + idlang = '" . Contenido_Security::toInteger($lang) . "' AND + idarea = '$value' AND + idcat != '0'"; + $this->db->query($sql); + + //if there are no rights for this area set the flag norights + if ($this->db->affected_rows() == 0) { + $item_rights[$value] = "noright"; + } + + //set the rights + while ($this->db->next_record()) { + if ($this->db->f("idcat") == $itemid) { + $flg = true; + } + $item_rights[$this->db->f("idarea")][$this->db->f("idaction")][$this->db->f("idcat")] = $this->db->f("idcat"); + } + } //end if + } //end for + return $flg; + } //end if + return true; + } + + function showareas($mainarea) { + + global $area_tree, $sess, $perm, $cfg; + + if (!is_object($this->db)) { + $this->db = new DB_Contenido; + } + + $mainarea = $this->getIDForArea($mainarea); + + //if $area_tree for this area is not register + if (!isset($area_tree[$mainarea])) { + $sess->register("area_tree"); + + // parent_id uses the name not the idarea + $sql = "SELECT + name + FROM + " . $cfg["tab"]["area"] . " + WHERE + idarea='$mainarea'"; + + $this->db->query($sql); + $this->db->next_record(); + $name = $this->db->f("name"); + + //check which subareas are there and write them in the array + $sql = "SELECT + idarea + FROM + " . $cfg["tab"]["area"] . " + WHERE + parent_id='$name' OR + idarea='$mainarea'"; + + $this->db->query($sql); + $area_tree[$mainarea] = array(); + while ($this->db->next_record()) { + $area_tree[$mainarea][] = $this->db->f("idarea"); + } + } + return $mainarea; + } + +} diff --git a/branches/php7/conlib/prepend.php b/branches/php7/conlib/prepend.php new file mode 100644 index 0000000..a14d20c --- /dev/null +++ b/branches/php7/conlib/prepend.php @@ -0,0 +1,69 @@ + + * @license http://www.contenido.org/license/LIZENZ.txt + * @link http://www.4fb.de + * @link http://www.contenido.org + * + * + * + * {@internal + * created 2000-01-01 + * modified 2008-07-04, bilal arslan, added security fix + * modified 2009-10-29, Murat Purc, automatic loading of configured database driver + * modified 2011-03-21, Murat Purc, inclusion of ct_session.inc + * + * $Id: prepend.php 67 2012-05-09 13:28:03Z oldperl $: + * }} + * + */ + + +if (!defined('CON_FRAMEWORK')) { + die('Illegal call'); +} + +$_PHPLIB = array(); +$_PHPLIB['libdir'] = str_replace ('\\', '/', dirname(__FILE__) . '/'); + +global $cfg; + +require($_PHPLIB['libdir'] . 'db_sql_abstract.inc'); + +// include/require database driver +$dbDriverFileName = 'db_' . $cfg['database_extension'] . '.inc'; +if (is_file($_PHPLIB['libdir'] . $dbDriverFileName)) { + require_once($_PHPLIB['libdir'] . $dbDriverFileName); +} else { + die('Invalid database extension: ' . $cfg['database_extension']); +} +unset($dbDriverFileName); + +require_once($_PHPLIB['libdir'] . 'ct_sql.inc'); // Data storage container: database +require_once($_PHPLIB['libdir'] . 'ct_file.inc'); // Data storage container: file +require_once($_PHPLIB['libdir'] . 'ct_shm.inc'); // Data storage container: memory +require_once($_PHPLIB['libdir'] . 'ct_session.inc');// Data storage container: memory +require_once($_PHPLIB['libdir'] . 'ct_null.inc'); // Data storage container: null - + // no session container - Contenido does not work + +require_once($_PHPLIB['libdir'] . 'session.inc'); // Required for everything below. +require_once($_PHPLIB['libdir'] . 'auth.inc'); // Disable this, if you are not using authentication. +require_once($_PHPLIB['libdir'] . 'perm.inc'); // Disable this, if you are not using permission checks. + +// Additional require statements go before this line + +require_once($_PHPLIB['libdir'] . 'local.php'); // Required, contains your local configuration. + +require_once($_PHPLIB['libdir'] . 'page.inc'); // Required, contains the page management functions. diff --git a/branches/php7/conlib/session.inc b/branches/php7/conlib/session.inc new file mode 100644 index 0000000..05dc56e --- /dev/null +++ b/branches/php7/conlib/session.inc @@ -0,0 +1,536 @@ + + * @copyright (c) 2014, ConLite Team + * @link http://conlite.org ConLite Portal + * + * $Id:$ + */ + +/** + * @package ContenidoBackendArea + * @version 1.1.1.2 + * @author Boris Erdmann, Kristian Koehntopp + * @copyright four for business AG + * @license http://www.contenido.org/license/LIZENZ.txt + * @link http://www.4fb.de + * @link http://www.contenido.org + */ + +if(!defined('CON_FRAMEWORK')) {die('Illegal call');} + +/** + * old session class, now only extends new cSession + * + * @deprecated since version 2.0 + */ +class Session extends cSession { + +} + + +class cSession { + + var $classname = "Session"; ## Needed for object serialization. + ## Define the parameters of your session by either overwriting + ## these values or by subclassing session (recommended). + var $magic = ""; ## Some string you should change. + var $mode = "cookie"; ## We propagate session IDs with cookies + var $fallback_mode; ## If this doesn't work, fall back... + var $lifetime = 0; ## 0 = do session cookies, else minutes + var $cookie_domain = ""; ## If set, the domain for which the + ## session cookie is set. + var $gc_time = 1440; ## Purge all session data older than 1440 minutes. + var $gc_probability = 5; ## Garbage collect probability in percent + var $auto_init = ""; ## Name of the autoinit-File, if any. + var $secure_auto_init = 1; ## Set to 0 only, if all pages call + ## page_close() guaranteed. + var $allowcache = "no"; ## "passive", "no", "private" or "public" + var $allowcache_expire = 1440; ## If you allowcache, data expires in this + ## many minutes. + var $that_class = ""; ## Name of data storage container + ## + ## End of parameters. + ## + var $name; ## Session name + var $id; ## Unique Session ID + var $that; + var $pt = array(); ## This Array contains the registered things + var $in = 0; ## Marker: Did we already include the autoinit file? + var $expires; ## Expire date + var $_expires; + + ## register($things): + ## + ## call this function to register the things that should become persistent + + function register($things) { + $things = explode(",", $things); + reset($things); + while (list(, $thing) = each($things)) { + $thing = trim($thing); + if ($thing) { + $this->pt[$thing] = true; + } + } + } + + function setExpires($time) { + $this->_expires = $time; + } + + function is_registered($name) { + if (isset($this->pt[$name]) && $this->pt[$name] == true) + return true; + return false; + } + + function unregister($things) { + $things = explode(",", $things); + reset($things); + while (list(, $thing) = each($things)) { + $thing = trim($thing); + if ($thing) { + unset($this->pt[$thing]); + } + } + } + + ## get_id(): + ## + ## Propagate the session id according to mode and lifetime. + ## Will create a new id if necessary. To take over abandoned sessions, + ## one may provide the new session id as a parameter (not recommended). + + function get_id($id = "") { + global $_COOKIE, $_GET, $_POST, $QUERY_STRING; + $newid = true; + + $this->name = $this->cookiename == "" ? $this->classname : $this->cookiename; + + if ("" == $id) { + $newid = false; + switch ($this->mode) { + case "get": + $id = isset($_GET[$this->name]) ? + $_GET[$this->name] : + ( isset($_POST[$this->name]) ? + $_POST[$this->name] : + ""); + break; + case "cookie": + $id = isset($_COOKIE[$this->name]) ? + $_COOKIE[$this->name] : ""; + break; + default: + die("This has not been coded yet."); + break; + } + } + + if ("" == $id) { + $newid = true; + $id = $this->that->ac_newid(md5(uniqid($this->magic)), $this->name); + } + + switch ($this->mode) { + case "cookie": + if ($newid && ( 0 == $this->lifetime )) { + SetCookie($this->name, $id, 0, "/", $this->cookie_domain); + } + if (0 < $this->lifetime) { + SetCookie($this->name, $id, time() + $this->lifetime * 60, "/", $this->cookie_domain); + } + + // Remove session ID info from QUERY String - it is in cookie + if (isset($QUERY_STRING) && ("" != $QUERY_STRING)) { + $QUERY_STRING = preg_replace( + "/(^|&)" . quotemeta(urlencode($this->name)) . "=" . $id . "(&|$)/", "\\1", $QUERY_STRING); + } + break; + case "get": + if (isset($QUERY_STRING) && ("" != $QUERY_STRING)) { + $QUERY_STRING = preg_replace( + "/(^|&)" . quotemeta(urlencode($this->name)) . "=" . $id . "(&|$)/", "\\1", $QUERY_STRING); + } + break; + default: + ; + break; + } + $this->id = $id; + } + + ## put_id(): + ## + ## Stop using the current session id (unset cookie, ...) and + ## abandon a session. + + function put_id() { + global $_COOKIE; + + switch ($this->mode) { + case "cookie": + $this->name = $this->cookiename == "" ? $this->classname : $this->cookiename; + SetCookie($this->name, "", 0, "/", $this->cookie_domain); + $_COOKIE[$this->name] = ""; + break; + + default: + // do nothing. We don't need to die for modes other than cookie here. + break; + } + } + + ## delete(): + ## + ## Delete the current session record and put the session id. + + function delete() { + $this->that->ac_delete($this->id, $this->name); + $this->put_id(); + } + + ## url($url): + ## + ## Helper function: returns $url concatenated with the current + ## session $id. + + function url($url) { + // Remove existing session info from url + $url = preg_replace( + "/([&?])" . quotemeta(urlencode($this->name)) . "=" . $this->id . "(&|$)/", "\\1", $url); + + // Remove trailing ?/& if needed + $url = preg_replace("/[&?]+$/", "", $url); + + switch ($this->mode) { + case "get": + $url .= ( strpos($url, "?") != false ? "&" : "?" ) . + urlencode($this->name) . "=" . $this->id; + break; + default: + ; + break; + } + + // Encode naughty characters in the URL + $url = str_replace(array("<", ">", " ", "\"", "'"), array("%3C", "%3E", "+", "%22", "%27"), $url); + return $url; + } + + function purl($url) { + print $this->url($url); + } + + /** + * + * @param array $aParam + * @return string + */ + function self_url($aParam = array()) { + $sURI = $_SERVER["PHP_SELF"]; + parse_str($_SERVER["QUERY_STRING"], $aQuery); + $aQuery = array_merge($aQuery, $aParam); + $sQuery = http_build_query($aQuery,'','&'); + + return $this->url($_SERVER["PHP_SELF"] . "?" . $sQuery); + } + + function pself_url() { + print $this->self_url(); + } + + function hidden_session($mode = 0) { + if ($mode) { + return sprintf("\n", $this->name, $this->id); + } else { + printf("\n", $this->name, $this->id); + } + } + + function add_query($qarray) { + global $PHP_SELF; + global $QUERY_STRING; + + if ((isset($QUERY_STRING) && ("" != $QUERY_STRING)) || ($this->mode == "get")) { + $sep_char = "&"; + } else { + $sep_char = "?"; + } + + $qstring = ""; + while (list($k, $v) = each($qarray)) { + $qstring .= $sep_char . urlencode($k) . "=" . urlencode($v); + $sep_char = "&"; + } + + return $qstring; + } + + function padd_query($qarray) { + print $this->add_query($qarray); + } + + ## serialize($var,&$str): + ## + ## appends a serialized representation of $$var + ## at the end of $str. + ## + ## To be able to serialize an object, the object must implement + ## a variable $classname (containing the name of the class as string) + ## and a variable $persistent_slots (containing the names of the slots + ## to be saved as an array of strings). + + function serialize($var, &$str) { + static $t, $l, $k; + + ## Determine the type of $$var + eval("\$t = gettype(\$$var);"); + switch ($t) { + + case "array": + ## $$var is an array. Enumerate the elements and serialize them. + eval("reset(\$$var); \$l = gettype(list(\$k)=each(\$$var));"); + $str .= "\$$var = array(); "; + while ("array" == $l) { + ## Structural recursion + $this->serialize($var . "['" . preg_replace("/([\\'])/", "\\\\1", $k) . "']", $str); + eval("\$l = gettype(list(\$k)=each(\$$var));"); + } + + break; + case "object": + ## $$var is an object. Enumerate the slots and serialize them. + eval("\$k = \$${var}->classname; \$l = reset(\$${var}->persistent_slots);"); + $str.="\$$var = new $k; "; + while ($l) { + ## Structural recursion. + $this->serialize($var . "->" . $l, $str); + eval("\$l = next(\$${var}->persistent_slots);"); + } + + break; + default: + ## $$var is an atom. Extract it to $l, then generate code. + eval("\$l = \$$var;"); + $str.="\$$var = '" . preg_replace("/([\\'])/", "\\\\1", $l) . "'; "; + break; + } + } + + function get_lock() { + $this->that->ac_get_lock(); + } + + function release_lock() { + $this->that->ac_release_lock(); + } + + ## freeze(): + ## + ## freezes all registered things ( scalar variables, arrays, objects ) into + ## a database table + + function freeze() { + $str = ""; +//print "DBG:
"; var_dump($this->pt); print "
\n"; + $this->serialize("this->in", $str); + $this->serialize("this->pt", $str); + + reset($this->pt); + while (list($thing) = each($this->pt)) { + $thing = trim($thing); + if ($thing && isset($GLOBALS[$thing])) { + $this->serialize("GLOBALS['" . $thing . "']", $str); + } + } +//return; + $r = $this->that->ac_store($this->id, $this->name, $str); + $this->release_lock(); + + if (!$r) + $this->that->ac_halt("Session: freeze() failed."); + } + + ## thaw: + ## + ## Reload frozen variables from the database and microwave them. + + function thaw() { + $this->get_lock(); + + $vals = $this->that->ac_get_value($this->id, $this->name); + eval(sprintf(";%s", $vals)); + } + + ## + ## Variable precedence functions + ## + + function reimport_get_vars() { + $this->reimport_any_vars("_GET"); + } + + function reimport_post_vars() { + $this->reimport_any_vars("_POST"); + } + + function reimport_cookie_vars() { + $this->reimport_any_vars("HTTP_COOKIE_VARS"); + } + + function reimport_any_vars($arrayname) { + global $$arrayname; + + if (!is_array($$arrayname)) + return; + + reset($$arrayname); + while (list($key, $val) = each($$arrayname)) { + $GLOBALS[$key] = $val; + } + } + + ## + ## All this is support infrastructure for the start() method + ## + + function set_container() { + $name = $this->that_class; + $this->that = new $name; + + $this->that->ac_start(); + } + + function set_tokenname() { + $this->name = $this->cookiename == "" ? $this->classname : $this->cookiename; + } + + function release_token($sid = "") { + global $_COOKIE, $_POST, $_GET, + $HTTP_HOST, $HTTPS; + + if (isset($this->fallback_mode) && ("get" == $this->fallback_mode) && ("cookie" == $this->mode) && (!isset($_COOKIE[$this->name]))) { + + // Looks like no cookie here - check GET/POST params + if (isset($_GET[$this->name]) || isset($_POST[$this->name])) { + // Session info passed via GET/POST - go to fallback_mode + $this->mode = $this->fallback_mode; + } else { + // It seems to be the first load of this page - + // no cookie and no GET/POST params + // Generate session ID and setup cookie. + $this->get_id($sid); + + // Next line is to generate correct self_url() later + $this->mode = $this->fallback_mode; + + if (isset($HTTPS) && $HTTPS == 'on') { + ## You will need to fix suexec as well, if you + ## use Apache and CGI PHP + $PROTOCOL = 'https'; + } else { + $PROTOCOL = 'http'; + } + header("Status: 302 Moved Temporarily"); + header("Location: " . $PROTOCOL . "://" . $HTTP_HOST . $this->self_url()); + exit; + } + } + } + + function put_headers() { + # Allowing a limited amount of caching, as suggested by + # Padraic Renaghan on phplib@lists.netuse.de. + # + # Note that in HTTP/1.1 the Cache-Control headers override the Expires + # headers and HTTP/1.0 ignores headers it does not recognize (e.g, + # Cache-Control). Mulitple Cache-Control directives are split into + # mulitple headers to better support MSIE 4.x. + # + # Added pre- and post-check for MSIE 5.x as suggested by R.C.Winters, + # see http://msdn.microsoft.com/workshop/author/perf/perftips.asp#Use%20Cache-Control%20Extensions + # for details + switch ($this->allowcache) { + + case "passive": + $mod_gmt = gmdate("D, d M Y H:i:s", getlastmod()) . " GMT"; + header("Last-Modified: " . $mod_gmt); + # possibly ie5 needs the pre-check line. This needs testing. + header("Cache-Control: post-check=0, pre-check=0"); + break; + + case "public": + $exp_gmt = gmdate("D, d M Y H:i:s", time() + $this->allowcache_expire * 60) . " GMT"; + $mod_gmt = gmdate("D, d M Y H:i:s", getlastmod()) . " GMT"; + header("Expires: " . $exp_gmt); + header("Last-Modified: " . $mod_gmt); + header("Cache-Control: public"); + header("Cache-Control: max-age=" . $this->allowcache_expire * 60); + break; + + case "private": + $mod_gmt = gmdate("D, d M Y H:i:s", getlastmod()) . " GMT"; + header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); + header("Last-Modified: " . $mod_gmt); + header("Cache-Control: private"); + header("Cache-Control: max-age=" . $this->allowcache_expire * 60); + header("Cache-Control: pre-check=" . $this->allowcache_expire * 60); + break; + + default: + $rand = md5(mt_rand()); + $mod_gmt = gmdate("D, d M Y H:i:s", time() - 3600) . " GMT"; + + if ($this->_expires > 0) { + header("Expires: " . gmdate("D, d M Y H:i:s", $this->_expires) . " GMT"); + } else { + header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); + } + + header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); + header("Cache-Control:no-store, no-cache, must-revalidate"); + header("Cache-Control: post-check=0, pre-check=0", false); + header("Cache-control: private, no-cache"); + header("Pragma: no-cache"); + header("ETag: $rand"); + + break; + } + } + + ## + ## Garbage collection + ## + ## Destroy all session data older than this + ## + + function gc() { + srand(time()); + if ((rand() % 100) < $this->gc_probability) { + $this->that->ac_gc($this->gc_time, $this->name); + } + } + + ## + ## Initialization + ## + + function start($sid = "") { + $this->set_container(); + $this->set_tokenname(); + $this->put_headers(); + $this->release_token($sid); + $this->get_id($sid); + $this->thaw(); + $this->gc(); + $this->setExpires(0); + } + +}