homepage Welcome to WebmasterWorld Guest from 23.22.179.210
register, free tools, login, search, subscribe, help, library, announcements, recent posts, open posts,
Pubcon Platinum Sponsor 2014
Visit PubCon.com
Home / Forums Index / Code, Content, and Presentation / PHP Server Side Scripting
Forum Library, Charter, Moderators: coopster & jatar k

PHP Server Side Scripting Forum

    
PHP Cron Job Timeout (Memory issue)
ZakAltF4




msg:4418510
 10:20 pm on Feb 16, 2012 (gmt 0)

I have written a script to dynamically write our Meta descriptions and keywords .. My issue that I am having is that I am receiving a PHP memory error. Granted this is when trying to run the script from the browser. I don't have control over the PHP memory settings, however according to our Dedicated Host it is set to 1024MB. Will running this cron off the server still generate this error? If so, is there a way that any of you can see that I can reduce the amount of memory used for the following script?

Some background info: There are some 15,000 products that reside in over 700 categories ...


<?php
//This script takes individual product/category info and generates more narrowed meta data ...

$mageFilename = $_SERVER['DOCUMENT_ROOT'] . '/app/Mage.php';
require_once $mageFilename;
umask(0);
Mage::app('-- snip --_english'); // change to admin possibly
Mage::setIsDeveloperMode(true);
ini_set('display_errors',1);
echo "####################################### Start ###################################<br>";
?>

<?php
$collection = Mage::getModel('catalog/category')->getCollection();
$collection->addAttributeToSelect('*');
$counter = 0;
foreach ($collection as $element) {
$category_name = $element->getName();
$category_id = $element->getId();
if ($counter == 99999) { break; } // Set to 3 for testing
if ($counter !== 0 && $counter !== 1)
{
echo $category_name . " " . $category_id . "<br>"; // Do stuff here
$mArray = array();
$category = new Mage_Catalog_Model_Category();
//$category->getResource()->getAttribute('description');

$loaded = $category->load($category_id);
$collection1 = $loaded->getProductCollection();
$pc = 0;
foreach ($collection1 as $product) {
// var_dump($product) . "<br><br>";
//if ($pc < 4){
$pid = $product->getId();
$model = Mage::getModel('catalog/product'); //getting product model
$_product = $model->load($pid);

//##################################


$result = $_product->getName();
$result = preg_replace('/\ - .*/', '', $result);

array_push($mArray, $result);
$acv=array_count_values($mArray); // 1=>2, 2=>3,3=>1
arsort($acv); //save keys, 2=>3, 1=>2, 3=>1
$result=array_keys($acv);

//###################################

$pc++;
// }
}
$kw = $category_name; //get name
$ds = "";
if (isset($result[0])){
$kw = $kw . ", " . $result[0];
$ds = $ds . ", " . $result[0];
}
if (isset($result[1])){
$kw = $kw . ", " . $result[1];
$ds = $ds . ", " . $result[1];
}
if (isset($result[2])){
$kw = $kw . ", " . $result[2];
$ds = $ds . ", " . $result[2];
}
if (isset($result[3])){
$kw = $kw . ", " . $result[3];
$ds = $ds . ", " . $result[3];
}
if (isset($result[4])){
$kw = $kw . ", " . $result[4];
$ds = $ds . ", " . $result[4];
}

$kw = $kw . ", Natural, Organic, Healthy, Green";
$kw = preg_replace('/[^a-z0-9]/i', ' ', $kw);
try
{
$resource = Mage::getSingleton('core/resource');
$writeConnection = $resource->getConnection('core_write');
$table = "catalog_category_flat_store_1";
$query = "UPDATE {$table} SET meta_keywords = '{$kw}' WHERE entity_id = $category_id" ;
$writeConnection->query($query);

}
catch(Exception $e)
{
echo $e;
}

$ds = "In " . $category_name . " , enjoy brands like " . $ds . "! Live eco-friendly with -- Snip -- !" ;
$ds = preg_replace('/[^a-z0-9]/i', ' ', $ds);
try
{
$resource = Mage::getSingleton('core/resource');
$writeConnection = $resource->getConnection('core_write');
$table = "catalog_category_flat_store_1";
$query = "UPDATE {$table} SET meta_description = '{$ds}' WHERE entity_id = $category_id" ;
$writeConnection->query($query);

}
catch(Exception $e)
{
echo $e;
}

}
$counter++;
}
?>

<?php
echo "####################################### End ###################################<br>";
?>


The error being generated is:



Fatal error: Allowed memory size of 1073741824 bytes exhausted (tried to allocate 71 bytes)



Yeah .. Finally get it working, only to find out it needs to run more efficiently!

 

rocknbil




msg:4418872
 5:33 pm on Feb 17, 2012 (gmt 0)

This is exactly why I don't like to use frameworks or some OOP based classes - often you don't know what it's really doing "behind the scenes" and it may be using more resources than necessary.

I don't have control over the PHP memory settings, however according to our Dedicated Host


Something is wrong there, if it's a dedicated host you should have control over it. But if it's using up 1024MB, something is definitely being selfish. That's a whole GB of memory. Wow.

First I'd look at this:

1) $collection = Mage::getModel('catalog/category')->getCollection();
2) $collection->addAttributeToSelect('*');
3) foreach ($collection as $element) {
4) $category = new Mage_Catalog_Model_Category();
4a) $collection1 = $loaded->getProductCollection();
5) foreach ($collection1 as $product) {
...
6)array_push($mArray, $result);

1: What this **appears** to be doing is pushing the entire product database into a $collection1 object, is this correct? Keep in mind that in the bowels of your class, it's probably doing something like

$result = mysql_query($query);

So here you have the database results stored in $result, then returned from the class and stored in $collection, so basically you have the entire database stored in memory twice (this is not "for sure," an efficient class would destroy it's internal values once passed on . . but it's a thought.)

2: Do you REALLY need all fields? (guessing no.) * is highly inefficient, select only fields you need. The memory hoggage may be shared between your script AND mysql.
3: Then you loop through the entire collection - 15,000 items - stored in memory.
4/4a: Then you create another object within this for loop,
5): then create ANOTHER array in which to store the meta description

If you're storing data for 15,000 in memory, you can see how that could hog it up. Can you devise a way to pass a limit to this class, maybe do the steps in chunks of 10 records each? It may run a little longer but won't use up as much memory.

The "best" answer, of course, would be that you shouldn't be doing this at all. You should have the meta description and keyword fields editable in the product edit and handle it manually there, or at the time of product creation. But anyway . . .

What I'd do is skip all the classes and OOP, if all you want to do is generate keyword descriptions,

$query = "select id,title,product_description from products";
$result = mysql_query($query);
while (list($id,$t,$desc)=mysql_fetch_array($result)) {
$query = "update products set meta_desc='$t, $desc' where id=$id";
mysql_query($query);
}


That's probably a simplified example and not exactly what you need, but you get the idea. You don't need a sledgehammer to smack a fly. :-)

Note I've "recycled" the variable $query, as once it's executed outside the loop I don't need it's previous value to persist, hence I can use that space in memory within the loop. Not doing this would be more or less a "common approach," creating new variables when you don't need to, using more memory.

Global Options:
 top home search open messages active posts  
 

Home / Forums Index / Code, Content, and Presentation / PHP Server Side Scripting
rss feed

All trademarks and copyrights held by respective owners. Member comments are owned by the poster.
Home ¦ Free Tools ¦ Terms of Service ¦ Privacy Policy ¦ Report Problem ¦ About ¦ Library ¦ Newsletter
WebmasterWorld is a Developer Shed Community owned by Jim Boykin.
© Webmaster World 1996-2014 all rights reserved