Search code examples
phparraysmysqlimemory-limit

PHP Script always exceeds memory limit when adding to an array?


I've been going mental over this one. I'm sure it never used to do this, however I must've changed something so it did.

This is the php script in question:

<?php

echo <<<START
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>Spotify Community Staff Tracker</title>
<link rel="stylesheet" type="text/css" href="styles.css" />
<meta http-equiv="Content-Type" content="text/xhtml; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<script type='text/javascript' src='scripts/respond.min.js'></script>
</head>
<body>
START;

error_reporting(E_ALL & ~E_NOTICE & ~E_WARNING);

require_once('config.php');

$posts = array();

$db = new mysqli($config['host'], $config['user'], $config['password'], $config['database']);

if ( ($result = $db->query('SELECT * FROM `posts`')) != false)
{
    while ( ($obj = mysqli_fetch_object($result)) !== false)
    {
        if (@$_GET['idfilter'] && @$_GET['idfilter'] != $obj->board)
        {
            continue;
        }

        $posts[] = array('datetime' => $obj->datetime, 'subject' => $obj->subject, 'post_url' => $obj->post_link, 'user_url' => $obj->author_link, 'user' => $obj->author_name);
    }

    if (sizeof($posts) == 0)
    {
        if ($_GET['idfilter'])
            die("Filter caused zero result, or cron hasn't run.");
        die("Cron hasn't been run.");
    }

}
else
{
    die("An error occured.");
}

$lupdate = mysqli_fetch_object($db->query("SELECT * FROM `last_update`"));

echo <<<BOTTOM
<div id="right" class="fixed">
    <p id="lastupdate">Last Updated: {$lupdate->timestamp}</p>
    <p><form id="filter" action="" method="get">
            <input type="text" placeholder="Enter a forum id to filter..." name="idfilter" />
            <input type="submit" value="Filter" id="submit" />
    </form>
            </p>
</div>
BOTTOM;

echo("\n<div id=\"posts\">");

foreach (array_reverse($posts) as $post)
{
    echo("\n<p><a class=\"postlink\" target=\"_blank\" href=\"{$post['post_url']}\">{$post['subject']}</a> - by <a class=\"suser\" target=\"_blank\" href=\"{$post['user_url']}\"><img src=\"http://spotify.i.lithium.com/html/rank_icons/spotify_icon_new.png\" alt=\"Spotify Staff\" />{$post['user']}</a> <span class=\"datetime\">on {$post['datetime']}</span>\n</p>");
}

echo("\n</div>");

echo <<<END
\n</body>
</html>
END;

?>

Whenever I run it I get the following error:

Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 44 bytes) in <filepath>\index.php on line 36

It's always the same error, - same allocation, same line. I've tried moving things around, I've tried using an array instead of an object, no use.

Any ideas as to why such a large amount of memory is trying to be used?

(There are around 400 rows in the database)


Solution

  • It's this line that's causing you the problem:

    while ( ($obj = mysqli_fetch_object($result)) !== false)
    

    If you look at the documentation: http://www.php.net/manual/en/mysqli-result.fetch-object.php

    mysqli_fetch_object returns the next row if there is one; or null if there isn't. So because you're doing a strict comparison, your loop will never end. To fix this, you can simple do:

    while ($obj = mysqli_fetch_object($result))
    

    And let PHP's type juggling convert the null at the end of the recordset to a boolean false.