Неустранимая ошибка допустимого размера памяти; Улучшить сценарий

У меня есть следующая функция, которая возвращает мне отформатированную таблицу, показывающую список браузеров, которые просматривали веб-сайт. Он извлекается из базы данных MySQL и пользовательского агента (я знаю, что это не совсем надежно, но на данный момент этого достаточно).

Однако; эта функция (и другая, которая делает операционную систему из того же пользовательского агента, максимально увеличивает допустимый размер памяти и выдает фатальную ошибку PHP. Я увеличил свой лимит памяти до 100 МБ, а затем проверил memory_get_peak_usage() и два работают около 56 МБ.

Могу ли я что-нибудь сделать с этой функцией (и с ОС, которая не включена, но очень похожа на эту), чтобы улучшить использование памяти?

function getBrowsers() {
    global $stats,$db;
    $overall = $db->select("SELECT * FROM `".$db->prefix."web_stats`");
    /*while($row = $db->get_row($overall)) {
        $table[] = $row["agent"];
    }
    echo "<pre>";
    print_r($table);
    echo "</pre>";*/
    $overall = $db->num_rows($overall);

    $browser_array = array(
                        'msie'      => 'Internet Explorer',
                        'firefox'   => 'Firefox',
                        'safari'    => 'Safari',
                        'chrome'    => 'Chrome',
                        'edge'      => 'Edge',
                        'opera'     => 'Opera',
                        'netscape'  => 'Netscape',
                        'maxthon'   => 'Maxthon',
                        'konqueror' => 'Konqueror',
                        'mobile'    => 'Handheld Browser',
                        'spider'    => 'Search Spider',
                        'AdsBot'    => 'Google AdsBot',
                        'bot'       => 'Bot'
                 );

    

    $data["total"] = 0;
    foreach($browser_array as $value => $key) {
        $count = $this->get_os($value);
        $data[$key] = $count;
        $data["total"] += $count;
    }
    
    //$data["Unkown"] = $overall - $data["total"];
    
    arsort($data, SORT_NUMERIC);
    $table = "
        <table  class='table table-no-more table-bordered table-striped mb-none'>
            <thead>
                <tr>
                    <th>OS</th>
                    <th>Hits</th>
                    <th>Percent</th>
                </tr>
            </thead>
            <tbody>";
    foreach($data as $key => $value) {
        if($key!="total" && $value > 0) {
            $percent = $this->calculateper($value, $overall);
            if(preg_match('/(Chrome)/i', $key) === 1) {
                $icon = '<i class="fab fa-chrome"></i>';                    
            }
            elseif(preg_match('/(FireFox)/i', $key) === 1) {
                $icon = '<i class="fab fa-firefox"></i>';                   
            }
            elseif(preg_match('/(Edge)/i', $key) === 1) {
                $icon = '<i class="fab fa-edge"></i>';                  
            }
            elseif(preg_match('/(Google)/i', $key) === 1) {
                $icon = '<i class="fab fa-google"></i>';                    
            }
            elseif(preg_match('/(Google)/i', $key) === 1) {
                $icon = '<i class="fab fa-google"></i>';                    
            }
            elseif(preg_match('/(bot)/i', $key) === 1) {
                $icon = '<i class="fas fa-robot"></i>';                 
            }
            
            elseif(preg_match('/(Internet Explorer)/i', $key) === 1) {
                $icon = '<i class="fab fa-internet-explorer"></i>';                 
            }
            
            elseif(preg_match('/(Spider)/i', $key) === 1) {
                $icon = '<i class="fas fa-spider"></i>';                    
            }
            
            elseif(preg_match('/(Opera)/i', $key) === 1) {
                $icon = '<i class="fab fa-opera"></i>';                 
            }
            elseif(preg_match('/(Safari)/i', $key) === 1) {
                $icon = '<i class="fab fa-safari"></i>';                    
            }
            else {
                $icon = '<i class="far fa-question-circle"></i>';
            }
            $table .= "<tr>
                <td data-title='OS'>
                    ".$icon." ".$key."
                </td>
                <td data-title='Hits'>
                ".$value."
                </td>
                <td data-title='Percent'>
                    <div class='progress dark m-md'>
                        <div class='progress-bar progress-bar-success' role='progressbar' aria-valuenow='".$percent."' aria-valuemin='0' aria-valuemax='100' style='width: ".$percent."%;'>
                            ".$percent."%
                        </div>
                    </div>
                </td>
                </tr>";
        }
    }
    $table .= '</tbody>
            </table>';

    return $table;
}
//Get counts from the user agent
function get_os($opers) {
    global $stats,$db;
    $sql = "SELECT count(agent) as cnt FROM `".$db->prefix."web_stats` WHERE `agent` LIKE '%$opers%'"; 
    $result = $db->select($sql); 
     while ($row = $db->get_row($result)) { 
        $os1 = $row["cnt"]; 
        return $os1;
     } 
} 

person Dawson Irvine    schedule 30.11.2020    source источник


Ответы (1)


На первый взгляд кажется, что больше всего памяти используется при выполнении первого запроса, поскольку вы загружаете все данные в эту таблицу только для того, чтобы позже подсчитать результаты.

Итак, первым улучшением было бы позволить базе данных вести подсчет, как вы уже сделали для операционных систем:

$stmt = $db->select("SELECT COUNT(*) AS total FROM `".$db->prefix."web_stats`");
$result = $db->get_row($stmt);
$overall = $result['total'];

Второе, что вы должны рассмотреть, это немного отформатировать код, так как он выглядит немного запутанным для меня.

person Mihai Matei    schedule 30.11.2020
comment
Я решил проверить производительность памяти в нескольких других областях, по которым работает статистика. У меня есть аналогичный запрос, который поглощает память, однако я изменил его на что-то похожее на то, что вы предложили, и теперь мой результат далек. $getPass = $db->select("SELECT COUNT(*) as total FROM ".$db->prefix."web_stats GROUP BY ipaddress"); $result = $db->get_row($getPass); echo number_format($result['total']); То, как я вернул 26 910 (что правильно). Использование MySQL COUNT(*) возвращает 7. - person Dawson Irvine; 03.12.2020