My test server is apache 2 to work php coding. i want to create a mp3 server.
Everything is working fine, however today i tried to build an admin page by taking the mp3 info, change it, delete etc. There is a play button in page for selected mp3, when clicked to play button, file loading with header option and playing,
Sample code is here:
session control &
$filename = '/home/bla..bla/mp3/'. $_GET['v'] . '.mp3';
if(file_exists($filename)) {
header('Content-Type: audio/mpeg');
header('Content-length: '.filesize($filename));
header('X-Pad: avoid browser bug');
header('Cache-Control: no-cache');
readfile($filename);
}else{
exit();
}
Everything looks fine, but when i click to another button (e.g. search again mp3 with ajax code or take value with javascript in same page) nothing is happening.
Page is waiting to load mp3 file. looks like blocking request. when mp3 loading %60 or %70, query is coming.
if i can't find a solution,i will be killer :)
ps: my system build on apache2, PHP5 , MySQL, using audio tag in admin page but same problem with jplayer.
Most likely you're running into session locking. When requesting a page in which you session_start(), the session file is opened and locked to prevent problems with concurrent access. The file stays locked until the current script is finished. While the file is locked, other processes can't access it and will wait until it becomes unlocked.
Before you do any long-running tasks like streaming an MP3 file, unlock the session with session_write_close.
Even better, let the web server handle the mundane task of streaming a file, don't keep a PHP process busy with it. Try mod_xsendfile.
Related
I'm randomly getting download errors from a link on a page. I also simplified the link to a directory for easy usage in emails for users.
On the main page the link looks like this:
a href="http://myPage.com/Mac" target="_blank" id="macDownloadButton" class="downloadbutton w-button">Download Mac version</a>
On my server, that's a directory with an index.php in it which looks like this:
<?php
// mac version
$file="http://www.myPage.com/downloads/myApp_Mac.zip";
$filename="myApp_Mac.zip";
header('Content-Transfer-Encoding: binary');
header('Accept-Ranges: bytes');
header('Content-Length: ' . filesize($file));
header('Content-Encoding: none');
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename=' . $filename);
readfile($file);
exit;
?>
Again, the reason I do this is so it's a simple link to send to users in email like, "http://myPage.com/Mac" and "http://myPage.com/Windows".
The weird thing is that it mostly works...but sometimes it doesn't.
What am I doing wrong?
It's hard to know precisely what's wrong unless you check for errors on your readfile() call.
But you're invoking your web server from your web server here when you specify a filename starting with http. You're doing
readfile('http://www.myPage.com/downloads/myApp_Mac.zip');
where you could just as easily do
readfile('../downloads/myApp_Mac.zip');
and read the zip file from the local file system to send to your user.
What's more, filesize('../downloads/myApp_Mac.zip'); will yield a numerical value quickly and send it in the Content-Length header. That will allow the browser, by knowing the total size of the file you're sending, to display a meaningful progress bar.
You should remove the Accept-Ranges header; the php program you showed us doesn't honor range requests. If you lie to the browser by telling it you do honor those requests, the browser may get confused and corrupt the downloaded copy of your file. That will baffle your user.
Your Content-Disposition header is perfect. It defines the filename to be used on your user's machine in the downloads folder.
Simple operations are more reliable, and this may help you.
The reason you got stat failed with link as an error message is this: stat(2) is a operating-system call that operates on files in local and mounted file systems.
As previously mentioned by O. Jones you should definitely always use your local file path.
Most of my previous issues have been mostly browser related where I needed to tweak/add a http header, and in one case I needed to send all the HTTP headers in lowercase but I haven't had an issue like that in years. My personal recommendation would be to use a solid download library/function - it will make a noticeable difference to your productivity as well as rule out most browser related issues you may come across.
I have used the codeIgniter download helper for the last 3 years and recommend it for 99% of use cases. At the very least I would recommend your read through it's code - you will probably find a few cases you have never even considered such as clearing the output buffer,mime detection and even a special case for Android 2.1 as well as a few headers you may or may not need.
If all else fails I have no idea what server your running this on but if you continue to have issues I would recommend monitoring which processes your machine is running while paying close attention to ram and IO usage. I've have encountered bad/misbehaving services that run periodically using 99% of my IO or ram for short intervals at a time that caused a few really odd and unexpected errors.
I want my mobile webapp be able to download files. My Android device unfortunately tells me it does not support file download via jquery plugin jquery.fileDownload.js...
So I just send a jsonP (cross domain, because my app runs on another server) request.
My php script looks
ob_clean();
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="file.JPG"');
readfile('/var/.../file.JPG');
die();
In my android chrome browser nothing happens after I send the jsonp request.
What I am doing wrong? Isnt it possible to download files via jsonp? Same code tested
on my desktop browser works perfectly.
Thanks in advance.
JSONP requires you to send back actual executable javascript code. You're just dumping out some essentially random bytes, which your browser will try to execute, and fail miserably.
You need to do some reading first: http://en.wikipedia.org/wiki/JSONP
You'd need to respond with a proper JSONP callback, and include your file data as a parameter, e.g.
header('Content-Type: text/javascript');
echo "jsonCallback(", json_encode(file_get_contents('your file here')); , ");"
I have a Chromecast and a URL of an mp4 file online. I also have a 2Mbps download connection, which is pathetic and renders direct buffering to the Chromecast too slow. That's what I tried so far:
Through the developer console, I simply set location.href to the online URL of the mp4. The Chromecast would buffer for 20 seconds, play 10 seconds' worth of video, and then buffer again. So, through the console, I paused the video and let it buffer for 5 minutes. When I let it play again, it played for about 15 seconds, and then lost all progress and had to be returned to the home screen.
As I don't want to wait for the whole download of the mp4 to complete, I am currently attempting this: I buffer the mp4 to a local file which is in my htdocs directory, and I then direct the Chromecast to that file's location. However, when opening the mp4 file thorugh Chrome (the browser), instead of playing, it shows a download prompt, and the Chromecast returns to the home screen.
I have implemented the buffering in PHP, and it looks as thus:
$bufferSource = 'http://example.com/path/to/file.mp4';
$bufferedReader = fopen($bufferSource, 'r');
while(!($finished = feof($bufferedReader))){
if($finished !== false){ break; }
//get onle line
$buffer = fgets($bufferedReader);
file_put_contents('buffer.mp4', $buffer, FILE_APPEND);
}
fclose($bufferedReader);
I know that PHP does its work, as I can watch the file size grow on my computer, and I can open the file with VLC. Is there maybe another PHP script I could make to access the locally buffered mp4 file which simulates 'bufferability', so Chrome does not show the download dialog but buffers the file, as should do the Chromecast?
EDIT: One more thing. I am not directing the Chromecast to the PHP script. I am actually directing it directly to the buffer.mp4 file.
You're missing a Content-Type header in your PHP script.
Figure out what the original content type header is from your server (probably video/mp4) and send it with your proxying script like this:
header('Content-Type: video/mp4');
This will allow the browser to detect the content type and play it directly (if supported), without downloading.
Also, I would consider using a real proxy server, such as Nginx, rather than reinventing the wheel. This will be much easier and more reliable.
You can use a receiver with a Media Element tag and then point its source to your mp4 file on your server. If you don't want to write your own receiver, you can use either the default or Styled Media Receiver . You would need a very simple sender to send the url, check out the github repo for examples
I am currently developing an application in PHP in which my server (a dedicated server) must to download a file, and the user should download the file in same time.
Here is an example :
Server start to download a file at a time A.
User wants to download this file at the time A + 3 seconds (for example)
I already solved the problem :"If the user downloads the file faster than the server..". But I didn't know how to make a php script in which the user is gonna to download the full file (it means that the size must be the full size of the file, not the size it's currently downloaded at the time A+3seconds). I already make that :
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.$data['name'].'";');
header('Content-Transfer-Encoding: binary');
header('Content-Length: '.$data['size']);
readfile($remoteFile);
But it doesn't work, the user is gonna download just the size it is currently on the server (which corrupt the file) and not the full file...
If you have any solution, thank you.
You could probably pipe the file manually, by opening the connection and reading until you're past all headers. Then once you've figured out the Content-Length, send that to the user and just echo all remaining data you get (do use flush() and avoid output buffers).
Pseudocode(-ish):
open the file
# grab headers
while you didn't get all HTTP headers:
read more
look for the Content-Length header
send the Content-Length header
# grab the file
while the rest of the request isn't done
read more
send it to the user
flush the buffers
done
Expanding on #Tom answer, you can use cURL to greatly simplify the algorithm by using the CURLOPT_HEADERFUNCTION and CURLOPT_READFUNCTION callbacks - see curl_setopt().
Don't send the content-length header. It's not required assuming you're using http 1.1(your webserver almost certainly does). Drawback is their browser cant show download time/size remaining.
<?php
$filename= './get/me/me_'.rand(1,100).'.zip';
header("Content-Length: " . filesize($filename));
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename=foo.zip');
readfile($filename);
?>
Hi,
I have this simple code that forces a random file download, my problem is that if I call the script two or more times from the same browser the second download won't start until the first is completed or interrupted. Thus I can download only one file per time.
Do you have any clue?
This may be related to PHP's session handling.
Using the default session handler, when a PHP script opens a session it locks it. Subsequent scripts that need to access it have to wait until the first script is finished with it and unlocks it (which happens automatically at shutdown, or by session_write_close() ). This will manifest as the script not doing anything till the previous one finishes in exactly the same way you describe.
Clearly you aren't starting the session explicitly, but there's a config flag that causes the session to start automatically: session.auto_start - http://www.php.net/manual/en/session.configuration.php
Either use phpinfo() to determine if this is set to true, or look in your config. You could also try adding session_write_close() to the top of the script, see if it makes the issue go away.
just guesses. There could be different reasons.
first, your server could restrict the number of connections or childs in paralell. But I guess this sin't the problem
second, it is more likely that the client restricts the number of connections. The "normal" browser opens only two connections at a time to a certain server. Modern browsers allow up to 8 (?) connections. This is a simple restriction in order to avoid problems which could occur with slow servers.
One workaround could be to place every download on a "virtual" subdomain.
give it a try!
Just to say that the session_write_close(); solved the problem for me.
I was using session_destroy(); (that worked) but was not much good if I needed to keep session data :)
All you need to do I place session_write_close(); just before you start streaming the file data.
Example:
<?php
$filename= './get/me/me_'.rand(1,100).'.zip';
session_write_close();
header("Content-Length: " . filesize($filename));
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename=foo.zip');
readfile($filename);
?>
I'd further investigate Ralf's suggestion about the server restrictions and start with checking the logfiles to ensure that the second request is received by the server at all. Having that knowledge, you can eliminate one of the possibilities and at least see which side the problem resides on.
From the client's browser - you didn't mention which one is it - if Firefox, try to install the Live Http Headers extension to see what happens to request you send and if browser receives any response from the server side.
As far as I can find, there is no php configuration setting that restricts max downloads or anything like that - besides, such a configuration is outside the scope of php.
Therefore, I can come to only two conclusions:
The first is that this is browser behaviour, see if the problem is repeated across multiple browsers (let me know if it is). The HTTP spec does say that only two connections to the same domain should be active at any one time, but I wasn't aware that affected file downloads as well as page downloads. A way of getting round such a limitation is to allocate a number of sub-domains to the same site (or do a catch-all subdomains DNS entry), and when generating a link to the download, select a random sub domain to download from. This should work around the multiple request issue if it is a browser problem.
A second and much more unlikely option is that (and this only applys if you are using Apache), your MaxKeepAliveRequests configuration option is set to something ridiculously low and KeepAlives are enabled. However, I highly doubt that is the issue, so I suggest investigating the browser possibility.
Are you getting an error message from the browser when the second download is initiated, or does it just hang? If it just hangs, this suggests it is a browser issue.