-3

我在 Joomla 的一个组件中有这个错误

这是我的代码(错误在第 263 行):

<?php
/**
 * @package     Joomla.Platform
 * @subpackage  Database
 *
 * @copyright   Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE
 */

defined('JPATH_PLATFORM') or die;

JLoader::register('JDatabaseMySQL', dirname(__FILE__) . '/mysql.php');
JLoader::register('JDatabaseQueryMySQLi', dirname(__FILE__) . '/mysqliquery.php');
JLoader::register('JDatabaseExporterMySQLi', dirname(__FILE__) . '/mysqliexporter.php');
JLoader::register('JDatabaseImporterMySQLi', dirname(__FILE__) . '/mysqliimporter.php');

/**
 * MySQLi database driver
 *
 * @package     Joomla.Platform
 * @subpackage  Database
 * @see         http://php.net/manual/en/book.mysqli.php
 * @since       11.1
 */
class JDatabaseMySQLi extends JDatabaseMySQL
{
    /**
     * The name of the database driver.
     *
     * @var    string
     * @since  11.1
     */
    public $name = 'mysqli';

    /**
     * Constructor.
     *
     * @param   array  $options  List of options used to configure the connection
     *
     * @since   11.1
     */
    protected function __construct($options)
    {
        // Get some basic values from the options.
        $options['host'] = (isset($options['host'])) ? $options['host'] : 'localhost';
        $options['user'] = (isset($options['user'])) ? $options['user'] : 'root';
        $options['password'] = (isset($options['password'])) ? $options['password'] : '';
        $options['database'] = (isset($options['database'])) ? $options['database'] : '';
        $options['select'] = (isset($options['select'])) ? (bool) $options['select'] : true;
        $options['port'] = null;
        $options['socket'] = null;

        /*
         * Unlike mysql_connect(), mysqli_connect() takes the port and socket as separate arguments. Therefore, we
         * have to extract them from the host string.
         */
        $tmp = substr(strstr($options['host'], ':'), 1);
        if (!empty($tmp))
        {
            // Get the port number or socket name
            if (is_numeric($tmp))
            {
                $options['port'] = $tmp;
            }
            else
            {
                $options['socket'] = $tmp;
            }

            // Extract the host name only
            $options['host'] = substr($options['host'], 0, strlen($options['host']) - (strlen($tmp) + 1));

            // This will take care of the following notation: ":3306"
            if ($options['host'] == '')
            {
                $options['host'] = 'localhost';
            }
        }

        // Make sure the MySQLi extension for PHP is installed and enabled.
        if (!function_exists('mysqli_connect'))
        {

            // Legacy error handling switch based on the JError::$legacy switch.
            // @deprecated  12.1
            if (JError::$legacy)
            {
                $this->errorNum = 1;
                $this->errorMsg = JText::_('JLIB_DATABASE_ERROR_ADAPTER_MYSQLI');
                return;
            }
            else
            {
                throw new JDatabaseException(JText::_('JLIB_DATABASE_ERROR_ADAPTER_MYSQLI'));
            }
        }

        $this->connection = @mysqli_connect(
            $options['host'], $options['user'], $options['password'], null, $options['port'], $options['socket']
        );

        // Attempt to connect to the server.
        if (!$this->connection)
        {
            // Legacy error handling switch based on the JError::$legacy switch.
            // @deprecated  12.1
            if (JError::$legacy)
            {
                $this->errorNum = 2;
                $this->errorMsg = JText::_('JLIB_DATABASE_ERROR_CONNECT_MYSQL');
                return;
            }
            else
            {
                throw new JDatabaseException(JText::_('JLIB_DATABASE_ERROR_CONNECT_MYSQL'));
            }
        }

        // Finalize initialisation
        JDatabase::__construct($options);

        // Set sql_mode to non_strict mode
        mysqli_query($this->connection, "SET @@SESSION.sql_mode = '';");

        // If auto-select is enabled select the given database.
        if ($options['select'] && !empty($options['database']))
        {
            $this->select($options['database']);
        }
    }

    /**
     * Destructor.
     *
     * @since   11.1
     */
    public function __destruct()
    {
        if (is_callable(array($this->connection, 'close')))
        {
            mysqli_close($this->connection);
        }
    }

    /**
     * Method to escape a string for usage in an SQL statement.
     *
     * @param   string   $text   The string to be escaped.
     * @param   boolean  $extra  Optional parameter to provide extra escaping.
     *
     * @return  string  The escaped string.
     *
     * @since   11.1
     */
    public function escape($text, $extra = false)
    {
        $result = mysqli_real_escape_string($this->getConnection(), $text);

        if ($extra)
        {
            $result = addcslashes($result, '%_');
        }

        return $result;
    }

    /**
     * Test to see if the MySQL connector is available.
     *
     * @return  boolean  True on success, false otherwise.
     *
     * @since   11.1
     */
    public static function test()
    {
        return (function_exists('mysqli_connect'));
    }

    /**
     * Determines if the connection to the server is active.
     *
     * @return  boolean  True if connected to the database engine.
     *
     * @since   11.1
     */
    public function connected()
    {
        if (is_object($this->connection))
        {
            return mysqli_ping($this->connection);
        }

        return false;
    }

    /**
     * Get the number of affected rows for the previous executed SQL statement.
     *
     * @return  integer  The number of affected rows.
     *
     * @since   11.1
     */
    public function getAffectedRows()
    {
        return mysqli_affected_rows($this->connection);
    }

    /**
     * Gets an exporter class object.
     *
     * @return  JDatabaseExporterMySQLi  An exporter object.
     *
     * @since   11.1
     * @throws  JDatabaseException
     */
    public function getExporter()
    {
        // Make sure we have an exporter class for this driver.
        if (!class_exists('JDatabaseExporterMySQLi'))
        {
            throw new JDatabaseException(JText::_('JLIB_DATABASE_ERROR_MISSING_EXPORTER'));
        }

        $o = new JDatabaseExporterMySQLi;
        $o->setDbo($this);

        return $o;
    }

    /**
     * Gets an importer class object.
     *
     * @return  JDatabaseImporterMySQLi  An importer object.
     *
     * @since   11.1
     * @throws  JDatabaseException
     */
    public function getImporter()
    {
        // Make sure we have an importer class for this driver.
        if (!class_exists('JDatabaseImporterMySQLi'))
        {
            throw new JDatabaseException(JText::_('JLIB_DATABASE_ERROR_MISSING_IMPORTER'));
        }

        $o = new JDatabaseImporterMySQLi;
        $o->setDbo($this);

        return $o;
    }

    /**
     * Get the number of returned rows for the previous executed SQL statement.
     *
     * @param   resource  $cursor  An optional database cursor resource to extract the row count from.
     *
     * @return  integer   The number of returned rows.
     *
     * @since   11.1
     */
    public function getNumRows($cursor = null)
    {
        return mysqli_num_rows($cursor ? $cursor : $this->cursor);
    }

    /**
     * Get the current or query, or new JDatabaseQuery object.
     *
     * @param   boolean  $new  False to return the last query set, True to return a new JDatabaseQuery object.
     *
     * @return  mixed  The current value of the internal SQL variable or a new JDatabaseQuery object.
     *
     * @since   11.1
     * @throws  JDatabaseException
     */
    public function getQuery($new = false)
    {
        if ($new)
        {
            // Make sure we have a query class for this driver.
            if (!class_exists('JDatabaseQueryMySQLi'))
            {
                throw new JDatabaseException(JText::_('JLIB_DATABASE_ERROR_MISSING_QUERY'));
            }
            return new JDatabaseQueryMySQLi($this);
        }
        else
        {
            return $this->sql;
        }
    }

    /**
     * Get the version of the database connector.
     *
     * @return  string  The database connector version.
     *
     * @since   11.1
     */
    public function getVersion()
    {
        return mysqli_get_server_info($this->connection);
    }

    /**
     * Determines if the database engine supports UTF-8 character encoding.
     *
     * @return  boolean  True if supported.
     *
     * @since   11.1
     * @deprecated 12.1
     */
    public function hasUTF()
    {
        JLog::add('JDatabaseMySQLi::hasUTF() is deprecated.', JLog::WARNING, 'deprecated');
        return true;
    }

    /**
     * Method to get the auto-incremented value from the last INSERT statement.
     *
     * @return  integer  The value of the auto-increment field from the last inserted row.
     *
     * @since   11.1
     */
    public function insertid()
    {
        return mysqli_insert_id($this->connection);
    }

    /**
     * Execute the SQL statement.
     *
     * @return  mixed  A database cursor resource on success, boolean false on failure.
     *
     * @since   11.1
     * @throws  JDatabaseException
     */
    public function execute()
    {
        if (!is_object($this->connection))
        {
            // Legacy error handling switch based on the JError::$legacy switch.
            // @deprecated  12.1
            if (JError::$legacy)
            {
                if ($this->debug)
                {
                    JError::raiseError(500, 'JDatabaseMySQLi::query: ' . $this->errorNum . ' - ' . $this->errorMsg);
                }
                return false;
            }
            else
            {
                JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED', $this->errorNum, $this->errorMsg), JLog::ERROR, 'database');
                throw new JDatabaseException($this->errorMsg, $this->errorNum);
            }
        }

        // Take a local copy so that we don't modify the original query and cause issues later
        $sql = $this->replacePrefix((string) $this->sql);
        if ($this->limit > 0 || $this->offset > 0)
        {
            $sql .= ' LIMIT ' . $this->offset . ', ' . $this->limit;
        }

        // If debugging is enabled then let's log the query.
        if ($this->debug)
        {
            // Increment the query counter and add the query to the object queue.
            $this->count++;
            $this->log[] = $sql;

            JLog::add($sql, JLog::DEBUG, 'databasequery');
        }

        // Reset the error values.
        $this->errorNum = 0;
        $this->errorMsg = '';

        // Execute the query.
        $this->cursor = mysqli_query($this->connection, $sql);

        // If an error occurred handle it.
        if (!$this->cursor)
        {
            $this->errorNum = (int) mysqli_errno($this->connection);
            $this->errorMsg = (string) mysqli_error($this->connection) . ' SQL=' . $sql;

            // Legacy error handling switch based on the JError::$legacy switch.
            // @deprecated  12.1
            if (JError::$legacy)
            {
                if ($this->debug)
                {
                    JError::raiseError(500, 'JDatabaseMySQLi::query: ' . $this->errorNum . ' - ' . $this->errorMsg);
                }
                return false;
            }
            else
            {
                JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED', $this->errorNum, $this->errorMsg), JLog::ERROR, 'databasequery');
                throw new JDatabaseException($this->errorMsg, $this->errorNum);
            }
        }

        return $this->cursor;
    }

    /**
     * Select a database for use.
     *
     * @param   string  $database  The name of the database to select for use.
     *
     * @return  boolean  True if the database was successfully selected.
     *
     * @since   11.1
     * @throws  JDatabaseException
     */
    public function select($database)
    {
        if (!$database)
        {
            return false;
        }

        if (!mysqli_select_db($this->connection, $database))
        {
            // Legacy error handling switch based on the JError::$legacy switch.
            // @deprecated  12.1
            if (JError::$legacy)
            {
                $this->errorNum = 3;
                $this->errorMsg = JText::_('JLIB_DATABASE_ERROR_DATABASE_CONNECT');
                return false;
            }
            else
            {
                throw new JDatabaseException(JText::_('JLIB_DATABASE_ERROR_DATABASE_CONNECT'));
            }
        }

        return true;
    }

    /**
     * Set the connection to use UTF-8 character encoding.
     *
     * @return  boolean  True on success.
     *
     * @since   11.1
     */
    public function setUTF()
    {
        mysqli_query($this->connection, "SET NAMES 'utf8'");
    }

    /**
     * Method to fetch a row from the result set cursor as an array.
     *
     * @param   mixed  $cursor  The optional result set cursor from which to fetch the row.
     *
     * @return  mixed  Either the next row from the result set or false if there are no more rows.
     *
     * @since   11.1
     */
    protected function fetchArray($cursor = null)
    {
        return mysqli_fetch_row($cursor ? $cursor : $this->cursor);
    }

    /**
     * Method to fetch a row from the result set cursor as an associative array.
     *
     * @param   mixed  $cursor  The optional result set cursor from which to fetch the row.
     *
     * @return  mixed  Either the next row from the result set or false if there are no more rows.
     *
     * @since   11.1
     */
    protected function fetchAssoc($cursor = null)
    {
        return mysqli_fetch_assoc($cursor ? $cursor : $this->cursor);
    }

    /**
     * Method to fetch a row from the result set cursor as an object.
     *
     * @param   mixed   $cursor  The optional result set cursor from which to fetch the row.
     * @param   string  $class   The class name to use for the returned row object.
     *
     * @return  mixed   Either the next row from the result set or false if there are no more rows.
     *
     * @since   11.1
     */
    protected function fetchObject($cursor = null, $class = 'stdClass')
    {
        return mysqli_fetch_object($cursor ? $cursor : $this->cursor, $class);
    }

    /**
     * Method to free up the memory used for the result set.
     *
     * @param   mixed  $cursor  The optional result set cursor from which to fetch the row.
     *
     * @return  void
     *
     * @since   11.1
     */
    protected function freeResult($cursor = null)
    {
        mysqli_free_result($cursor ? $cursor : $this->cursor);
    }

    /**
     * Execute a query batch.
     *
     * @param   boolean  $abortOnError     Abort on error.
     * @param   boolean  $transactionSafe  Transaction safe queries.
     *
     * @return  mixed  A database resource if successful, false if not.
     *
     * @deprecated  12.1
     * @since   11.1
     */
    public function queryBatch($abortOnError = true, $transactionSafe = false)
    {
        // Deprecation warning.
        JLog::add('JDatabaseMySQLi::queryBatch() is deprecated.', JLog::WARNING, 'deprecated');

        $sql = $this->replacePrefix((string) $this->sql);
        $this->errorNum = 0;
        $this->errorMsg = '';

        // If the batch is meant to be transaction safe then we need to wrap it in a transaction.
        if ($transactionSafe)
        {
            $sql = 'START TRANSACTION;' . rtrim($sql, "; \t\r\n\0") . '; COMMIT;';
        }
        $queries = $this->splitSql($sql);
        $error = 0;
        foreach ($queries as $query)
        {
            $query = trim($query);
            if ($query != '')
            {
                $this->cursor = mysqli_query($this->connection, $query);
                if ($this->debug)
                {
                    $this->count++;
                    $this->log[] = $query;
                }
                if (!$this->cursor)
                {
                    $error = 1;
                    $this->errorNum .= mysqli_errno($this->connection) . ' ';
                    $this->errorMsg .= mysqli_error($this->connection) . " SQL=$query <br />";
                    if ($abortOnError)
                    {
                        return $this->cursor;
                    }
                }
            }
        }
        return $error ? false : true;
    }
}
4

2 回答 2

0

如果您使用的是 joomla 2.5,请再次检查您的 php 版本;它至少必须是 php 5.3。

于 2014-01-02T10:33:37.273 回答
0

正如 Jon Conde 提供的链接所说,您得到这个是因为您的查询中有错误。您没有提供查询,因此无法知道问题所在。不幸的是,总体上你得到的一些建议会使情况变得更糟,因为问题不在 JDatabaseQueryMysqli 中,而在你调用它的代码中。由于查询失败,您得到的是布尔值 false 而不是预期的结果。

要查看生成的查询,您可以使用

echo $query->dump();

把它放在你调用 getNumRows() 之前。你可能需要一个模具;根据上下文或仅记录它,或者如果在 cms 中,您可以打开调试器并查看生成的查询(全局配置,调试)。

如果您提供代码(不是 api 的副本),那么人们可以帮助调试您的查询。

我会说这是一个错误,它没有对此进行测试,并且如果您的查询失败则抛出异常。

于 2013-07-21T10:22:20.057 回答