我编写了以下PHP脚本(symphony 1.4 Task),它循环遍历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();
}
}
}
答案 0 :(得分:0)
最好的解决方案是编辑php.ini文件。分配:
memory_limit = 16M
不确定16M是否为默认值但应该关闭。无论如何,这是允许PHP脚本使用的内存量。您可以将此数字设置得更高并解决问题。
或者,您可以在PHP脚本的顶部写下这个:
ini_set('memory_limit', '16M');
其中16M可以更改为您希望脚本允许的任何内存量。
答案 1 :(得分:0)
注意ini_sets,其值以“M”结尾 - 它们无法按预期工作。速记符号仅适用于php.ini,相应的信息包含在文档中:http://php.net/manual/en/faq.using.php#faq.using.shorthandbytes
答案 2 :(得分:0)
你应该这样做:
...
$my_product->save();
$my_product->free();
unset($my_product);
...
答案 3 :(得分:0)
假设您的CSV太大,服务器无法一次性处理内存,我会考虑将CSV拆分为较小的文件,这对于Unix命令(拆分等)来说非常简单。
然后,您将使用PHP脚本异步执行每个bitesize CSV。