Memory Usage

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

Post Reply
evans123
Forum Newbie
Posts: 18
Joined: Wed Nov 17, 2010 4:48 pm

Memory Usage

Post by evans123 »

I have a problem of memory usage causing a fatal error.

Code: Select all

Fatal error:  Allowed memory size of 68157440 bytes exhausted (tried to allocate 11851666 bytes) in /home/xxx/xxx/xxx/resources/classes/database.php on line 136
I called the following code in my home.php file.

Code: Select all

$db->query("SELECT b FROM users");
The field "b" doesn't actually exist so in the database class it catches the error and then trys to log it using the log class.

The insert statement of the log class fails to execute, therefore a loop occurs as the database class trys to log this error, causing a build up of memory usage.

Any ideas on what is causing it?

Database Class:

Code: Select all

<?
/**
 * News Muncher Database Class
 *
 * The Database class is meant to simplify the task of accessing
 * information from the website's database.
 *
 * Written by: Ben Web Developer.com
 * Last Updated: 25 October 2010
 * Version: 0.1.0
 */
 
class Database {
    
    /**
     * The pdo database object
     *
     * @access private
     * @var object
    */
    private $dbh;
    
    /**
     * The mysqli prepared statement database object
     *
     * @access private
     * @var object
    */
    private $stmt;
    
    /**
     * Whether to show SQL/DB errors
     *
     * @since 0.1.0
     * @var bool
     */
    var $show_errors = false;
    
    /**
     * The start time of the query
     *
     * @since 0.1.0
     * @var string
     */
    var $query_start_time;
    
    /**
     * Time taken to execute the query
     *
     * @since 0.1.0
     * @var string
     */
    var $query_time;
    
    /**
     * Total time taken to execute all queries
     *
     * @since 0.1.0
     * @var string
     */
    var $total_query_time;
    
    /**
     * Amount of queries made
     *
     * @since 0.1.0
     * @var int
     */
    var $num_queries = 0;
    
    /**
     * Amount of queries that contained errors
     *
     * @since 0.1.0
     * @var int
     */
    var $num_error_queries = 0;
    
    /**
     * Results of the last query
     *
     * @since 0.1.0
     * @var array
     */
    var $last_result = array();
    
    /**
     * Class constructor
     *
     * @since 0.1.0
     * @var bool
     */
    public function __construct() {
        try {
            // Connect to database
            $this->dbh = new PDO("mysql:host=".SERVER.";dbname=".NAME.";", USER, PASS, array( PDO::ATTR_PERSISTENT => true ));

            // Set the PDO error mode to exception
            $this->dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        }
        catch (PDOException $e) {
            // Show errors if enabled
            if($this->show_errors) {
                echo $e->getMessage();
                echo $e->getLine();
            }
            return false;
        }
    }
    
    /**
     * Query the database
     *
     * @access public
     * @since 0.1.0
     * @var bool
     */
    public function query($sql, $params = array()) {
        
        global $log, $page_handler;
    
        // Try and execute the query        
        try {

            // Start query execution time
            $this->query_start_time = microtime(true);
            
            // Prepare the sql statement
            $this->stmt = $this->dbh->prepare($sql);
            
            // Bind the parameters
            
            if( count($params) > 0 )
                $this->stmt = $this->bind_params($this->stmt, $params);
            // Execute the statment
            $this->stmt->execute();
            
            // Debug
            echo size_format(memory_get_usage(), 4).' - '.$sql.' '.$this->stmt->columnCount().'<br />';
            
            // Fetch Results
            
                /**
                 * Using the column count of the statement we can determine if the sql statement was a update, insert, delete or select etc.
                 * Therefore we can see if we need to return a result set or not.
                 */
                
                if( $this->stmt->columnCount() > 0 )
                    $this->fetch_all();
                else
                    $this->last_result = array();

            // Calculate query time and add it onto the total query time.
            $this->query_time = microtime(true) - $this->query_start_time;
            $this->total_query_time = $this->total_query_time + $this->query_time;
            
            // Increase the number of queries
            $this->num_queries++;
            
            // Return true upon success
            return true;                
        }
        catch (PDOException $e) {
            
            /**
             * Increase the number of error queries and stop the query time.
             */
             $this->num_error_queries++;
             $this->query_start_time = 0;
            
             /**
              * Log and show the error if enabled
              * The exception handler will return a trace of the error, we can use this to determine where the error occured.
              * We need to use the template file and not the class file to determine where the error is, hence why we return
              * the 2nd row in our array.
              */
             $log->add('database', $page_handler->url, $e->getTrace());
              if( $this->show_errors ) {
                  
                  echo '<pre><h4>Database Error</h4>';
                  
                  echo '<strong>SQL Statement:</strong> '.$e->getMessage().'<br />';
                  
                  echo '<br /><strong>Error Trace</strong><br /><br />';
                  foreach ($e->getTrace() as $key => $value) {
                      echo '<strong>File:</strong> '.$value['file'].'<br />';
                      echo '<strong>Line Number:</strong> '.$value['line'].'<br /><br />';
                  }
                  echo '</pre>';
              }

            // Return false upon failure
            return false;
        }
    
    }

    /**
     * Dynamically bind parameters
     *
     * @access private
     * @since 0.1.0
     * @var object
     */
     private function bind_params($stmt, $params) {
        try {
        foreach($params as $key => &$value)
            {
                $stmt->bindParam($key, $value);                
            }
            return $stmt;
        }
        catch (PDOException $e) {
                // Show errors if enabled
                if($this->show_errors)
                echo $e->getMessage();
                echo $e->getLine();
                
                //Log errors

                return false;
        }
     }
    
    /**
     * Get insert id from last query
     *
     * @access public
     * @since 0.1.0
     * @var int
     */
    public function getLastInsertId() {
        return $this->dbh->lastInsertId( );
    }
    
    /**
     * Fetch all of the records returned from the query
     * and set the last_result variable.
     *
     * @since 0.1.0
     * @var array
     */
    private function fetch_all() {
        $this->last_result = $this->stmt->fetchAll(PDO::FETCH_ASSOC);
    }
    
    /**
     * Get the number of rows returned from the query
     * Applies to select queries.
     *
     * @since 0.1.0
     * @var string
     */
    public function get_num_rows() {
        return count($this->last_result);
    }
    
    /**
     * Get number of affected rows from last query
     * Applies to update, insert and delete queries
     *
     * @access public
     * @since 0.1.0
     * @var int
     */
    public function get_affected_rows() {
        return $this->stmt->rowCount();    
    }
}
Log Class:

Code: Select all

<?
/**
 * News Muncher Log Class
 *
 * The Log class is meant to simplify the task of logging
 * any errors the website generates.
 *
 * Written by: Ben Web Developer.com
 * Last Updated: 19 December 2010
 * Version: 0.1.0
 */
class Log {
    
    public function add($type, $url, $info) {
        global $db, $user_management;
        
        
        $db->query('INSERT INTO log (type, url, information, timestamp, username, ip, read) VALUES (:type, :url, :information, :timestamp, :username, :ip, :read)', array(':type' => $type, ':url' => $url, ':information' => serialize($info), ':timestamp' => time(), ':username' => $user_management->username, ':ip' => $_SERVER['REMOTE_ADDR'], ':read' => '0'));    
        return true;
        
    }
    
    public function show() {
        global $db;
        
            $db->query('SELECT type, url, information, timestamp, read FROM log');    
            return $db->last_result;
        
        
    }
}
evans123
Forum Newbie
Posts: 18
Joined: Wed Nov 17, 2010 4:48 pm

Re: Memory Usage

Post by evans123 »

Ive changed the insert statement slightly,

From: type, url, information, timestamp, username, ip, read
To:`type` ,`url` ,`information` ,`timestamp` ,`username` ,`ip` ,`read`

Having done this the query now works, i don't understand why it didnt work in the first one.
evans123
Forum Newbie
Posts: 18
Joined: Wed Nov 17, 2010 4:48 pm

Re: Memory Usage

Post by evans123 »

Sorted Now...

There is a list of sql reserved words which if you use in your statements must be escaped.
Post Reply