繁体   English   中英

PHP脚本内存不足

[英]PHP script is running out of memory

我写了下面的PHP脚本(语法1.4任务),该脚本遍历CSV文件,然后通过Doctrine将数据导入MySQL。

不幸的是,脚本被中止,因为它分配了很多内存。 使用的内存随着每个foreach周期的增长而增加。 我尝试了很多事情,但是无法使使用的内存更稳定。

有人可以给我一个提示吗?

<?php 
class importERPTask extends sfBaseTask
{
protected function configure()
{
    $this->addOptions(array(
        new sfCommandOption('application', null, sfCommandOption::PARAMETER_REQUIRED, 'The application name', 'frontend'),
        new sfCommandOption('env', null, sfCommandOption::PARAMETER_REQUIRED, 'The environment', 'dev'),
        new sfCommandOption('connection', null, sfCommandOption::PARAMETER_REQUIRED, 'The connection name', 'doctrine'),
        // add your own options here
    ));

    $this->namespace                = 'w2';
    $this->name                         = 'importERP';
    $this->briefDescription = 'Imports product data .';
}

public function execute($arguments = array(), $options = array())
{
    // initialize the database connection
    $databaseManager = new sfDatabaseManager($this->configuration);
    $connection = $databaseManager->getDatabase($options['connection'])->getConnection();

    $this->logSection('importERP', 'Start');
    if(!(file_exists(sfConfig::get('sf_root_dir'). DIRECTORY_SEPARATOR .'import_data'.DIRECTORY_SEPARATOR.'VK.csv') && file_exists(sfConfig::get('sf_root_dir'). DIRECTORY_SEPARATOR .'import_data'.DIRECTORY_SEPARATOR.'Artikel.csv')))
    {
        $this->logSection('importERP', 'No import CSV');
        $this->logSection('importERP', 'Done.');
        return;
    }

    $this->importPrices();

    //import products
    $this->logSection('importERP', 'Import products');

    Doctrine::getTable('CatalogueProduct')->setAllImportFalse();

    $file_handle = fopen(sfConfig::get('sf_root_dir'). DIRECTORY_SEPARATOR .'import_data'.DIRECTORY_SEPARATOR.'Artikel.csv', 'r');
    if($file_handle)
    {
        $i = 0;
        while(!feof($file_handle))
        {
            //skip first line
            if(++$i == 1)
            {
                continue;
            }
            $this->importProduct($file_handle);
        }
        fclose($file_handle);
    }

    $this->deleteProducts();

    unlink(sfConfig::get('sf_root_dir'). DIRECTORY_SEPARATOR .'import_data'.DIRECTORY_SEPARATOR.'VK.csv');
    unlink(sfConfig::get('sf_root_dir'). DIRECTORY_SEPARATOR .'import_data'.DIRECTORY_SEPARATOR.'Artikel.csv');
    $this->logSection('importERP', 'Done.');
}

private function importPrices()
{
    //import price helper table
    $this->logSection('importERP', 'Import price helper table');

    Doctrine::getTable('ImportHelperPrice')->clearAllData();
    $file_handle = fopen(sfConfig::get('sf_root_dir'). DIRECTORY_SEPARATOR .'import_data'.DIRECTORY_SEPARATOR.'VK.csv', 'r');
    if($file_handle)
    {
        $i = 0;
        while(!feof($file_handle))
        {
            $line_of_text = fgetcsv($file_handle, 0, ';', '"');

            //skip first line
            if(++$i == 1)
            {
                continue;
            }

            $price = new ImportHelperPrice();
            $price->setImportId($line_of_text[0]);
            $price->setStartAmount($line_of_text[1]);
            $price->setPrice(str_replace(',', '.', $line_of_text[2]));
            $price->save();
        }
    }
}

private function importProduct($file_handle)
{
    $line_of_text = fgetcsv($file_handle, 0, ';', '"');

    $this->logSection('importERP', 'Import product '.$line_of_text[1]);
    //no empty article number
    if($line_of_text[0] == '')
    {
        $this->logSection('importERP', '... skipped');
        return;
    }

    if($line_of_text[4] == '')
    {
        $this->logSection('importERP', '... has no category');
        return;
    }
    $my_product = Doctrine::getTable('CatalogueProduct')->findOneByCode($line_of_text[0]);
    $my_cat = Doctrine::getTable('CatalogueCategory')->findOneByImportCode($line_of_text[4]);
    if(!$my_cat)
    {
        $this->logSection('importERP', '... has no category');
        return;
    }
    if(!$my_product)
    {
        $this->logSection('importERP', '... is new');
        $my_product = new CatalogueProduct();
        $my_product->setCode($line_of_text[0]);

        // do not overwrite handmade configurations from backend
        $my_product->setVatId(1);
        $my_product->setTemplateId(4);
    }
    else
    {
        $this->logSection('importERP', '... is updated');
    }

    //get prices
    $price = Doctrine::getTable('ImportHelperPrice')->getPriceForImportId($line_of_text[0]);
    if(!$price)
    {
        return;
    }

    $my_product->setPriceGrossEur($price->getPrice());
    $my_product->Translation['de']->title = $line_of_text[2];
    $my_product->Translation['de']->shortdescription = $line_of_text[3];
    $my_product->Translation['de']->description =$line_of_text[3];
    $my_product->setCatalogueCategory($my_cat);
    $my_product->setHidden(false);
    $my_product->setImportFlag(true);

    $config_prices = Doctrine::getTable('ImportHelperPrice')->getPriceConfigForImportId($line_of_text[0]);
    if($config_prices)
    {
        $price_config = '';
        foreach($config_prices as $cp)
        {
            $discount = 100 - ($cp->getPrice() / ($price->getPrice() / 100));
            if($discount == 0)
            {
                continue;
            }
            if($price_config != '')
            {
                $price_config .= ';';
            }
            $price_config .= $cp->getStartAmount() . ':' . number_format($discount, 2, ',', '');
        }
        $my_product->setPriceConfig($price_config);
    }


    //move images
    $img_default = sfConfig::get('sf_root_dir'). DIRECTORY_SEPARATOR .'import_data'.DIRECTORY_SEPARATOR.'images'.DIRECTORY_SEPARATOR.$line_of_text[1].'_m.jpg';
    if(file_exists($img_default))
    {
        rename($img_default, sfConfig::get('sf_web_dir').DIRECTORY_SEPARATOR.'products'.DIRECTORY_SEPARATOR.$line_of_text[1].'_m.jpg');
        $my_product->setImageDefault($line_of_text[1].'_m.jpg');
        $this->logSection('importERP', '... '.$my_product->getImageDefault().' saved');
    }
    else
    {
        $this->logSection('importERP', '... '.$img_default.' not found');
    }
    $img_zoom = sfConfig::get('sf_root_dir'). DIRECTORY_SEPARATOR .'import_data'.DIRECTORY_SEPARATOR.'images'.DIRECTORY_SEPARATOR.$line_of_text[1].'_gr.jpg';
    if(file_exists($img_zoom))
    {
        rename($img_zoom, sfConfig::get('sf_web_dir').DIRECTORY_SEPARATOR.'products'.DIRECTORY_SEPARATOR.$line_of_text[1].'_zoom.jpg');
        $my_product->setImageZoom($line_of_text[1].'_zoom.jpg');
        $this->logSection('importERP', '... '.$my_product->getImageZoom().' saved');
    }
    else
    {
        $this->logSection('importERP', '... '.$img_zoom.' not found');
    }
    $img_icon = sfConfig::get('sf_root_dir'). DIRECTORY_SEPARATOR .'import_data'.DIRECTORY_SEPARATOR.'images'.DIRECTORY_SEPARATOR.$line_of_text[1].'_kl.jpg';
    if(file_exists($img_icon))
    {
        rename($img_icon, sfConfig::get('sf_web_dir').DIRECTORY_SEPARATOR.'products'.DIRECTORY_SEPARATOR.$line_of_text[1].'_icon.jpg');
        $my_product->setImageIcon($line_of_text[1].'_icon.jpg');
        $this->logSection('importERP', '... '.$my_product->getImageIcon().' saved');
    }
    else
    {
        $this->logSection('importERP', '... '.$img_icon.' not found');
    }

    $my_product->save();

    $this->logSection('importERP', 'Memory usage '.memory_get_peak_usage() / 1048576,2 .' MB');
}

private function deleteProducts()
{
    //delete not mentioned products
    $this->logSection('importERP', 'Delete not mentioned products');
    $del_products = Doctrine::getTable('CatalogueProduct')->getAllImportFalse();
    foreach($del_products as $dp)
    {
        $this->logSection('importERP', 'Delete '.$dp->getCode());

        //delete images
        $img_default = sfConfig::get('sf_web_dir').DIRECTORY_SEPARATOR.'products'.DIRECTORY_SEPARATOR.$dp->getImageDefault();
        $img_zoom = sfConfig::get('sf_web_dir').DIRECTORY_SEPARATOR.'products'.DIRECTORY_SEPARATOR.$dp->getImageZoom();
        $img_icon = sfConfig::get('sf_web_dir').DIRECTORY_SEPARATOR.'products'.DIRECTORY_SEPARATOR.$dp->getImageIcon();
        if($dp->getImageDefault() != NULL && $dp->getImageDefault() != '' && file_exists($img_default))
        {
            unlink($img_default);
        }
        if($dp->getImageZoom() != NULL && $dp->getImageZoom() != '' && file_exists($img_zoom))
        {
            unlink($img_zoom);
        }
        if($dp->getImageIcon() != NULL && $dp->getImageIcon() != '' && file_exists($img_icon))
        {
            unlink($img_icon);
        }

        //delete product
        $dp->delete();
    }
}
}

最好的解决方案是编辑您的php.ini文件。 分配:

memory_limit = 16M

不确定16M是否为默认值,但应该将其关闭。 无论如何,这就是允许PHP脚本使用的内存量。 您可以将此数字设置得更高一些并解决问题。

或者,您可以在PHP脚本的顶部编写此代码:

ini_set('memory_limit', '16M');

可以将16M更改为您希望脚本允许的任何内存量。

注意ini_sets的值以'M'结尾-它们不能按预期工作。 速记符号仅在php.ini中有效,适当的信息包含在文档中: http : //php.net/manual/zh/faq.using.php#faq.using.shorthandbytes

你应该做:

...
$my_product->save();
$my_product->free();
unset($my_product);
...

假设您的CSV太大了,服务器无法一sw而就地处理内存,我会考虑将CSV拆分成较小的文件,这对于Unix命令(拆分等)来说是非常简单的任务。

然后,您将使用PHP脚本异步执行每个bitesize CSV。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM