Hallo, lieber Forumbenutzer. Wir haben in letzter Zeit festgestellt, dass die Kommunikation via Slack viel schneller und zielführender ist als ein Beitrag im Forum. Aufgrund der neuen Möglichkeiten der Kommunikation ist das Forum ein wenig eingeschlafen und weniger Nutzer benutzen das Forum aktiv (trotzdem lohnt es sich evtl. hier nach Lösungen zu suchen oder seine Frage zu stellen).

Wir empfehlen, für deine Fragen/Probleme aktuell (zusätzlich) Slack zu nutzen. Dort sind viele kompetente Benutzer aktiv und beantworten jegliche Fragen, gerne auch von REDAXO-Anfängern! Slack wird von uns sehr intensiv und meistens "rund um die Uhr" benutzt :-)
Selbst einladen kannst Du dich hier: http://redaxo.org/slack/
jimhein
Beiträge: 69
Registriert: 3. Sep 2007, 11:00
Wohnort: Berlin

Redaxo 4 und PHP 7

17. Feb 2016, 13:00

Hallo zusammen,

ich Frage mich gerade wie es mit der PHP7 Unterstützung von Redaxo 4.6 aussieht.
Die Installation scheitert an
Die benötigte PHP-Extension mysql wurde nicht gefunden!
Hintergrund: Ich plane gerade eine umfangreichere Seite umzusetzen, die auch eine Suche benötigt. Somit kommt die tolle 5er Version noch nicht in Frage. Beim Hoster (Hosteurope) steht nun, das PHP 5.6 nur noch bis Mitte 2017 läuft. Wenn es andere Hoster auch so eilig haben wäre ein Einsatz von Redaxo 4.6 nicht mehr wirklich sinnvoll, da man schon bald alles wieder umstricken muß.

Was meint Ihr, bin ich da zu pessimistisch oder lässt sich Redaxo 4.6 'einfach' PHP7 tauglich machen?

Viele Grüße
Ingo

Phoebus Ryan
Beiträge: 164
Registriert: 27. Okt 2014, 15:57

Re: Redaxo 4 und PHP 7

17. Feb 2016, 14:10

Ich glaube nicht, dass dies ohne weiteres möglich ist. Die PHP-Extension mysql ist in PHP 5.6 deprecated und in 7.0 entfernt. Ich würde unbedingt davon abraten Redaxo 4 für weitere Projekte zu nutzen, da wie du schon festgestellt hast, die Hoster PHP 5 abschalten werden. Wenn du Glück hast, findest du einen Hoster, der es noch bis Mitte 2018 anbietet aber viel länger wird es nicht passieren.

Wenn du schon umfangreichere Seiten umsetzen möchtest, wäre Redaxo 5 sowieso besser wegen dem Caching etc. Eine Suchfunktion ist soweit ich weiss bereits in Entwicklung; anderenfalls kann man diese auch erstmal selbst bauen und später durch eine Addon ersetzen.

In Redaxo 5 ist übrigens alles updatefähig. Alleine das wäre schon ein Grund auf Redaxo 5 zu setzen.

Benutzeravatar
RexDude
Beiträge: 2543
Registriert: 22. Apr 2010, 11:24

Re: Redaxo 4 und PHP 7

17. Feb 2016, 14:22

@Ingo: Ich habe das gleiche Problem wie du (+ noch paar weitere) mit R5 und deshalb überlege ich mir ein R4 Fork zu ziehen. Als ersten Schritt werde ich daher testen wie problematisch/aufwändig man von der mysql auf die mysqli extension migrieren kann und was es sonst noch braucht um R4 auf PHP7 zu heben. Falls das ne Option für dich ist sag mir bescheid, ich halte dich dann auf dem laufenden.

Benutzeravatar
Gregor.Harlan
Entwickler
Beiträge: 1130
Registriert: 4. Jun 2007, 10:35
Wohnort: Frankfurt am Main

Re: Redaxo 4 und PHP 7

17. Feb 2016, 14:59

Soweit ich weiß, ist die mysql-Extension das einzige Problem im Core und den Core-Addons. Bei den "Fremd"-Addons kann das natürlich auch anders aussehen.

Sollte es tatsächlich einigermaßen unproblematisch sein, mysql durch mysqli zu ersetzten und sollten die Hoster tatsächlich zeitnah PHP5 nicht mehr anbieten, könnte ich mir auch vorstellen, dass wir noch eine Version rausbringen (oder nur eine aktualisierte rex_sql-Klasse).

@Rudi: Falls du das mal austestet, würde ich mich sehr freuen!

Falls die Hoster tatsächlich schon 2017 damit anfangen, PHP 5 abzuschalten, ist das Thema jedenfalls natürlich nicht unwichtig!

PS: Es wird bis Ende 2016 noch normale Bugfixes für PHP 5.6 geben, und bis Ende 2018 Security Fixes.
Friends Of REDAXO: Gemeinsame REDAXO-Entwicklung!

Benutzeravatar
RexDude
Beiträge: 2543
Registriert: 22. Apr 2010, 11:24

Re: Redaxo 4 und PHP 7

17. Feb 2016, 15:11

Ich bin dran Gregor :D

Benutzeravatar
RexDude
Beiträge: 2543
Registriert: 22. Apr 2010, 11:24

Re: Redaxo 4 und PHP 7

18. Feb 2016, 02:27

Der geeeeht!!! :D

Ein Problem gibts aktuell aber noch: Im Frontend wie Backend werden die Sonderzeichen wie z.B. Umlaute nur kryptisch ausgegeben. Das setzen von utf8_encode() in Zeile 38 hilft, allerdings nur bedingt. Umlaute werden dann richtig dargestellt aber Anfürhungszeichen immer noch nicht. Jemand ne Idee?

class.rex_sql.inc.php
(Konstanten muss ich dann auch noch ersetzen bzw. auch in Addons etc.)

Code: Alles auswählen

<?php

/**
 * Klasse zur Verbindung und Interatkion mit der Datenbank
 * @version svn:$Id$
 */

// Hinweis: @ wurden aktuell auskommentiert

if (!extension_loaded('mysql') ){
    define('MYSQL_BOTH',MYSQLI_BOTH);
    define('MYSQL_NUM',MYSQLI_NUM);
    define('MYSQL_ASSOC',MYSQLI_ASSOC);
}

// wrapper for mysql_result, taken from http://stackoverflow.com/a/31986858 (Thx!)
function mysqli_result($result, $row, $field) {
    $result->data_seek($row);

    // for no table prefix just go ahead and fetch assoc
    if ( strstr($field, ".") === false ) {
        // Fetch result array
        $data = $result->fetch_assoc();

        return $data[$field];
    }

    // workaround for assoc use and overwriting fieldnames like "a.timestamp" and "b.timestamp"
    list($tablename,$fieldname) = explode(".",$field);
    $resultData = $result->fetch_array(MYSQLI_NUM);

    foreach( $result->fetch_fields() as $index => $fieldData ) {
        if ( $fieldData->table == $tablename && $fieldData->name == $fieldname ) {
            return $resultData[$index]; // solution without utf8_encode ???
        }
    }

    return false;
}


class rex_sql
{
    var $values; // Werte von setValue
    var $fieldnames; // Spalten im ResultSet

    var $table; // Tabelle setzen
    var $wherevar; // WHERE Bediengung
    var $query; // letzter Query String
    var $counter; // ResultSet Cursor
    var $rows; // anzahl der treffer
    var $result; // ResultSet
    var $last_insert_id; // zuletzt angelegte auto_increment nummer
    var $debugsql; // debug schalter
    var $identifier; // Datenbankverbindung
    var $DBID; // ID der Verbindung

    var $error; // Fehlertext
    var $errno; // Fehlernummer

    /*private*/ function rex_sql($DBID = 1)
    {
        global $REX;

        $this->debugsql = false;
        $this->selectDB($DBID);

        $this->flush();
    }

    /**
     * Stellt die Verbindung zur Datenbank her
     */
    /*protected*/ function selectDB($DBID)
    {
        global $REX;

        $this->DBID = $DBID;

        if ($REX['DB'][$DBID]['PERSISTENT']) {
            $this->identifier = /*@*/mysqli_connect('p:' . $REX['DB'][$DBID]['HOST'], $REX['DB'][$DBID]['LOGIN'], $REX['DB'][$DBID]['PSW']);
        } else {
            $this->identifier = /*@*/mysqli_connect($REX['DB'][$DBID]['HOST'], $REX['DB'][$DBID]['LOGIN'], $REX['DB'][$DBID]['PSW']);
        }

        if (!/*@*/mysqli_select_db($this->identifier, $REX['DB'][$DBID]['NAME'])) {
            echo "<font style='color:red; font-family:verdana,arial; font-size:11px;'>Class SQL 1.1 | Database down. | Please contact <a href=mailto:" . $REX['ERROR_EMAIL'] . '>' . $REX['ERROR_EMAIL'] . "</a>\n | Thank you!\n</font>";
            exit;
        }

        if (!isset($REX['DB'][$DBID]['IDENTIFIER']) || $REX['DB'][$DBID]['IDENTIFIER'] != $this->identifier) {
            $REX['DB'][$DBID]['IDENTIFIER'] = $this->identifier;

            // ggf. Strict Mode abschalten
            $this->setQuery('SET SQL_MODE=""');

            // MySQL Version bestimmen
            $res = $this->getArray('SELECT VERSION() as VERSION');
            if (preg_match('/([0-9]+\.([0-9\.])+)/', $res[0]['VERSION'], $matches)) {
                $version = $matches[1];
                if ($DBID == 1) {
                    $REX['MYSQL_VERSION'] = $version;
                }
            } else {
                exit('Could not identifiy MySQL Version!');
            }

            // connection auf UTF8 trimmen
            if (function_exists('mysqli_set_charset') and version_compare($version, '5.0.7', '>=')) {
                mysqli_set_charset($this->identifier, 'utf8');
            } else {
                $this->setQuery('SET NAMES utf8');
            }
        }
    }

    /**
     * Gibt die DatenbankId der Abfrage (SQL) zurück,
     * oder false wenn die Abfrage keine DBID enthält
     *
     * @param $query Abfrage
     */
    static /*protected*/ function getQueryDBID($qry)
    {
        $qry = trim($qry);

        if (preg_match('/\(DB([1-9]){1}\)/i', $qry, $matches)) {
            return $matches[1];
        }

        return false;
    }

    /**
     * Entfernt die DBID aus einer Abfrage (SQL) und gibt die DBID zurück falls
     * vorhanden, sonst false
     *
     * @param $query Abfrage
     */
    static /*protected*/ function stripQueryDBID(&$qry)
    {
        $qry = trim($qry);

        if (($qryDBID = self::getQueryDBID($qry)) !== false) {
            $qry = substr($qry, 6);
        }

        return $qryDBID;
    }

    /**
     * Gibt den Typ der Abfrage (SQL) zurück,
     * oder false wenn die Abfrage keinen Typ enthält
     *
     * Mögliche Typen:
     * - SELECT
     * - SHOW
     * - UPDATE
     * - INSERT
     * - DELETE
     * - REPLACE
     *
     * @param $query Abfrage
     */
    static /*protected*/ function getQueryType($qry)
    {
        $qry = trim($qry);
        // DBID aus dem Query herausschneiden, falls vorhanden
        self::stripQueryDBID($qry);

        if (preg_match('/^(SELECT|SHOW|UPDATE|INSERT|DELETE|REPLACE)/i', $qry, $matches)) {
            return strtoupper($matches[1]);
        }

        return false;
    }

    /**
     * Setzt eine Abfrage (SQL) ab, wechselt die DBID falls vorhanden
     *
     * @param $query Abfrage
     * @return boolean True wenn die Abfrage erfolgreich war (keine DB-Errors
     * auftreten), sonst false
     */
    /*public*/ function setDBQuery($qry)
    {
        if (($qryDBID = self::stripQueryDBID($qry)) !== false) {
            $this->selectDB($qryDBID);
        }

        return $this->setQuery($qry);
    }

    /**
     * Setzt Debugmodus an/aus
     *
     * @param $debug Debug TRUE/FALSE
     */
    /*public*/ function setDebug($debug = true)
    {
        $this->debugsql = $debug;
    }

    /**
     * Setzt eine Abfrage (SQL) ab
     *
     * @param $query Abfrage
     * @return boolean True wenn die Abfrage erfolgreich war (keine DB-Errors
     * auftreten), sonst false
     */
    /*public*/ function setQuery($qry)
    {
        // Alle Werte zurücksetzen
        $this->flush();

        $qry = trim($qry);
        $this->query = $qry;
        $this->result = /*@*/ mysqli_query($this->identifier, $qry);

        if ($this->result) {
            if (($qryType = $this->getQueryType($this->query)) !== false) {
                switch ($qryType) {
                    case 'SELECT' :
                    case 'SHOW' :
                    {
                        $this->rows = mysqli_num_rows($this->result);
                        break;
                    }
                    case 'REPLACE' :
                    case 'DELETE' :
                    case 'UPDATE' :
                    {
                        $this->rows = mysqli_affected_rows($this->identifier);
                        break;
                    }
                    case 'INSERT' :
                    {
                        $this->rows = mysqli_affected_rows($this->identifier);
                        $this->last_insert_id = mysqli_insert_id($this->identifier);
                        break;
                    }
                }
            }
        } else {
            $this->error = mysqli_error($this->identifier);
            $this->errno = mysqli_errno($this->identifier);
            
            rex_register_extension_point('REX_SQL_ERROR', $this);
        }

        if ($this->debugsql || $this->error != '') {
            $this->printError($qry);
        }

        return $this->getError() === '';
    }

    /**
     * Setzt den Tabellennamen
     *
     * @param $table Tabellenname
     */
    /*public*/ function setTable($table)
    {
        $this->table = $table;
    }

    /**
     * Setzt den Wert eine Spalte
     *
     * @param string $feldname Spaltenname
     * @param string $wert Wert
     */
    /*public*/ function setValue($feldname, $wert)
    {
        $this->values[$feldname] = $wert;
    }

    /**
     * Setzt ein Array von Werten zugleich
     *
     * @param $valueArray Ein Array von Werten
     * @param $wert Wert
     */
    /*public*/ function setValues($valueArray)
    {
        if (is_array($valueArray)) {
            foreach ($valueArray as $name => $value) {
                $this->setValue($name, $value);
            }
            return true;
        }
        return false;
    }

    /**
     * Prüft den Wert einer Spalte der aktuellen Zeile ob ein Wert enthalten ist
     * @param $feld Spaltenname des zu prüfenden Feldes
     * @param $prop Wert, der enthalten sein soll
     */
    /*protected*/ function isValueOf($feld, $prop)
    {
        if ($prop == '') {
            return true;
        } else {
            return strpos($this->getValue($feld), $prop) !== false;
        }
    }

    /**
     * Setzt die WHERE Bedienung der Abfrage
     */
    /*public*/ function setWhere($where)
    {
        $this->wherevar = "WHERE $where";
    }

    /**
     * Gibt den Wert einer Spalte im ResultSet zurück
     * @param $value Name der Spalte
     * @param [$row] Zeile aus dem ResultSet
     */
    /*public*/ function getValue($feldname, $row = null)
    {
        if (isset($this->values[$feldname])) {
            return $this->values[$feldname];
        }

        $_row = $this->counter;
        if (is_int($row)) {
            $_row = $row;
        }

        $res = mysqli_result($this->result, $_row, $feldname);

        if ($res === false) {
            $sendWarnings = (error_reporting() & E_WARNING) == E_WARNING;

            if ($sendWarnings && function_exists('debug_backtrace')) {
                $trace = debug_backtrace();
                $loc = $trace[0];
                echo '<b>Warning</b>:  mysqli_result(' . $feldname . '): Initial error found in file <b>' . $loc['file'] . '</b> on line <b>' . $loc['line'] . '</b><br />';
            }
        }
        return $res;
    }

    /**
     * Gibt den Wert der aktuellen Zeile im ResultSet zurueck und
     * bewegt den internen Zeiger auf die naechste Zeile
     */
    /*public*/ function getRow($fetch_type = MYSQL_ASSOC)
    {
        return mysqli_fetch_array($this->result, $fetch_type);
    }

    /**
     * Prüft, ob eine Spalte im Resultset vorhanden ist
     * @param $value Name der Spalte
     */
    /*public*/ function hasValue($feldname)
    {
        return in_array($feldname, $this->getFieldnames());
    }

    /**
     * Prüft, ob das Feld mit dem Namen $feldname Null ist.
     *
     * Falls das Feld nicht vorhanden ist,
     * wird Null zurückgegeben, sonst True/False
     */
    /*public*/ function isNull($feldname)
    {
        if ($this->hasValue($feldname)) {
            return $this->getValue($feldname) === null;
        }

        return null;
    }

    /**
     * Gibt die Anzahl der Zeilen zurück
     */
    /*public*/ function getRows()
    {
        return $this->rows;
    }

    /**
     * Gibt die Zeilennummer zurück, auf der sich gerade der
     * interne Zähler befindet
     *
     * @deprecated since version 4.3.0
     */
    /*public*/ function getCounter()
    {
        return $this->counter;
    }

    /**
     * Gibt die Anzahl der Felder/Spalten zurück
     */
    /*public*/ function getFields()
    {
        return mysqli_num_fields($this->result);
    }

    /**
     * Baut den SET bestandteil mit der
     * verfügbaren values zusammen und gibt diesen zurück
     *
     * @see setValue
     */
    /*protected*/ function buildSetQuery()
    {
        $qry = '';
        if (is_array($this->values)) {
            foreach ($this->values as $fld_name => $value) {
                if ($qry != '') {
                    $qry .= ',';
                }

                // Bei <tabelle>.<feld> Notation '.' ersetzen, da sonst `<tabelle>.<feld>` entsteht
                if (strpos($fld_name, '.') !== false) {
                    $fld_name = str_replace('.', '`.`', $fld_name);
                }

                if ($value === null) {
                    $qry .= '`' . $fld_name . '`= NULL';
                } else {
                    $qry .= '`' . $fld_name . '`=\'' . $value . '\'';
                }

// Da Werte via POST/GET schon mit magic_quotes escaped werden,
// brauchen wir hier nicht mehr escapen
//        $qry .= '`' . $fld_name . '`=' . $this->escape($value);
            }
        }

        return $qry;
    }

    /**
     * Setzt eine Select-Anweisung auf die angegebene Tabelle
     * mit den WHERE Parametern ab
     *
     * @see #setTable()
     * @see #setWhere()
     */
    /*public*/ function select($fields)
    {
        return $this->setQuery('SELECT ' . $fields . ' FROM `' . $this->table . '` ' . $this->wherevar);
    }

    /**
     * Setzt eine Update-Anweisung auf die angegebene Tabelle
     * mit den angegebenen Werten und WHERE Parametern ab
     *
     * @see #setTable()
     * @see #setValue()
     * @see #setWhere()
     */
    /*public*/ function update($successMessage = null)
    {
        return $this->statusQuery('UPDATE `' . $this->table . '` SET ' . $this->buildSetQuery() . ' ' . $this->wherevar, $successMessage);
    }

    /**
     * Setzt eine Insert-Anweisung auf die angegebene Tabelle
     * mit den angegebenen Werten ab
     *
     * @see #setTable()
     * @see #setValue()
     */
    /*public*/ function insert($successMessage = null)
    {
        return $this->statusQuery('INSERT INTO `' . $this->table . '` SET ' . $this->buildSetQuery(), $successMessage);
    }

    /**
     * Setzt eine Replace-Anweisung auf die angegebene Tabelle
     * mit den angegebenen Werten ab
     *
     * @see #setTable()
     * @see #setValue()
     * @see #setWhere()
     */
    /*public*/ function replace($successMessage = null)
    {
        return $this->statusQuery('REPLACE INTO `' . $this->table . '` SET ' . $this->buildSetQuery() . ' ' . $this->wherevar, $successMessage);
    }

    /**
     * Setzt eine Delete-Anweisung auf die angegebene Tabelle
     * mit den angegebenen WHERE Parametern ab
     *
     * @see #setTable()
     * @see #setWhere()
     */
    /*public*/ function delete($successMessage = null)
    {
        return $this->statusQuery('DELETE FROM `' . $this->table . '` ' . $this->wherevar, $successMessage);
    }

    /**
     * Setzt den Query $query ab.
     *
     * Wenn die Variable $successMessage gefüllt ist, dann wird diese bei
     * erfolgreichem absetzen von $query zurückgegeben, sonst die MySQL
     * Fehlermeldung
     *
     * Wenn die Variable $successMessage nicht gefüllt ist, verhält sich diese
     * Methode genauso wie setQuery()
     *
     * Beispiel:
     *
     * <code>
     * $sql = rex_sql::factory();
     * $message = $sql->statusQuery(
     *    'INSERT  INTO abc SET a="ab"',
     *    'Datensatz  erfolgreich eingefügt');
     * </code>
     *
     *  anstatt von
     *
     * <code>
     * $sql = rex_sql::factory();
     * if($sql->setQuery('INSERT INTO abc SET a="ab"'))
     *   $message  = 'Datensatz erfolgreich eingefügt');
     * else
     *   $message  = $sql- >getError();
     * </code>
     */
    /*public*/ function statusQuery($query, $successMessage = null)
    {
        $res = $this->setQuery($query);
        if ($successMessage) {
            if ($res) {
                return $successMessage;
            } else {
                return $this->getError();
            }
        }
        return $res;
    }

    /**
     * Stellt alle Werte auf den Ursprungszustand zurück
     */
    /*public*/ function flush()
    {
        $this->flushValues();
        $this->fieldnames = array ();

        $this->table = '';
        $this->wherevar = '';
        $this->query = '';
        $this->counter = 0;
        $this->rows = 0;
        $this->result = '';
        $this->last_insert_id = '';
        $this->error = '';
        $this->errno = '';
    }

    /**
     * Stellt alle Values, die mit setValue() gesetzt wurden, zurück
     *
     * @see #setValue(), #getValue()
     */
    /*public*/ function flushValues()
    {
        $this->values = array ();
    }


    /**
     * Setzt den Cursor des Resultsets auf die nächst niedrigere Stelle
     */
    /*public*/ function previous()
    {
        $this->counter--;
    }

    /**
     * Setzt den Cursor des Resultsets auf die nächst höhere Stelle
     */
    /*public*/ function next()
    {
        $this->counter++;
    }

    /*
     * Prüft ob das Resultset weitere Datensätze enthält
     */
    /*public*/ function hasNext()
    {
        return $this->counter != $this->rows;
    }

    /**
     * Setzt den Cursor des Resultsets zurück zum Anfang
     */
    /*public*/ function reset()
    {
        $this->counter = 0;
    }

    /**
     * Setzt den Cursor des Resultsets aufs Ende
     */
    /*public*/ function last()
    {
        $this->counter = ($this->rows - 1);
    }

    /**
     * Gibt die letzte InsertId zurück
     */
    /*public*/ function getLastId()
    {
        return $this->last_insert_id;
    }

    /**
     * Lädt das komplette Resultset in ein Array und gibt dieses zurück und
     * wechselt die DBID falls vorhanden
     *
     * @param string $sql        Abfrage
     * @param string $fetch_type Default: MYSQL_ASSOC; weitere: MYSQL_NUM, MYSQL_BOTH
     * @return array
     */
    /*public*/ function getDBArray($sql = '', $fetch_type = MYSQL_ASSOC)
    {
        return $this->_getArray($sql, $fetch_type, 'DBQuery');
    }

    /**
     * Lädt das komplette Resultset in ein Array und gibt dieses zurück
     *
     * @param string $sql        Abfrage
     * @param string $fetch_type Default: MYSQL_ASSOC; weitere: MYSQL_NUM, MYSQL_BOTH
     * @return array
     */
    /*public*/ function getArray($sql = '', $fetch_type = MYSQL_ASSOC)
    {
        return $this->_getArray($sql, $fetch_type);
    }

    /**
     * Hilfsfunktion
     *
     * @see getArray()
     * @see getDBArray()
     * @param string $sql        Abfrage
     * @param string $fetch_type MYSQL_ASSOC, MYSQL_NUM oder MYSQL_BOTH
     * @param string $qryType    void oder DBQuery
     * @return array
     */
    /*private*/ function _getArray($sql, $fetch_type, $qryType = 'default')
    {
        if ($sql != '') {
            switch ($qryType) {
                case 'DBQuery': $this->setDBQuery($sql); break;
                default       : $this->setQuery($sql);
            }
        }

        $data = array();
        while ($row = /*@*/ mysqli_fetch_array($this->result, $fetch_type)) {
            $data[] = $row;
        }

        return $data;
    }

    /**
     * Gibt die zuletzt aufgetretene Fehlernummer zurück
     */
    /*public*/ function getErrno()
    {
        return $this->errno;
    }

    /**
     * Gibt den zuletzt aufgetretene Fehlernummer zurück
     */
    /*public*/ function getError()
    {
        return $this->error;
    }

    /**
     * Prüft, ob ein Fehler aufgetreten ist
     */
    /*public*/ function hasError()
    {
        return $this->error != '';
    }

    /**
     * Gibt die letzte Fehlermeldung aus
     */
    /*public*/ function printError($query)
    {
        if ($this->debugsql == true) {
            echo '<hr />' . "\n";
            echo 'Query: ' . nl2br(htmlspecialchars($query)) . "<br />\n";

            if (strlen($this->getRows()) > 0) {
                echo 'Affected Rows: ' . $this->getRows() . "<br />\n";
            }
            if (strlen($this->getError()) > 0) {
                echo 'Error Message: ' . htmlspecialchars($this->getError()) . "<br />\n";
                echo 'Error Code: ' . $this->getErrno() . "<br />\n";
            }
        }
    }

    /**
     * Setzt eine Spalte auf den nächst möglich auto_increment Wert
     * @param $field Name der Spalte
     */
    /*public*/ function setNewId($field)
    {
        // setNewId muss neues sql Objekt verwenden, da sonst bestehende informationen im Objekt überschrieben werden
        $sql = self::factory();
        if ($sql->setQuery('SELECT `' . $field . '` FROM `' . $this->table . '` ORDER BY `' . $field . '` DESC LIMIT 1')) {
            if ($sql->getRows() == 0) {
                $id = 0;
            } else {
                $id = $sql->getValue($field);
            }

            $id++;
            $this->setValue($field, $id);

            return $id;
        }

        return false;
    }

    /**
     * Gibt die Spaltennamen des ResultSets zurück
     */
    /*public*/ function getFieldnames()
    {
        if (empty($this->fieldnames)) {
            for ($i = 0; $i < $this->getFields(); $i++) {
                $this->fieldnames[] = mysqli_fetch_field_direct($this->result, $i)->name;
            }
        }
        return $this->fieldnames;
    }

    /**
     * Escaped den übergebenen Wert für den DB Query
     *
     * @param string $value den zu escapenden Wert
     * @param string $delimiter Delimiter der verwendet wird, wenn es sich bei $value um einen String handelt
     * @param boolean $force Escapen erzwingen, unabhängig davon ob es ein nummerischer Wert ist
     */
    /*public*/ function escape($value, $delimiter = '', $force = false)
    {
        // Quote if not a number or a numeric string
        if ($force || !is_numeric($value)) {
            $value = $delimiter . mysqli_real_escape_string($this->identifier, $value) . $delimiter;
        }
        return $value;
    }

    /**
     * Erstellt das CREATE TABLE Statement um die Tabelle $table
     * der Datenbankverbindung $DBID zu erstellen.
     *
     * @param $table string Name der Tabelle
     * @param $DBID int Id der Datenbankverbindung
     * @return string CREATE TABLE Sql-Statement zu erstsellung der Tabelle
     */
    static /*public*/ function showCreateTable($table, $DBID = 1)
    {

        $sql = self::factory($DBID);
        $create = $sql->getArray("SHOW CREATE TABLE `$table`");
        $create = current($create);
        $create = $create['Create Table'];

        return $create;
    }

    /**
     * Sucht alle Tabellen der Datenbankverbindung $DBID.
     * Falls $tablePrefix gesetzt ist, werden nur dem Prefix entsprechende Tabellen gesucht.
     *
     * @param $DBID int Id der Datenbankverbindung
     * @param $tablePrefix string Zu suchender Tabellennamen-Prefix
     * @return array Ein Array von Tabellennamen
     */
    static /*public*/ function showTables($DBID = 1, $tablePrefix = null)
    {
        $qry = 'SHOW TABLES';
        if ($tablePrefix != null) {
            $tablePrefix = str_replace('_', '\_', $tablePrefix);
            $qry .= ' LIKE "' . $tablePrefix . '%"';
        }

        $sql = self::factory($DBID);
        $tables = $sql->getArray($qry);
        $tables = array_map('reset', $tables);

        return $tables;
    }

    /**
     * Sucht Spalteninformationen der Tabelle $table der Datenbankverbindung $DBID.
     *
     * @param $table string Name der Tabelle
     * @param $DBID int Id der Datenbankverbindung
     * @return array Ein Array das die Metadaten enthält
     */
    static /*public*/ function showColumns($table, $DBID = 1)
    {
        $sql = self::factory($DBID);
        $sql->setQuery('SHOW COLUMNS FROM ' . $table);

        $columns = array();
        for ($i = 0; $i < $sql->getRows(); $i++) {
            $columns [] = array(
                'name' => $sql->getValue('Field'),
                'type' => $sql->getValue('Type'),
                'null' => $sql->getValue('Null'),
                'key' => $sql->getValue('Key'),
                'default' => $sql->getValue('Default'),
                'extra' => $sql->getValue('Extra')
            );
            $sql->next();
        }

        return $columns;
    }

    /**
     * Gibt die Serverversion zurück.
     *
     * Die Versionsinformation ist erst bekannt,
     * nachdem der rex_sql Konstruktor einmalig erfolgreich durchlaufen wurde.
     */
    static /*public*/ function getServerVersion()
    {
        global $REX;
        return $REX['MYSQL_VERSION'];
    }

    /**
     * @param int  $DBID
     * @param string $class
     * @return static
     */
    static /*public*/ function factory($DBID = 1, $class = null)
    {
        // keine spezielle klasse angegeben -> default klasse verwenden?
        if (!$class) {
            // ----- EXTENSION POINT
            $class = rex_register_extension_point('REX_SQL_CLASSNAME', 'rex_sql',
                array(
                    'DBID'      => $DBID
                )
            );
        }

        return new $class($DBID);
    }

    /**
     * Gibt ein SQL Singelton Objekt zurück
     *
     * @deprecated since 4.3.0
     */
    static /*public*/ function getInstance($DBID = 1, $deprecatedSecondParam = null)
    {
        return self::factory($DBID);
    }

    /**
     * Gibt den Speicher wieder frei
     */
    /*public*/ function freeResult()
    {
        if (is_resource($this->result)) {
            mysqli_free_result($this->result);
        }
    }

    /**
     * Prueft die uebergebenen Zugangsdaten auf gueltigkeit und legt ggf. die
     * Datenbank an
     */
    static /*public*/ function checkDbConnection($host, $login, $pw, $dbname, $createDb = false)
    {
        global $I18N;

        $err_msg = true;
        $link = /*@*/ mysqli_connect($host, $login, $pw);
        if (!$link) {
            $err_msg = $I18N->msg('setup_021');
        } else {
            $result = mysqli_query($link, 'SELECT VERSION() AS version');
            $result = mysqli_fetch_array($result, MYSQL_ASSOC);
            if (version_compare($result['version'], '5.0', '<')) {
                $err_msg = $I18N->msg('setup_021_1', $result['version']);
            } elseif (!/*@*/ mysqli_select_db($link, $dbname)) {
                if ($createDb) {
                    mysqli_query($link, 'CREATE DATABASE `' . $dbname . '`');
                    if (mysqli_error($link) != '') {
                        $err_msg = $I18N->msg('setup_022');
                    }
                } else {
                    $err_msg = $I18N->msg('setup_022');
                }
            }
        }

        if ($link) {
            mysqli_close($link);
        }
        return $err_msg;
    }

    /**
     * Schließt die Verbindung zum DB Server
     */
    static /*public*/ function disconnect($DBID = 1)
    {
        global $REX;

        // Alle Connections schließen
        if ($DBID === null) {
            foreach ($REX['DB'] as $DBID => $DBSettings) {
                self::disconnect($DBID);
            }

            return;
        }

        if (!$REX['DB'][$DBID]['PERSISTENT'] &&
             isset($REX['DB'][$DBID]['IDENTIFIER']) &&
             is_resource($REX['DB'][$DBID]['IDENTIFIER'])
        ) {
            $db = self::factory($DBID);

            if (self::isValid($db)) {
                mysqli_close($db->identifier);
            }
        }
    }

    /*public*/ function addGlobalUpdateFields($user = null)
    {
        global $REX;

        if (!$user) {
            $user = $REX['USER']->getValue('login');
        }

        $this->setValue('updatedate', time());
        $this->setValue('updateuser', $user);
    }

    /*public*/ function addGlobalCreateFields($user = null)
    {
        global $REX;

        if (!$user) {
            $user = $REX['USER']->getValue('login');
        }

        $this->setValue('createdate', time());
        $this->setValue('createuser', $user);
    }

    static /*public*/ function isValid($object)
    {
        return is_object($object) && is_a($object, 'rex_sql');
    }
} 

Benutzeravatar
Gregor.Harlan
Entwickler
Beiträge: 1130
Registriert: 4. Jun 2007, 10:35
Wohnort: Frankfurt am Main

Re: Redaxo 4 und PHP 7

18. Feb 2016, 11:53

RexDude hat geschrieben:Der geeeeht!!! :D
Das wollte ich hören! :wink:

Eine Wrapper-Funktion für mysql_real_escape_string wäre sicherlich auch noch sinnvoll.
Friends Of REDAXO: Gemeinsame REDAXO-Entwicklung!

Benutzeravatar
RexDude
Beiträge: 2543
Registriert: 22. Apr 2010, 11:24

Re: Redaxo 4 und PHP 7

18. Feb 2016, 12:12

Eine Wrapper-Funktion für mysql_real_escape_string wäre sicherlich auch noch sinnvoll.
Ja aufjedefall....ist mir auch schon im Code aufgefallen. Hast du da was oder soll ich mal schauen/googlen?

Das utf8 Prob hat sich übrigens verflüchtigt. Kanns nicht mehr reproduzieren.

Dafür tauchen paar deprecated Meldungen auf die aber alle leicht zu fixen sind (über all wo der konstruktur wie die klasse heisst muss es __construct() heissen)

Kann das ganze als PR fertig machen :)

Benutzeravatar
Gregor.Harlan
Entwickler
Beiträge: 1130
Registriert: 4. Jun 2007, 10:35
Wohnort: Frankfurt am Main

Re: Redaxo 4 und PHP 7

18. Feb 2016, 12:36

Ich habe gerade das gefunden: https://github.com/dshafik/php7-mysql-shim
Auch interessant!

Ansonsten wäre meine Idee, die Funktion mysql_real_escape_string auf die mysqli-Variante umzuleiten.

Wegen construct: Wenn nur deprecated-Meldungen kommen, würde ich da nichts ändern, sondern nur die deprecated-Meldungen unterdrücken.
Denn sonst kann es Probleme geben, wenn Addons die Klassen erweitern und darin den Parent-Konstruktor aufrufen.

Aber ansonsten: gerne als PR!
Friends Of REDAXO: Gemeinsame REDAXO-Entwicklung!

jimhein
Beiträge: 69
Registriert: 3. Sep 2007, 11:00
Wohnort: Berlin

Re: Redaxo 4 und PHP 7

18. Feb 2016, 12:37

Cool, funktioniert!!!
Umlauteprobleme gab es bei mir nicht. Allerdings musste ich in der setup.inc.php noch den EXTENSION CHECK "anpassen":

Code: Alles auswählen

 // -------------------------- EXTENSION CHECK
        foreach (array('session', 'mysqli', 'pcre') as $extension) {
            if (!extension_loaded($extension)) {
            $MSG['err'] .= '<li>' . $I18N->msg('setup_010_1', $extension) . '</li>';
            }
        }
vielen dank!
ingo

Benutzeravatar
RexDude
Beiträge: 2543
Registriert: 22. Apr 2010, 11:24

Re: Redaxo 4 und PHP 7

18. Feb 2016, 13:02

@ingo:

ja genau der extension check muss auch noch angepasst werden.
wenn du dass ganze jetzt natürlich intensiv testest ist das super :D
Bitte gibt bescheid wenns noch was anzupassen gibt oder du auf Probleme stösst.

@gregor:
Ich habe gerade das gefunden: https://github.com/dshafik/php7-mysql-shim
Auch interessant!
Ich hatte verschiedne Wrapper und Converter ausprobiert zuerst, funzte aber nicht sauber. Aber den kann ich mir auch nochmal anschauen. Was aber sinnvoller ist weiss ich nicht....tendiere eigentlich eher zum "echten" Umbau...
Ansonsten wäre meine Idee, die Funktion mysql_real_escape_string auf die mysqli-Variante umzuleiten.
Yoa, wenns die gibt dann ist das Prob ja auch schon behoben.
Wegen construct: Wenn nur deprecated-Meldungen kommen, würde ich da nichts ändern, sondern nur die deprecated-Meldungen unterdrücken.
Denn sonst kann es Probleme geben, wenn Addons die Klassen erweitern und darin den Parent-Konstruktor aufrufen.
Verstehe deinen Einwand, allerdings wissen wir alle aus Erfahrung das die Leute Probleme bekommen werden weil sie von deprecated Meldungen überflutet werden und nicht wissen was sie damit anstellen sollen.
Aber ansonsten: gerne als PR!
hmmm, da noch einige Dinge unklar sind halte ich mich damit noch zurück....bzw. ich mach wie ichs für richtig halte und ihr könnt euch dann nach herzenslust bedienen wenn ihr wollt :D

Benutzeravatar
Gregor.Harlan
Entwickler
Beiträge: 1130
Registriert: 4. Jun 2007, 10:35
Wohnort: Frankfurt am Main

Re: Redaxo 4 und PHP 7

18. Feb 2016, 13:25

RexDude hat geschrieben:Ich hatte verschiedne Wrapper und Converter ausprobiert zuerst, funzte aber nicht sauber. Aber den kann ich mir auch nochmal anschauen. Was aber sinnvoller ist weiss ich nicht....tendiere eigentlich eher zum "echten" Umbau...
Weiß auch nicht, was sinnvoller ist, hab mir die Lib auch nicht genauer angeschaut. Hab zurzeit keine Tendenz. Würde sagen, hauptsache es funktioniert zuverlässig.
RexDude hat geschrieben:Verstehe deinen Einwand, allerdings wissen wir alle aus Erfahrung das die Leute Probleme bekommen werden weil sie von deprecated Meldungen überflutet werden und nicht wissen was sie damit anstellen sollen.
Ja das stimmt. Daher denke ich, wir sollten die Deaktivierung erzwingen. Sprich error_reporting-Wert auslesen, und den so verändern, dass Deprecated und Strict nicht beachtet werden.
RexDude hat geschrieben:hmmm, da noch einige Dinge unklar sind halte ich mich damit noch zurück....bzw. ich mach wie ichs für richtig halte und ihr könnt euch dann nach herzenslust bedienen wenn ihr wollt :D
Ist mir auch recht. Ich habe es da auch nicht so eilig. Also gerne erst mal bisschen testen etc.
Friends Of REDAXO: Gemeinsame REDAXO-Entwicklung!

Benutzeravatar
RexDude
Beiträge: 2543
Registriert: 22. Apr 2010, 11:24

Re: Redaxo 4 und PHP 7

18. Feb 2016, 13:29

Ja das stimmt. Daher denke ich, wir sollten die Deaktivierung erzwingen. Sprich error_reporting-Wert auslesen, und den so verändern, dass Deprecated und Strict nicht beachtet werden.
ohhh erzwingen.....böse böse :lol:

Benutzeravatar
fietstouring
Beiträge: 47
Registriert: 10. Okt 2006, 12:30
Wohnort: Wien
Kontaktdaten: Website

Re: Redaxo 4 und PHP 7

18. Feb 2016, 15:33

also ich poste es jetzt mal doch, obwohl es anscheinend nicht bei allen klassen/funktionen geht.
die zweite funktion ist so kein konstruktor mehr.

Code: Alles auswählen

function __construct() {
        $this->rex_select();
    }

    ################ Konstruktor
    /*public*/ function rex_select()
    {
        $this->init();
    }

netmanix

Re: Redaxo 4 und PHP 7

8. Mär 2016, 11:17

Wird es einen offiziellen PHP7 fix geben?
Ich bekomme so eine leichte Panik, bei dem einen oder anderen Projekt, sollten die Provider auf PHP 7 umstellen.
Eine Migration nach REX5 scheint mir bei einigen Projekten aufwändiger zu sein, als ein FIX der 4er Versionen.

Benutzeravatar
Gregor.Harlan
Entwickler
Beiträge: 1130
Registriert: 4. Jun 2007, 10:35
Wohnort: Frankfurt am Main

Re: Redaxo 4 und PHP 7

8. Mär 2016, 11:32

netmanix hat geschrieben:Wird es einen offiziellen PHP7 fix geben?
Ja. Zurzeit arbeiten wir an der Version 5.1, die recht bald fertig werden soll.
Danach werde ich mich mit dem PHP7-Fix beschäftigen.
Friends Of REDAXO: Gemeinsame REDAXO-Entwicklung!

netmanix

Re: Redaxo 4 und PHP 7

8. Mär 2016, 18:35

Danke, das hört sich gut an.
Sicher werde ich demnächst neue Projekte in REX5 umsetzen, dennoch wäre es schön wenn die 4er Version noch ein Weilchen gepflegt wird.
Ich arbeite mich noch in Rex5 ein und versuche noch mir einen Workflow zu erarbeiten, da ich mich gleichzeitig auch in less und Boostrap einarbeite. Für schnelle Lösungen setze ich aber eben noch ein REX4.x auf.

Benutzeravatar
Thomas.Blum
Entwickler
Beiträge: 5063
Registriert: 24. Aug 2004, 22:11
Wohnort: Dresden
Kontaktdaten: Website

Re: Redaxo 4 und PHP 7

8. Mär 2016, 21:06

Hej,
gleichzeitig auch in less und Boostrap einarbeite
Wenn du bei Bootstrap bleiben willst, dan arbeite dich eher in Sass als in Less ein. Die 4er Bootstrapversion ist auf Sass-basis.

vg Thomas

netmanix

Re: Redaxo 4 und PHP 7

9. Mär 2016, 14:55

Danke für den Tipp. :arrow: Schon wieder von vorn :(

Benutzeravatar
Gregor.Harlan
Entwickler
Beiträge: 1130
Registriert: 4. Jun 2007, 10:35
Wohnort: Frankfurt am Main

Re: Redaxo 4 und PHP 7

19. Apr 2016, 15:57

Wir haben heute die 4.7 veröffentlicht, mit PHP7-Unterstützung.
Friends Of REDAXO: Gemeinsame REDAXO-Entwicklung!

Benutzeravatar
georgkaser
Beiträge: 12
Registriert: 11. Mär 2013, 20:27
Wohnort: Worms
Kontaktdaten: Website

Re: Redaxo 4 und PHP 7

19. Apr 2016, 17:06

Sauuucool - Danke!!

Benutzeravatar
RexDude
Beiträge: 2543
Registriert: 22. Apr 2010, 11:24

Re: Redaxo 4 und PHP 7

19. Apr 2016, 17:35

@georgkaser: Schalte nicht aus versehen dein Error Reporting voll ein sonst erlebst du ganz viele lustige deprecated meldungen. Desweiteren ists mit PHP8 dann auch schon wieder inkompatibel. Aber ich nehme mal an in 5 Jaren oder so gibts sicherlich noch mal ein Update ;)

Benutzeravatar
Gregor.Harlan
Entwickler
Beiträge: 1130
Registriert: 4. Jun 2007, 10:35
Wohnort: Frankfurt am Main

Re: Redaxo 4 und PHP 7

19. Apr 2016, 20:32

RexDude hat geschrieben:@georgkaser: Schalte nicht aus versehen dein Error Reporting voll ein sonst erlebst du ganz viele lustige deprecated meldungen.
Nein, wird er nicht. Denn der Core selbst schaltet die seit 4.7 ab (nur Strict und Deprecated).
Hintergrund: Es wird auch in vielen Addons Code geben, der Strict- oder Deprecated-Meldungen erzeugt. Vor allem ist nicht absehbar, was in den nächsten PHP-Versionen noch so als deprecated markiert werden wird, und es sind nun mal keine regelmäßigen Updates mehr für R4 geplant. Eigentlich nur noch bei Sicherheitsproblemen.
RexDude hat geschrieben:Desweiteren ists mit PHP8 dann auch schon wieder inkompatibel. Aber ich nehme mal an in 5 Jaren oder so gibts sicherlich noch mal ein Update ;)
Bis jetzt ist ja noch überhaupt nicht absehbar, wann es PHP 8 geben wird. Und wie ich oben schon geschrieben hab, vor allem auch nicht, was bis dahin alles noch so als deprecated markiert wird und somit in PHP 8 wegfallen wird. Also selbst, wenn wir jetzt alle Deprecated-Meldungen aufgelöst hätten, wäre 4.7 höchstwahrscheinlich trotzdem nicht mit PHP 8 kompatibel.

Wenn PHP 8 dann in Sicht ist, werden wir uns Gedanken machen, wie wir damit umgehen. Wenn R4 dann noch relevant ist, und es mit vertretbaren Aufwand möglich ist, R4 in PHP 8 lauffähig zu machen, werden wir das sicherlich tun.

Ich hoffe, ich konnte dir damit deine Sorgen etwas nehmen.
Friends Of REDAXO: Gemeinsame REDAXO-Entwicklung!

Benutzeravatar
RexDude
Beiträge: 2543
Registriert: 22. Apr 2010, 11:24

Re: Redaxo 4 und PHP 7

19. Apr 2016, 21:37

Gregor du musst wissen was du tust. Überzeugt von deiner Lösung bin ich nicht weil ich es nie für eine gute Idee halte einfach Fehlermeldungen zu unterdrücken um ein Problem zu beseitigen. Und ja ich weiss das das im Core abheschaltet wird, aber was ist denn wenn ich ein Addon entwickeln will und dann dessen Notices/Deprectes beseitigen will. Dann hab ich doch denn ganzen Schmodder vom Core auch mit einheschaltet?

Ich habe noch weitere Anmerkungen zu deinem Release:
- Im Zip befindet sich ein Layout ordner.
- Das Zip hat 7MB. Entpacket man es und packt es wieder sinds nur noch 2,8MB
- Auf eine VM mit Linux und XAMPP (PHP7) scheint kommt dass hier.

Weitere Tests erübrigen sich damit für mich erstmal weil das Ding so unbenutzbar ist.
Dateianhänge
r47.jpg
r47.jpg (171.24 KiB) 8873 mal betrachtet

Benutzeravatar
Markus.Staab
Entwickler
Beiträge: 9634
Registriert: 29. Jan 2005, 15:50
Wohnort: Aschaffenburg/Germany
Kontaktdaten: ICQ Website

Re: Redaxo 4 und PHP 7

19. Apr 2016, 21:45

Rudi, wenn du redaxo weiterbringen wolltest hättest du diese Probleme einfach gemeldet und nicht mit so einer nebulösen Aussage die Forenuser verschreckt.

Dass deine arbeitsweise nicht für einen großteil der Community steht hat sich ja schon des öfteren in Gesprächen gezeigt

Zurück zu „Allgemeines [R4]“