【问题标题】:Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 64 bytes) on line 305致命错误:第 305 行允许的内存大小为 134217728 字节已用尽(尝试分配 64 字节)
【发布时间】:2016-02-02 12:14:29
【问题描述】:

我刚刚在我的网页中添加了一个新的query,它使用while loop 生成array 的结果。但是,当我尝试运行该页面时,出现错误:"Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 64 bytes) on line 305"。我无法弄清楚为什么会突然发生这种情况,或者内存泄漏可能是什么。我不希望增加 PHP memory_limit 的大小。

我的问题有所不同...我想就可能导致内存泄漏的原因寻求建议,而不是这个致命错误是什么或意味着什么。

有问题的查询:

<?php

        $result1 = $con->query("SELECT SkillID FROM userskills WHERE UserID = '$User'") or die(mysqli_error($con));

        $current_skills = array();

        while (($skillrow = mysqli_fetch_array($result1, MYSQLI_NUM)) !== false){
            $current_skills[] = $skillrow;
            }
?>

整页:

<?php 

error_reporting(E_ALL); ini_set('display_errors', 1); 
require 'Assets/Connections/Connections.php';
session_start(); 
    if(isset($_SESSION["UserID"]))
    {
    }
    else
    {
        header('Location: LogIn.php');
        die();
    }

    $User = (int)$_SESSION["UserID"];

    $result = $con->query("SELECT * FROM user WHERE UserID ='$User'") or die(mysqli_error($con));

    $row = $result->fetch_array(MYSQLI_BOTH);

    $_SESSION["FirstName"] = $row['Fname'];
    $_SESSION["LastName"] = $row['Lname'];
    $_SESSION["Email"] = $row['Email'];
    $_SESSION["Role"] = $row['JobRole'];

    $skillresult = $con->query("SELECT userskills.SkillID, Description, Experience FROM User INNER JOIN userskills ON User.UserId = userskills.UserId JOIN Skills ON userskills.SkillID = Skills.SkillID WHERE user.UserID ='$User'") 
    or die(mysqli_error($con));

    $skills_array = array();

    while($r=mysqli_fetch_array($skillresult)){
    if (!isset($skills_array[$r['SkillID']])){
        $skills_array[$r['SkillID']] = array();
    }
    $skills_array[$r['SkillID']][] = $r['Description'];
}

    if(isset($_POST['Update']))
    {

        $UpdateFName = $_SESSION["FirstName"];
        if ($_POST['FirstName'] != '' ) { $UpdateFName = $_POST['FirstName'];}
        $UpdateLName = $_SESSION["LastName"];
        if ($_POST['LastName'] != '' ) { $UpdateLName = $_POST['LastName'];}
        $UpdateEmail = $_SESSION["Email"];
        if ($_POST['Email'] != '' ) { $UpdateEmail = $_POST['Email'];}
        $UpdateRole = $_SESSION["Role"];
        if ($_POST['JobRole'] != '' ) { $UpdateRole = $_POST['JobRole'];}
        $PasswordCheck = $_POST['Password'];
        if(password_verify($PasswordCheck, $row['Password']))
        {

            $sql = $con->query("UPDATE user SET 
                Fname = '{$UpdateFName}', 
                Lname = '{$UpdateLName}', 
                Email = '{$UpdateEmail}', 
                JobRole = '{$UpdateRole}'
            WHERE UserID = $User") or die(mysqli_error($con));

            if(!empty($_FILES['file']['name']))
            {
                $file = basename($_FILES['file']['name']);
                move_uploaded_file($_FILES['file']['tmp_name'], 'Assets/Images/'.$file);
            }

            if(isset($file))
            {
                $sql = $con->query("UPDATE user SET ProfileImage = '".$_FILES['file']['name']."' WHERE UserID = $User") or die(mysqli_error($con));
            }

            $default = 0;

            foreach($skills_array AS $skills_id=>$skills_name)
            {
                if (isset($_POST[$skills_name]))
                {
                    if (empty($_POST[$skills_name.'exp']))
                    {
                        $exp = $default;
                    }
                    else
                    {
                        $exp = $_POST[$skills_name.'exp'];
                    }

                    $sql = $con->query("SELECT count(UserID) as total FROM userskills WHERE UserID = $User AND SkillID = ".$skills_id) or die(mysqli_error($con));

                    if ($row = mysqli_fetch_assoc($sql))
                    {
                        $sql = $con->query("INSERT INTO userskills ( UserID, SkillID, Experience) VALUES  ($User, $skills_id, $exp)");
                        //If the checkbox is not checked it will check to see if skill is already a skill assigned to the user. If they are it will delete it. If not it will ignore.   
                    }
                    else
                    {
                        $sql = $con->query("UPDATE userskills SET Experience = $exp WHERE UserID = $User AND SkillID = ".$skills_id);
                    }
                } 
                else
                {
                    $sql = $con->query("DELETE FROM userskills WHERE UserID = $User AND SkillID = ".$skills_id);
                }
            }

            header('Location: Account.php');
            die();
        }
        else
        {
            echo 'Incorrect password please try again.';
        }
    }
?>
<!doctype html>
<html>
<head>
<link href="Assets/CSS/Master.css" rel="stylesheet" type="text/css" />
<link href="Assets/CSS/Menu.css" rel="stylesheet" type="text/css" />
<meta charset="utf-8">
<title>Update Account</title>
</head>

<body>
<div class="Container">
        <div class="Header"></div>
        <div class="Menu">
                <div id="Menu">
                        <nav>
                                <ul class="cssmenu">
                                        <li><a href="Home.php">Home</a></li>
                                        <li><a href="Account.php">Account</a></li>
                                        <li><a href="Projects.php">Projects</a></li>
                                        <li><a href="Users.php">Users</a></li>
                                        <li><a href="LogOut.php">LogOut</a></li>
                                </ul>
                        </nav>
                </div>
        </div>
        <div class="LeftBody">
                <form id="form1" name="form1" method="post" enctype="multipart/form-data">
                        <div class="FormElement">
                                <input name="FirstName" type="text" class="TField" id="FirstName" placeholder="First Name" value="<?php echo $_SESSION["FirstName"]; ?>">
                        </div>
                        <div class="FormElement">
                                <input name="LastName" type="text" class="TField" id="LastName" placeholder="Last Name" value="<?php echo $_SESSION["LastName"]; ?>">
                        </div>
                        <div class="FormElement">
                                <input name="Email" type="email" class="TField" id="Email" placeholder="Email Address" value="<?php echo $_SESSION["Email"]; ?>">
                        </div>
                        <div class="FormElement">
                                <input name="JobRole" type="text" class="TField" id="JobRole" placeholder="Job Role" value="<?php echo $_SESSION["Role"]; ?>">
                        </div>
                        <div class="FormElement">
                                <input name="Password" type="password" class="TField" id="Password" placeholder="Password" required="requried">
                        </div>
                        <div class="FormElement">
                                <input type="file" name="file">
                                <br>
                                <br>
                        </div>
                        <div class="FormElement">
                                <input name="Update" type="submit" class="button" id="Update" value="Submit Changes">
                        </div>
                </form>
        </div>
        <div class="RightBody">
                <form id="form2" name="form2" method="post" enctype="multipart/form-data">
                        <p><h3>Skills:</h3>
        <?php

        //advice given from stackoverflow. Suggests looping around the results of this to output 
        $result1 = $con->query("SELECT skills.SkillID, skills.Description, COUNT(userskills.SkillID) AS SkillUserHas, MAX(Experience) AS Experience
                                FROM 
                                (
                                     SELECT 1 AS SkillID, 'Java' AS Description
                                     UNION
                                     SELECT 7 AS SkillID, 'iOS' AS Description
                                     UNION
                                     SELECT 9 AS SkillID, 'PHP' AS Description
                                     UNION
                                     SELECT 3 AS SkillID, 'SQL' AS Description
                                     UNION
                                     SELECT 4 AS SkillID, 'Windows' AS Description
                                     UNION
                                     SELECT 5 AS SkillID, 'Linux' AS Description
                                     UNION
                                     SELECT 6 AS SkillID, 'Unix' AS Description
                                     UNION
                                     SELECT 8 AS SkillID, 'Requirements Elicitation' AS Description
                                ) skills
                                LEFT OUTER JOIN userskills
                                ON skills.SkillID = userskills.SkillID AND userskills.UserID = '$User'
                                GROUP BY skills.SkillID, skills.Description
                                ORDER BY FIELD(skills.SkillID, 1, 7, 9, 3, 4, 5, 6, 8)") 
                                or die(mysqli_error($con));



        while ($skillrow = $result1->fetch_assoc()) 
        {
        ?>
                        <div class="CheckboxText">
                        <?php
                            echo '<label>';
                            echo '<input type="checkbox" name="'.$skillrow['Description'].'" id="CheckboxGroup1_'.$skillrow['SkillID'].'" class="skillselect" value="yes" '.(($skillrow['SkillUserHas'] > 0) ? 'checked' : '').'>';
                            echo $skillrow['Description'].'</label>';
                            echo '<input type="number" name="'.$skillrow['Description'].'exp" class="expnumber" placeholder="Enter Experience in years." value="'.$skillrow['Experience'].'">';
                            echo '<br />';
                            echo '<br />';

                         } 
                         ?>
                        </div>
                        </p>
                </form>
        </div>
        <div class="Footer">
                <footer class="footer-basic-centered">
                        <p class="footer-company-motto">We Always Believe</p>
                        <p class="footer-links"> <a href="Home.php">Home</a> · <a href="Account.php">Account</a> · <a href="Projects.php">Projects</a> · <a href="Users.php">Users</a> · <a href="LogOut.php">LogOut</a> </p>
                        <p class="footer-company-name">Project Mainframe &copy; 2016</p>
                </footer>
        </div>
</div>
</body>
</html>

【问题讨论】:

  • stackoverflow.com/questions/561066/… 可能是给定链接的副本..
  • @ameenulla0007 是的,如果可以,请关闭投票。 :)
  • 这一行$current_skills[] = $skillrow; 正在内存中构建一个大数组......数组占用大量内存......为什么不能在读取时简单地处理每条记录呢?
  • 目前我的查询只有 3 行要添加到数组中,所以肯定不会那么大吗?
  • 一个用户可以拥有多少技能?我希望相对较少(即,不是成千上万),所以我希望不需要太多的存储空间。但是如果有很多,那么它将迅速耗尽内存(并且可能表明您有一个允许插入大量重复记录的错误)。也不需要存储它,因为您可以直接循环结果集以输出行。您那里似乎也有大量重复的代码。

标签: php mysql sql mysqli memory-limit


【解决方案1】:

快速尝试清理代码。这只是使用技能的编码列表,而不是将它们存储在表格上,但希望能给您一些想法。

如果技能表将用户 ID/技能 ID 作为唯一索引,则可以做得更好,然后您可以只执行 INSERT / on duplicate key update 而不是尝试读取值来决定是插入还是更新记录

<?php 

error_reporting(E_ALL); ini_set('display_errors', 1); 
require 'Assets/Connections/Connections.php';
session_start(); 
    if(isset($_SESSION["UserID"]))
    {
    }
    else
    {
        header('Location: LogIn.php');
        die();
    }

    $User = (int)$_SESSION["UserID"];

    $result = $con->query("SELECT * FROM user WHERE UserID ='$User'") or die(mysqli_error($con));

    $row = $result->fetch_array(MYSQLI_BOTH);

    $_SESSION["FirstName"] = $row['Fname'];
    $_SESSION["LastName"] = $row['Lname'];
    $_SESSION["Email"] = $row['Email'];
    $_SESSION["Role"] = $row['JobRole'];

    $skills_array = array(1=>'Java',
                        7=>'iOS',
                        9=>'PHP',
                        3=>'SQL',
                        4=>'Windows',
                        5=>'Linux',
                        6=>'Unix',
                        8=>'Requirements Elicitation');

    if(isset($_POST['Update']))
    {

        $UpdateFName = $_SESSION["FirstName"];
        if ($_POST['FirstName'] != '' ) { $UpdateFName = $_POST['FirstName'];}
        $UpdateLName = $_SESSION["LastName"];
        if ($_POST['LastName'] != '' ) { $UpdateLName = $_POST['LastName'];}
        $UpdateEmail = $_SESSION["Email"];
        if ($_POST['Email'] != '' ) { $UpdateEmail = $_POST['Email'];}
        $UpdateRole = $_SESSION["Role"];
        if ($_POST['JobRole'] != '' ) { $UpdateRole = $_POST['JobRole'];}
        $PasswordCheck = $_POST['Password'];
        if(password_verify($PasswordCheck, $row['Password']))
        {

            $sql = $con->query("UPDATE user SET 
                Fname = '{$UpdateFName}', 
                Lname = '{$UpdateLName}', 
                Email = '{$UpdateEmail}', 
                JobRole = '{$UpdateRole}'
            WHERE UserID = $User") or die(mysqli_error($con));

            if(!empty($_FILES['file']['name']))
            {
                $file = basename($_FILES['file']['name']);
                move_uploaded_file($_FILES['file']['tmp_name'], 'Assets/Images/'.$file);
            }

            if(isset($file))
            {
                $sql = $con->query("UPDATE user SET ProfileImage = '".$_FILES['file']['name']."' WHERE UserID = $User") or die(mysqli_error($con));
            }

            $default = 0;

            foreach($skills_array AS $skills_id=>$skills_name)
            {
                if (isset($_POST[$skills_name]))
                {
                    if (empty($_POST[$skills_name.'exp']))
                    {
                        $exp = $default;
                    }
                    else
                    {
                        $exp = $_POST[$skills_name.'exp'];
                    }

                    $sql = $con->query("SELECT count(UserID) as total FROM userskills WHERE UserID = $User AND SkillID = ".$skills_id) or die(mysqli_error($con));

                    if ($row = mysqli_fetch_assoc($sql))
                    {
                        $sql = $con->query("INSERT INTO userskills ( UserID, SkillID, Experience) VALUES  ($User, $skills_id, $exp)");
                        //If the checkbox is not checked it will check to see if skill is already a skill assigned to the user. If they are it will delete it. If not it will ignore.   
                    }
                    else
                    {
                        $sql = $con->query("UPDATE userskills SET Experience = $exp WHERE UserID = $User AND SkillID $skills_id");
                    }
                } 
                else
                {
                    $sql = $con->query("DELETE FROM userskills WHERE UserID = $User AND SkillID = ".$skills_id);
                }
            }

            header('Location: Account.php');
            die();
        }
        else
        {
            echo 'Incorrect password please try again.';
        }
    }
?>
<!doctype html>
<html>
<head>
<link href="Assets/CSS/Master.css" rel="stylesheet" type="text/css" />
<link href="Assets/CSS/Menu.css" rel="stylesheet" type="text/css" />
<meta charset="utf-8">
<title>Update Account</title>
</head>

<body>
    <div class="Container">
        <div class="Header">
        </div>
        <div class="Menu">
            <div id="Menu">
                <nav>
                    <ul class="cssmenu">
                        <li><a href="Home.php">Home</a></li>
                        <li><a href="Account.php">Account</a></li>
                        <li><a href="Projects.php">Projects</a></li>
                        <li><a href="Users.php">Users</a></li>
                        <li><a href="LogOut.php">LogOut</a></li>
                    </ul>
                </nav>
            </div>
        </div>
        <div class="LeftBody"></div>
        <div class="RightBody">
            <form id="form1" name="form1" method="post" enctype="multipart/form-data">
                <div class="FormElement">
                    <input name="FirstName" type="text" class="TField" id="FirstName" placeholder="First Name" value="<?php echo $_SESSION["FirstName"]; ?>">
                </div>
                <div class="FormElement">
                    <input name="LastName" type="text" class="TField" id="LastName" placeholder="Last Name" value="<?php echo $_SESSION["LastName"]; ?>">
                </div>
                <div class="FormElement">
                    <input name="Email" type="email" class="TField" id="Email" placeholder="Email Address" value="<?php echo $_SESSION["Email"]; ?>">
                </div>
                <div class="FormElement">
                    <input name="JobRole" type="text" class="TField" id="JobRole" placeholder="Job Role" value="<?php echo $_SESSION["Role"]; ?>">
                </div>
                <div class="FormElement">
                    <input name="Password" type="password" class="TField" id="Password" placeholder="Password" required="requried">
                </div>
                <div class="FormElement">
                    <input type="file" name="file">
                <br />
                <br />
                </div>
                <p>
                    <?php

                        $result1 = $con->query("SELECT all_skills.SkillID, all_skills.SkillName, COUNT(userskills.SkillID) AS SkillKnown, MAX(Experience) AS Experience
                                                FROM 
                                                (
                                                    SELECT 1 AS SkillID, 'Java' AS SkillName
                                                    UNION
                                                    SELECT 7 AS SkillID, 'iOS' AS SkillName
                                                    UNION
                                                    SELECT 9 AS SkillID, 'PHP' AS SkillName
                                                    UNION
                                                    SELECT 3 AS SkillID, 'SQL' AS SkillName
                                                    UNION
                                                    SELECT 4 AS SkillID, 'Windows' AS SkillName
                                                    UNION
                                                    SELECT 5 AS SkillID, 'Linux' AS SkillName
                                                    UNION
                                                    SELECT 6 AS SkillID, 'Unix' AS SkillName
                                                    UNION
                                                    SELECT 8 AS SkillID, 'Requirements Elicitation'
                                                ) all_skills
                                                LEFT OUTER JOIN userskills 
                                                ON all_skills.SkillID = userskills.SkillID AND userskills.UserID = '$User' 
                                                GROUP BY all_skills.SkillID, all_skills.SkillName
                                                ORDER BY FIELD(all_skills.SkillID, 1, 7, 9, 3, 4, 5, 6, 8") or die(mysqli_error($con));

                        while ($skillrow = mysqli_fetch_array($result1, MYSQLI_ASSOC))
                        {
                            echo '<label>';
                            echo '<input type="checkbox" name="'.$skillrow['SkillName'].'" id="CheckboxGroup1_'.$skillrow['SkillID'].'" class="skillselect" value="yes" '.(($skillrow['SkillKnown'] > 0) ? 'checked' : '').'>';
                            echo $skillrow['SkillName'].'</label>';
                            echo '<input type="number" name="'.$skillrow['SkillName'].'exp" class="expnumber" placeholder="Enter Experience in years." value="'.$skillrow['Experience'].'">';
                            echo '<br />';
                            echo '<br />';
                        }

                    ?>
                </p>
                <div class="FormElement">
                    <input name="Update" type="submit" class="button" id="Update" value="Submit Changes">
                </div>
            </form>
        </div>
        <div class="Footer">
            <footer class="footer-basic-centered">
                <p class="footer-company-motto">We Always Believe</p>
                <p class="footer-links"> <a href="Home.php">Home</a> · <a href="Account.php">Account</a> · <a href="Projects.php">Projects</a> · <a href="Users.php">Users</a> · <a href="LogOut.php">LogOut</a> </p>
                <p class="footer-company-name">Project Mainframe &copy; 2016</p>
            </footer>
        </div>
    </div>
</body>
</html>

【讨论】:

  • 用户 ID 和技能 ID 是 userskills 表中的外键。我可以执行“插入/重复键更新而不是尝试读取值来决定是插入还是更新记录”吗?另请参阅上面的更新代码。
  • 要使用它,您需要一个涵盖这两列的唯一索引(即,一个涵盖两列的索引)。这可能不会给你带来问题。脚本现在没有明显错误,但需要测试(毫无疑问,我有一些错字!)。
  • 我非常感谢您为帮助我解决这个问题所付出的时间和精力,顶级人物!我还有一个问题要问你……我的技能没有被添加到表格中,但是如果我直接使用脚本添加它们,它们就会被删除。这让我相信变量 $skills_name 可能有问题?
  • 我可以看到 2 个小问题。首先在顶部,当您将 3 个表连接在一起以获得用户技能时,您需要 LEFT OUTER JOIN 用户技能表(因为您想要为该用户的每个可能的技能提供一行,无论他们是否拥有,然后只有如果用户具有该技能,则来自 userskills 的位)。其次,您将 $skills_array 填充为数组数组,但是当您循环遍历它时,您只需将其视为数组。您可能应该修改最后一个 SELECT 以使用技能表以避免对技能进行硬编码。
【解决方案2】:

请注意,根据文档,如果结果集中没有其他行,mysqli_fetch_array 将返回 NULL。您正在专门检查假而不是等同于假的东西。所以你有一个无限循环。将其更改为以下作为短期修复,直到您更正其他问题:-

while (($skillrow = mysqli_fetch_array($result1, MYSQLI_NUM)) != false)
{
    $current_skills[] = $skillrow;
}

将其余部分作为答案,虽然它更像是评论,但太长了。

你的代码有大量的重复代码。

例如,您为每种不同的技能执行以下几乎相同的代码:-

        //If the Unix checkbox is checked it will check to see if Unix is already a skill assigned to the user. If so it will ignore, if not it will add.   
    if (isset($_POST['unix'])){
        if (empty($_POST['unixexp'])){
            $unixexp = $default;
            }else{
            $unixexp = $_POST['unixexp'];}

        $sql = $con->query("SELECT count(UserID) as total FROM userskills WHERE UserID = $User AND SkillID = 6") 
        or die(mysqli_error($con));

        $row = mysqli_fetch_assoc($sql);

        if ($row ['total'] == "0"){

        $sql = $con->query("INSERT INTO userskills ( UserID, SkillID, Experience) VALUES  ($User, 6, $unixexp)");

    //If the Unix checkbox is not checked it will check to see if Unix is already a skill assigned to the user. If they are it will delete it. If not it will ignore.   
    }} else{

        $sql = $con->query("SELECT count(UserID) as total FROM userskills WHERE UserID = $User AND SkillID = 6") 
        or die(mysqli_error($con));

        $row = mysqli_fetch_assoc($sql);

        if ($row ['total'] == "1"){

        $sql = $con->query("DELETE FROM userskills 
        WHERE UserID = $User AND SkillID = 6");
        }}

这可以通过循环一系列技能来轻松完成,或者更好地循环存储这些技能的表的查询结果。这将使代码更短、更简单且更易于维护(因为将来您可以将新技能添加到顶部的数组中,或者更好地添加到技能表中,而根本不必更改脚本本身)。

此外,如果您有一个技能表,您可以查询用户技能:-

SELECT a.SkillID, a.SkillName, COUNT(b.SkillID) AS SkillUserHas
FROM all_skills a
LEFT OUTER JOIN auserskills b
ON a.SkillID = b.SkillID
AND b.UserID = '$User'
GROUP BY a.SkillID, a.SkillName 

然后你可以循环这个结果以输出复选框列表供用户勾选/取消勾选技能(这将返回每个技能 1 行,无论用户是否拥有它,以及一列将如果他们没有该技能,则为 0,如果为他们记录了该技能,则 >= 1)。

请注意,您似乎也对变量进行了零清理。您需要使用 mysqli_real_escape_string 或等效项,否则结果可能会很糟糕,因为用户可能会沉迷于 SQL 注入。

【讨论】:

    猜你喜欢
    • 2011-09-27
    • 2015-03-08
    • 1970-01-01
    • 1970-01-01
    • 2014-01-04
    • 2012-09-26
    • 2011-04-10
    • 1970-01-01
    • 2018-08-01
    相关资源
    最近更新 更多