PHP File Download Script Problem

  • (3 Pages)
  • +
  • 1
  • 2
  • 3

34 Replies - 2943 Views - Last Post: 17 February 2014 - 09:26 AM Rate Topic: -----

#1 chris98  Icon User is offline

  • D.I.C Lover

Reputation: 40
  • View blog
  • Posts: 1,100
  • Joined: 06-July 13

PHP File Download Script Problem

Posted 04 January 2014 - 07:02 AM

I have recently tried to download a 121 MB file from my website using the below PHP download script, which has failed with the error message below:

<?php
ini_set("memory_limit","128M");
define('PUN_ROOT', dirname(__FILE__).'/../forums/');
include PUN_ROOT.'include/common.php';
if ($pun_user['is_guest'])
    header("location: login.php");
class chip_download {
	
	/*
	|---------------------------
	| Properties
	|---------------------------
	*/
	
	private $download_hook = array();
	
	private $args = array(
						'download_path'			=>	NULL,
						'file'					=>	NULL,						
						'extension_check'		=>	TRUE,
						'referrer_check'		=>	FALSE,	
						'referrer'				=>	NULL,					
					);
	
	private $allowed_extensions = array(
						
						/* Archives */
						'zip'	=> 'application/zip'
					);
	

	/*
	|---------------------------
	| Constructor
	|
	| @public
	| @param array $args
	| @param array $allowed_extensions
	|
	|---------------------------
	*/
	
	public function __construct( $args = array(), $allowed_extensions = array()  ) {
		
		$this->set_args( $args );
		$this->set_allowed_extensions( $allowed_extensions );
						
	}
	
	/*
	|---------------------------
	| Print variable in readable format
	|
	| @public
	| @param string|array|object $var
	|
	|---------------------------
	*/
	
	public function chip_print( $var ) { 
		
		echo "<pre>";
    	print_r($var);
   	 	echo "</pre>";
	
	}
	
	/*
	|---------------------------
	| Update default arguments
	| It will update default array of class i.e $args
	|
	| @private
	| @param array $args - input arguments
	| @param array $defatuls - default arguments 
	| @return array
	|
	|---------------------------
	*/
	
	private function chip_parse_args( $args = array(), $defaults = array() ) { 
		return array_merge( $defaults, $args );	 
	}
	
	/*
	|---------------------------
	| Get extension and name of file
	|
	| @private
	| @param string $file_name 
	| @return array - having file_name and file_ext
	|
	|---------------------------
	*/
	
	private function chip_extension($file_name) {
		$temp = array();
		$temp['file_name'] = strtolower( substr( $file_name, 0, strripos( $file_name, '.' ) ) );
	    $temp['file_extension'] = strtolower( substr( $file_name, strripos( $file_name, '.' ) + 1 ) );
		return $temp;
	}
	
	/*
	|---------------------------
	| Set default arguments
	| It will set default array of class i.e $args
	|
	| @private
	| @param array $args
	| @return 0
	|
	|---------------------------
	*/
	
	private function set_args( $args = array() ) { 
		
		$defaults = $this->get_args();
		$args = $this->chip_parse_args( $args, $defaults );
		$this->args = $args;	 
	}
	
	/*
	|---------------------------
	| Get default arguments
	| It will get default array of class i.e $args
	|
	| @public
	| @return array
	|
	|---------------------------
	*/
	
	public function get_args() { 
		return $this->args;	 
	}
	
	/*
	|---------------------------
	| Set default allowed extensions
	| It will set default array of class i.e $allowed_extensions
	|
	| @private
	| @param array $allowed_extensions
	| @return 0
	|
	|---------------------------
	*/
	
	private function set_allowed_extensions( $allowed_extensions = array() ) { 
		
		$defaults = $this->get_allowed_extensions();
		$allowed_extensions = array_unique( $this->chip_parse_args( $allowed_extensions, $defaults ) );
		$this->allowed_extensions = $allowed_extensions;	 
	
	}
	
	/*
	|---------------------------
	| Get default allowed extensions
	| It will get default array of class i.e $allowed_extensions
	|
	| @public
	| @return array
	|
	|---------------------------
	*/
	
	public function get_allowed_extensions() { 
		return $this->allowed_extensions;	 
	}
	
	/*
	|---------------------------
	| Set Mimi Type
	| It will set default array of class i.e $allowed_extensions
	|
	| @private
	| @param string $file_path
	! @return string
	|
	|---------------------------
	*/
	
	private function set_mime_type( $file_path ) { 
		
		/* by Function - mime_content_type */
		if( function_exists( 'mime_content_type' ) ) {
			$file_mime_type = @mime_content_type( $file_path );
		}
		
		/* by Function - mime_content_type */
		else if( function_exists( 'finfo_file' ) ) {
			
			$finfo = @finfo_open(FILEINFO_MIME);
			$file_mime_type = @finfo_file($finfo, $file_path);
			finfo_close($finfo);  
		
		}
		
		/* Default - FALSE */
		else {
			$file_mime_type = FALSE;
		 }
		 
		 return $file_mime_type;	 
	
	}
	
	/*
	|---------------------------
	| Get Mimi Type
	| It will set default array of class i.e $allowed_extensions
	|
	| @public
	| @param string $file_path
	! @return string
	|
	|---------------------------
	*/
	
	public function get_mime_type( $file_path ) { 
		return $this->set_mime_type( $file_path );	 
	}
	
	/*
	|---------------------------
	| Pre Download Hook
	|
	| @private
	| @return 0
	|
	|---------------------------
	*/
	
	private function set_download_hook() { 
		
		/* Allowed Extensions */
		$allowed_extensions = $this->get_allowed_extensions();
		
		/* Arguments */
		$args = $this->get_args();		
		
		/* Extract Arguments */
		extract($args);
		
		/* Directory Depth */
		$dir_depth = dirname( $file );
		if ( !empty( $dir_depth ) && $dir_depth != "." ) {
			$download_path = $download_path . $dir_depth . "/";
		} 
		
		/* File Name */
		$file = basename( $file );
		
		/* File Path */
		$file_path = $download_path . $file;
		$this->download_hook['file_path'] = $file_path;
		
		/* File and File Path Validation */
		if( empty( $file ) || !file_exists( $file_path ) ) {
			$this->download_hook['download'] = FALSE;
			$this->download_hook['message'] = "Invalid File or File Path.";
			return 0;
		}
		
		/* File Name and Extension */
		$nameext = $this->chip_extension($file);
		$file_name = $nameext['file_name'];
		$file_extension = $nameext['file_extension'];
		
		$this->download_hook['file'] = $file;
		$this->download_hook['file_name'] = $file_name;
		$this->download_hook['file_extension'] = $file_extension;

		/* Allowed Extension - Validation */
		if ( $extension_check == TRUE && !array_key_exists( $file_extension, $allowed_extensions ) ) {
		  $this->download_hook['download'] = FALSE;
		  $this->download_hook['message'] = "File is not allowed to download"; 
		  return 0;
		}
		
		/* Referrer - Validation */		
		if ( $referrer_check == TRUE && !empty($referrer) && strpos( strtoupper( $_SERVER['HTTP_REFERER'] ), strtoupper( $referrer ) ) === FALSE ) {
			$this->download_hook['download'] = FALSE;
		 	$this->download_hook['message'] = "Internal server error - Please contact the site Administrator";
			return 0;
		}
		
		/* File Size in Bytes */
		$file_size = filesize($file_path);
		$this->download_hook['file_size'] = $file_size;
		
		/* File Mime Type - Auto, Manual, Default */
		$file_mime_type = $this->get_mime_type( $file_path );		
		if( empty( $file_mime_type ) ) {
			
			$file_mime_type = $allowed_extensions[$file_extension];
			if( empty( $file_mime_type ) ) {
				$file_mime_type = "application/force-download";
			}
		
		}		
		
		$this->download_hook['file_mime_type'] = $file_mime_type;
		
		$this->download_hook['download'] = TRUE;
		$this->download_hook['message'] = "File is ready to download";
		return 0;		
	
	}
	
	/*
	|---------------------------
	| Download Hook
	| Allows you to do some action before download
	|
	| @public
	| @return array
	|
	|---------------------------
	*/
	
	public function get_download_hook() { 
		$this->set_download_hook();
		return $this->download_hook;
	}
	
	/*
	|---------------------------
	| Post Download Hook
	|
	| @private
	| @return array
	|
	|---------------------------
	*/
	
	private function set_post_download_hook() { 
		return $this->download_hook;
	}
	
	/*
	|---------------------------
	| Download
	| Start download stream
	|
	| @public
	| @return 0
	|
	|---------------------------
	*/
	
	public function set_download() { 
		
		/* Download Hook */
		$download_hook = $this->set_post_download_hook();
		
		/* Extract */
		extract($download_hook);
		
		/* Recheck */
		if( $download_hook['download'] != TRUE ) {
			echo "File is not allowed to download";
			return 0;
		}
		
		/* Execution Time Unlimited */
		set_time_limit(0);
		
		/*
		|----------------
		| Header
		| Forcing a download using readfile()
		|----------------
		*/
		
		header('Content-Description: File Transfer');
		header('Content-Type: ' . $file_mime_type);
		header('Content-Disposition: attachment; filename=' . $file);
		header('Content-Transfer-Encoding: binary');
		header('Expires: 0');
		header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
		header('Pragma: public');
		header('Content-Length: ' . $file_size);
		ob_clean();
		flush();
		readfile($file_path);
		exit;
		
	}
	
	/*
	|---------------------------
	| Download
	| Start download stream
	|
	| @public
	| @return array
	|
	|---------------------------
	*/
	
	public function get_download() { 
		$this->set_download();
		exit;
	}

	/*
	|---------------------------
	| Destructor
	|---------------------------
	*/
	
	public function __destruct() {
	}
}
?>



download.php
<?php
ini_set("memory_limit","128M");
require_once('/home/*directories*.php');

/*
|-----------------
| Chip Error Manipulation
|------------------
*/


error_reporting(1);
/*
|-----------------
| Chip Constant Manipulation
|------------------
*/

define( "CHIP_DEMO_FSROOT",				dirname(__FILE__). "/" );





/*
|-----------------
| Chip Download Class
|------------------
*/

require_once("class.chip_download.php");


/*
|-----------------
| Class Instance
|------------------
*/

$download_path = CHIP_DEMO_FSROOT . "*download_path*";

$filename = $_REQUEST['fileid'];

$total_downloads = "SELECT downloads FROM `downloads` WHERE id = :fileid";
$ps = $shn_sites->prepare($total_downloads);
$ps->execute(array( 
':fileid'=>$filename));
foreach ($ps as $row)
  {
  $downloads_before = $row['downloads'];
  }

$one = '1';
$new_downloads = $downloads_before + $one;

$logdownload = "UPDATE downloads SET downloads = :downloads WHERE id = :fileid";
$ps = $shn_sites->prepare($logdownload);
$ps->execute(array( 
':fileid'=>$filename,
':downloads'=>$new_downloads));



$getdownload = "SELECT file FROM `downloads` WHERE id = :fileid";
$ps = $shn_sites->prepare($getdownload);
$ps->execute(array( 
':fileid'=>$filename));
foreach ($ps as $row)
  {
  $file = $row['file'];
  }
  
$args = array(
		'download_path'		=>	$download_path,
		'file'				=>	$file,		
		'extension_check'	=>	TRUE,
		'referrer_check'	=>	FALSE,
		'referrer'			=>	NULL,
		);
$download = new chip_download( $args );
/*
|-----------------
| Pre Download Hook
|------------------
*/

$download_hook = $download->get_download_hook();
//$download->chip_print($download_hook);
//exit;

/*
|-----------------
| Download
|------------------
*/

if( $download_hook['download'] == TRUE ) {

	/* You can write your logic before proceeding to download */
	
	/* Let's download file */
	$download->get_download();

}

?>


My MAX_FILE_SIZE is 128 MB

<br />
<b>Fatal error</b>:  Allowed memory size of 134217728 bytes exhausted (tried to allocate 127139841 bytes) in <b>/home/strong26/public_html/downloads/class.chip_download.php</b> on line <b>386</b><br />
. I know that you don't offer web development support, but could you just let me know one thing - Is this problem something I've created or is it a server/account problem?

I contacted hosting24 about it and they said:

Quote

Hello Chris,

If you get PHP error 'Allowed memory size of XXX bytes exhausted' here is one way how you can fix:

This error message can spring up in a previously functional PHP script when the memory requirements exceed the default 8MB limit. Don’t fret, though, because this is an easy problem to overcome.

To change the memory limit for one specific script by including a line such as this at the top of the script:
ini_set("memory_limit","128M");

Another way how this could be fixed is by modifying .htaccess file and adding this line to it:
php_value memory_limit 128M

Please contact us with any additional questions.

Best Wishes,
Alex F.
Help Desk Staff

www.hosting24.com


I have tried both of their suggestions and it still happens. What can I do?

This post has been edited by chris98: 04 January 2014 - 07:13 AM


Is This A Good Question/Topic? 0
  • +

Replies To: PHP File Download Script Problem

#2 andrewsw  Icon User is online

  • say what now
  • member icon

Reputation: 6408
  • View blog
  • Posts: 25,892
  • Joined: 12-December 12

Re: PHP File Download Script Problem

Posted 04 January 2014 - 07:15 AM

121 is very close to 128 and you cannot just compare these values directly - there are other factors. Notice that the error mentions the chunk of data it tried to allocate failed, that doesn't represent the total memory involved in your request.

Your host's response doesn't make clear whether 128M is the maximum they will allow. Try increasing the limit to perhaps 256M or 200M.
Was This Post Helpful? 0
  • +
  • -

#3 andrewsw  Icon User is online

  • say what now
  • member icon

Reputation: 6408
  • View blog
  • Posts: 25,892
  • Joined: 12-December 12

Re: PHP File Download Script Problem

Posted 04 January 2014 - 07:23 AM

Of course, that is a very large file, and you might want to consider your approach if downloading such large files will be a major feature of your site.
Was This Post Helpful? 0
  • +
  • -

#4 chris98  Icon User is offline

  • D.I.C Lover

Reputation: 40
  • View blog
  • Posts: 1,100
  • Joined: 06-July 13

Re: PHP File Download Script Problem

Posted 04 January 2014 - 07:29 AM

I increased it to 256, and now it will download but the archive is empty.

I've also just downloaded it in the cPanel file manager, and it works fine so it's definitely there.

This post has been edited by chris98: 04 January 2014 - 07:30 AM

Was This Post Helpful? 0
  • +
  • -

#5 andrewsw  Icon User is online

  • say what now
  • member icon

Reputation: 6408
  • View blog
  • Posts: 25,892
  • Joined: 12-December 12

Re: PHP File Download Script Problem

Posted 04 January 2014 - 07:36 AM

Try again, and try it with different files, to see if it is a problem with this particular file, or its size.
Was This Post Helpful? 0
  • +
  • -

#6 chris98  Icon User is offline

  • D.I.C Lover

Reputation: 40
  • View blog
  • Posts: 1,100
  • Joined: 06-July 13

Re: PHP File Download Script Problem

Posted 04 January 2014 - 07:38 AM

It's never happened before with any other files, and I've just tried with a 10 M file (the next largest in size) and it's worked.

This post has been edited by chris98: 04 January 2014 - 07:38 AM

Was This Post Helpful? 0
  • +
  • -

#7 andrewsw  Icon User is online

  • say what now
  • member icon

Reputation: 6408
  • View blog
  • Posts: 25,892
  • Joined: 12-December 12

Re: PHP File Download Script Problem

Posted 04 January 2014 - 07:43 AM

Try replacing the file itself on the server, and try with a different file of a similar size. These are all basic debugging steps to help you narrow down the problem: Is it a problem with this particular file, this particular copy of the file, or any files of this size?
Was This Post Helpful? 0
  • +
  • -

#8 chris98  Icon User is offline

  • D.I.C Lover

Reputation: 40
  • View blog
  • Posts: 1,100
  • Joined: 06-July 13

Re: PHP File Download Script Problem

Posted 04 January 2014 - 07:51 AM

Quote

try with a different file of a similar size


That's the problem - I had to upload it using file zilla because it wouldn't upload on the server and it took half an hour to upload. I can't upload any more files unless I solve this problem first because it downloads from a database id and it won't have one if it isn't uploaded with the script in that problem.
Was This Post Helpful? 0
  • +
  • -

#9 andrewsw  Icon User is online

  • say what now
  • member icon

Reputation: 6408
  • View blog
  • Posts: 25,892
  • Joined: 12-December 12

Re: PHP File Download Script Problem

Posted 04 January 2014 - 09:16 AM

If you will be dealing with large file uploads/downloads then you may want to investigate the services, and limits, provided by your current host and consider either upgrading your contract or look into another provider.

I don't know about this subject but I assume that there are hosts that might offer specific services to deal with large files, or even third-party services that you might use (DropBox?).

http://www.uploadify.com/

This post has been edited by andrewsw: 04 January 2014 - 09:21 AM

Was This Post Helpful? 0
  • +
  • -

#10 chris98  Icon User is offline

  • D.I.C Lover

Reputation: 40
  • View blog
  • Posts: 1,100
  • Joined: 06-July 13

Re: PHP File Download Script Problem

Posted 04 January 2014 - 09:19 AM

That's actually the main reason I upgraded from 000webhost.com. They have the MAX_FILE_SIZE set as 2 MB, whereas hosting24 have it set as 128 MB.

But to be honest, I don't see any real need in uploading a file bigger than 128 MB anyway (on my site) so it seems fine (if I can get this to work).
Was This Post Helpful? 0
  • +
  • -

#11 no2pencil  Icon User is offline

  • Professor Snuggly Pants
  • member icon

Reputation: 6559
  • View blog
  • Posts: 30,699
  • Joined: 10-May 07

Re: PHP File Download Script Problem

Posted 04 January 2014 - 09:21 AM

How is the error message in this topic different than the one from your other topic?
Was This Post Helpful? 0
  • +
  • -

#12 chris98  Icon User is offline

  • D.I.C Lover

Reputation: 40
  • View blog
  • Posts: 1,100
  • Joined: 06-July 13

Re: PHP File Download Script Problem

Posted 04 January 2014 - 09:25 AM

This one is from the download script, the other one is from the upload script (and at the time I posted it hosting24 were looking into the other one)

And this one doesn't have much to do with the MAX_FILE_SIZE does it? - is that not just for uploading files?
Was This Post Helpful? 0
  • +
  • -

#13 chris98  Icon User is offline

  • D.I.C Lover

Reputation: 40
  • View blog
  • Posts: 1,100
  • Joined: 06-July 13

Re: PHP File Download Script Problem

Posted 05 February 2014 - 01:58 PM

Yet again, trying to push the blame onto my script:

Quote

19:54James K.: Hello, how may I help you today?
19:55Chris: Hi, I'm experiencing a downloading problem via my website scripts; I can't seem to download files about 121 MB in size
19:56Chris: It downloads the archive with no errors, however, once it has downloaded, the archive is empty.
19:57James K.: If you upload file using PHP (instead of FTP), max file size limit is 128 MB and it could not be increased anymore.
19:59Chris: No, I'm talking about a download problem, I can't download files 121 MB
19:59Chris: I did get the error:
19:59Chris: <br />
<b>Fatal error</b>: Allowed memory size of 134217728 bytes exhausted (tried to allocate 127139841 bytes) in <b>/home/*****.php</b> on line <b>387</b><br />
20:00Chris: When I downloaded and attempted to open the archive, but now nothing is inside the archive
20:00James K.: It does not matter if it is upload or download. PHP scripts can not exceed 128MB limit.
20:00Chris: It's a 121 MB file, why isn't it working?
20:01Chris: The full path to the file is:
20:01Chris: /home/*****.zip
20:02James K.: You can download it via FTP without any issues. PHP script will be blocked if it will try to do that.
20:03Chris: PHP script will be blocked if I do what?
20:04James K.: You will get error message if you will try to download files that exceed the size limit.
20:04Chris: It doesn't exceed it though, it's only 121 MB
20:05James K.: There is a difference between Mb and MB. As you can see from the error message your file size is 127139841 bytes.
20:06James K.: ~127,1 MB
20:07Chris: What is the difference between Mb and MB?
20:07James K.: Do a Google research.
20:08Chris: Yes, but even if it is 127139841 bytes, the rest of the error message shows that it's still smaller:
20:08Chris: Allowed memory size of 134217728 bytes exhausted (tried to allocate 127139841 bytes)
20:09Chris: That doesn't make sense (to me)
20:10James K.: I already explained to you why this error is caused and that there is no way to increase the limit.
20:10James K.: Do You have any more questions or requests?
20:11Chris: Yes, it isn't working, and it isn't above the limit. So why isn't it working? Taken from the actual file size from my PC: 122, 376 KB
20:12Chris: That's the exact same file, except it is not uploaded.
20:12Chris: Oh wait, it's a different file that I'm having trouble with to the error above
20:13Chris: That error was from an old file. The archive downloads, but nothing is inside it. The new file size is : 122, 376 KB
20:14James K.: Do You have any more questions or requests?
20:15Chris: Yes. It appears that I have got the two files mixed up. The new file is 122, 376 KB and does not download. As this is clearly NOT over 128 Mb, why does it not download?
20:15James K.: Try to download it via FTP. It will download without any issues.
20:16Chris: But why won't it download by a PHP script?
20:16James K.: If you will keep repeating same questions all over again, I will close this chat session.
20:17James K.: It is either your script problem or the limit is being exceeded.
20:18Chris: Is that why it's empty?
20:18James K.: It could be.
20:20Chris: You did say in this below ticket to add the following into my .htaccess file and to add something into my PHP file, but even though I've done both of these, the error still continues. Do you know of anything else I could add? http://www.hosting24...cket.php?******
20:20Chris: ini_set("memory_limit","128M"); and
20:20Chris: php_value memory_limit 128M
20:21James K.: php_value memory_limit 256M in .htaccess file might help.
20:22Chris: Does it have to have a specific place (I.E. after rewrite base/) or can it go anywhere?
20:22James K.: Put it at the very bottom of the file.
20:24Chris: Does it matter where it goes in my download file as well?
20:24James K.: Don't put anything to your PHP file. Leave it as it was.
20:26Chris: No, it's still empty. I've taken it out from my PHP file, added it to the .htaccess at the bottom and it still downloads empty. If I gave you a link would you take a look?
20:27James K.: I can check it.
20:27Chris: http://****/download.php?fileid=15
20:29James K.: It doesn't even try to download the file. You said that it stops at 121MB. This issue is clearly caused by your script.
20:31Chris: The thing I don't understand is that it will download smaller files I.E:
20:31Chris: http://*******/download.php?fileid=29
20:45Chris: Hello?
James K. has left the conversation.
Click here to leave a message.
The chat conversation has ended.
Click here to take a short survey regarding the service you've received during this chat conversation.


What can I do to allow the file 121 Mb to download? Please somebody, help!

This post has been edited by chris98: 06 February 2014 - 10:25 AM

Was This Post Helpful? 0
  • +
  • -

#14 modi123_1  Icon User is offline

  • Suitor #2
  • member icon



Reputation: 13554
  • View blog
  • Posts: 54,090
  • Joined: 12-June 08

Re: PHP File Download Script Problem

Posted 05 February 2014 - 02:14 PM

Quote

20:05James K.: There is a difference between Mb and MB. As you can see from the error message your file size is 127139841 bytes.


You do understand the difference, right? One is megabyte is MB and megabits is Mb.


002	ini_set("memory_limit","128M");

From what I remember this sets the memory limit for php to operate in.. You know what it is allowed to allocate from the server.
http://us1.php.net/m...ni.memory-limit

Why do you think that is going to affect your ability to transfer a file from the server?
Was This Post Helpful? 0
  • +
  • -

#15 chris98  Icon User is offline

  • D.I.C Lover

Reputation: 40
  • View blog
  • Posts: 1,100
  • Joined: 06-July 13

Re: PHP File Download Script Problem

Posted 05 February 2014 - 02:19 PM

The MAX_FILE_SIZE probably, as well as the INI memory limit. I've already done what he said though, this is what I've added:

php_value memory_limit 256M

Was This Post Helpful? 0
  • +
  • -

  • (3 Pages)
  • +
  • 1
  • 2
  • 3