Solved

PHP Fatal error, out of memory

Posted on 2011-09-26
7
363 Views
Last Modified: 2012-05-12
I am trying to run a PHP script that parses an XML file and inserts into a database in the same directory.  It runs find on my system but when I move it to the server, I get the following error.  How do I fix?

Fatal error: Out of memory (allocated 17563648) (tried to allocate 17043391 bytes) in /home/directory/lib55as.xml.php on line 122

Open in new window


on line 122 of this file, I have the following:

		// format source;
		if($typeof == NULL)
			$data = $src;
		elseif($typeof == 'FILE') {
			$fop  = @fopen($src, 'r');
			$data = "";
			if ($fop) {
				while(!feof($fop))
					$data .= fgets($fop, 4096);  // Line 22 here
						
			}
			@fclose($fop);
		}

Open in new window



Here is a copy of the entire function including line 122:

	/**
	 * parse
	 * Set the parser Xml and theses options.
	 * Xml file could be a string, a file, or curl.
	 * When the source is loaded, we run the parse.
	 * After, we clean all the memory and variables,
	 * and return the result in an array.
	 *
	 * @access  public
	 * @param   src       string    Source
	 * @param   typeof    string    Source type : NULL, FILE, CURL.
	 * @param   encoding  string    Encoding type.
	 * @return  array
	 */
	function parse ( $src, $typeof = 'FILE', $encoding = 'UTF-8' ) {

		// ini;
		// (re)set array;
		$this->pOut = array();
		$this->parser = xml_parser_create();

		xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
		xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $encoding);

		xml_set_object($this->parser, $this);
		xml_set_element_handler($this->parser, 'startHandler', 'endHandler');
		xml_set_character_data_handler($this->parser, 'contentHandler');

		if(empty($src))
			trigger_error('Source could not be empty.', E_USER_ERROR);     

		// format source;
		if($typeof == NULL)
			$data = $src;
		elseif($typeof == 'FILE') {
			$fop  = @fopen($src, 'r');
			$data = "";
			if ($fop) {
				while(!feof($fop))
					$data .= fgets($fop, 4096);  // Line 122 here
						
			}
			@fclose($fop);
		}
		elseif($typeof == 'CURL') {
			$curl = curl_init();
			curl_setopt($curl, CURLOPT_URL, $src);
			curl_setopt($curl, CURLOPT_HEADER, 0);
			$data = curl_exec($curl);
			curl_close($curl);
		}
		else
			return trigger_error('Xml parser need data.', E_USER_ERROR);

		if ($data > "") {
			// parse $data;
			$parse = xml_parse($this->parser, $data);
			if(!$parse)
				return trigger_error('XML Error : %s at line %d.', E_USER_ERROR,
					array(xml_error_string(xml_get_error_code($this->parser)),
						xml_get_current_line_number($this->parser)));
	
			// destroy parser;
			xml_parser_free($this->parser);
	
			// unset extra vars;
			unset($data,
				  $this->track,
				  $this->tmpLevel);
	
			// remove global tag and return the result;
			return $this->pOut[0][key($this->pOut[0])];
		} else {
			return "";
		}
			
	}

Open in new window

0
Comment
Question by:pda4me
7 Comments
 
LVL 6

Accepted Solution

by:
neorush earned 500 total points
ID: 36657397
The problem is:
$data .= fgets($fop, 4096);
This loads the entire file into $data, if the file is bigger than the memory available to php you will get this error.  This function is written incorrectly for loading the whole file, it should just use file_get_contents() rather than read the file line by line as this would be faster.  But that would still result in an out of memory error since the entire file is saved to memory.

Instead you have to do something with every single line as it is read with fgets().  Which since this function is designed to return the entire XML file as an array, you would have to modify what ever script is calling this function as well.  Its a lot more complicated than just swapping a few lines since this is going to change the application quite a bit.

Two solutions, you have to go back and edit a lot more code than just this function, or you need more ram (memory) on your server.
0
 

Author Comment

by:pda4me
ID: 36660444
thanks neo, both local machine and remote have 8GB of RAM and it works fine on the one system...is it possible there is a setting in apache or php that is limiting the available memory?  Do you know what setting that would be?
0
 
LVL 6

Expert Comment

by:neorush
ID: 36662116
yes, there are limits per script set in php.ini
you can find a line like this in php.ini
memory_limit = 16M ;

you can also try adding a flag in a .htaccess file to change it:
php_value memory_limit 16M

or you can try changing it with php code:
<?php
ini_set('memory_limit', '16M');
?>

just change 16M to however many megabytes of memory you want available for the script.
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 6

Expert Comment

by:neorush
ID: 36664475
I should also clarify the diffences in the above:
Changes memory for every page on the entire server:
memory_limit = 16M ;

Changesmemory  for every page in the current directory and any subdirectories:
php_value memory_limit 16M

Changes memory for the current script:
ini_set('memory_limit', '16M');

So naturally you'll want to work backwards with these.  e.g. see if you can just change it for the script, then see if you need to change it for the directory, and finally change it for the entire server.
0
 
LVL 7

Expert Comment

by:boon86
ID: 36712310
you might increase it to higher value such as:

memory_limit = 512M

since you have 8GB RAM
0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 36713874
You might want to post either the input data or a link to the input data.  At EE we have seen lots of code that does not work, but given the input data and a clear description of the desired outputs we are sometimes able to create code that does work.

The man page references about memory sizes are available here.
http://php.net/manual/en/ini.core.php
http://php.net/manual/en/function.memory-get-peak-usage.php
http://php.net/manual/en/function.memory-get-usage.php
0
 

Author Closing Comment

by:pda4me
ID: 36717813
Thanks!
0

Featured Post

Control application downtime with dependency maps

Visualize the interdependencies between application components better with Applications Manager's automated application discovery and dependency mapping feature. Resolve performance issues faster by quickly isolating problematic components.

Join & Write a Comment

Developers of all skill levels should learn to use current best practices when developing websites. However many developers, new and old, fall into the trap of using deprecated features because this is what so many tutorials and books tell them to u…
Password hashing is better than message digests or encryption, and you should be using it instead of message digests or encryption.  Find out why and how in this article, which supplements the original article on PHP Client Registration, Login, Logo…
Learn how to match and substitute tagged data using PHP regular expressions. Demonstrated on Windows 7, but also applies to other operating systems. Demonstrated technique applies to PHP (all versions) and Firefox, but very similar techniques will w…
The viewer will learn how to create and use a small PHP class to apply a watermark to an image. This video shows the viewer the setup for the PHP watermark as well as important coding language. Continue to Part 2 to learn the core code used in creat…

747 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

9 Experts available now in Live!

Get 1:1 Help Now