Jump to content


  • Posts

  • Joined

  • Last visited

Posts posted by LLLLLLL

  1. It was not my intention to keep the code from you. I have been away all day. But saying it's a coding issue when the code clearly works on all other sites and browsers, but not on this site only with mobile, seems completely illogical. Here's the modified/simplified code. Almost all of it is application-specific and won't help you, but here it is anyway.

    if ( !common::gx( 'guid' ) ) {
    	echo translated_text::find( "Download.NoFileGuid" );
    $guid = common::g( 'guid' );
    // get the file location from preferences
    { phpfreaks...  read some preferences from DB }
    $source_dir        = 
    $root_download_dir = 
    $enforce_ip        = 
    $retry_mins        = 
    $download_attempts_allowed = 
    $data = { php freaks... read info about file }
    // these error numbers come from download_product constants
    if ( $data === false ) {
    	exit_w_msg( "error=681" );
    // read the product
    $dp = new download_product();
    $dp->read( $data );
    // need the order guid and the customer name.
    $data = { php freaks ... get customer name and order name }
    $order_guid = 
    $oid        = 
    $cname      = 
    //  php freaks... this is where the log shows we reach this code twice
    //	common::debug_to_log( $dp );
    //	common::debug_to_log( $download_attempts_allowed );
    // check status
    if ( $dp->status >= $download_attempts_allowed ) {
    	exit_w_msg( "id=$order_guid&error=" . download_product::ERR_ALREADY );
    // if an attempt has already been made on the file, verify the download rules
    if ( !empty( $dp->attempt_time ) ) {	
    	if ( $enforce_ip && $_SERVER[ 'REMOTE_ADDR' ] != $dp->ip_address ) {
    		exit_w_msg( "id=$order_guid&error=" . download_product::ERR_WRONG_IP );
    // find the source file to copy. we copy to a temporary directory
    // for safety; it's apparently better to stream from a directory that
    // doesn't actually exist except for temporarily. plus we may
    // alter the file before we stream it.
    $source_file = $source_dir . $dp->filename;
    if ( !file_exists( $source_file ) ) {
    	exit_w_msg( "id=$order_guid&error=" . download_product::ERR_NO_SOURCE );
    // find out where we need to copy the files.
    if ( !file_exists( $root_download_dir ) ) {
    	exit_w_msg( "id=$order_guid&error=" . download_product::ERR_NO_DIR );
    // the guid folder should NOT already exist. it should be deleted from
    // a previous download attempt. but if it DOES exist, just go ahead and
    // use it.
    if ( !file_exists( $root_download_dir . $guid ) ) {
    	// now create the new directory where we will copy the file
    	$dir_made = mkdir( $root_download_dir . $guid );
    	if ( !$dir_made ) {
    		exit_w_msg( "id=$order_guid&error=" . download_product::ERR_DIR_CREATE );
    // so create the filename, and then copy the file.
    $filename = $root_download_dir . $guid . "/" . $dp->filename;
    // that last line isn't always right. if the dp filename is
    // a subfolder/filename, remove the subfolder.
    if ( strpos( $dp->filename, "/" ) !== false ) {	
    	$just_filename = basename( $source_file );
    	$filename = $root_download_dir . $guid . "/" . $just_filename;
    $copy_ok = copy( $source_file, $filename );
    if ( !$copy_ok ) {
    	exit_w_msg( "id=$order_guid&error=" . download_product::ERR_FILE_COPY );
    // check for existence. would be odd, wouldn't it?
    if ( !file_exists( $filename ) ) {
    	exit_w_msg( "id=$order_guid&error=" . download_product::ERR_NO_FILE );
    ////////////////////////////////// all of the below is up for debate
    //header( "Pragma: public" ); // required
    //header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
    //header("Cache-Control: private",false); // required for certain browsers 
    header( "Content-Description: File Transfer" );
    header('Content-Transfer-Encoding: binary'); // test
    header('Expires: 0'); // test
    header('Cache-Control: must-revalidate'); // test
    header('Pragma: public'); // test
    header( "Content-Type: application/octet-stream"); // test
    header( "Content-Type: application/octet-stream" );  // commented. test
    header( "Content-Length: " . filesize( $filename ) );
    header( 'Content-Disposition: attachment; filename="' . $dp->download_filename . '"' );
    ob_clean(); // test
    flush(); // test
    readfile( $filename );
    ///////////////////////////////////// all of this is up for debate. ^^^^^^^^^^
    // we're done streaming. do some cleanup.
    unlink( $filename );
    $rm_dir_ok = rmdir( $root_download_dir . $guid );
    // now update the download status:
    $dp->status = $dp->status + 1;
    $dp->ip_address = $_SERVER[ 'REMOTE_ADDR' ];
    $d = date( 'Y-m-d H:i:s' );
    if ( empty( $dp->attempt_time ) )
    	$dp->attempt_time = $d;
    // this function logs ALL attempts (ip, time) on a file. security.
    $dp->log_attempt( $_SERVER[ 'REMOTE_ADDR' ], $d, $guid );
    function exit_w_msg( $msg ) {
    	header( "Location:download.php?" . $msg );
  2. I'm not "redirecting all over the place", and I never use HTTP_REFERER. I do appreciate the help but what you're suggesting here is not correct.

    1) There's a GET parameter passed that references a database row

    2) That row knows the file, knows if it was downloaded before, knows other security settings related to the download

    3) That file gets sent to the browser

    4) All logic to redirect (in #2) goes through a single function that calls header() and then calls exit.


    Posting the whole file isn't something that will help because the issue only occurs on one server. There's too much application logic on there anyway. Maybe I can send it to you privately, but at this point I'm awaiting the web host.


    I should have probably posted this in the Apache forum or something. The web host is unable to get back to me with the reason for the multiple requests on the file.

  3. I found that the script is getting called twice, and this is the problem. Because after the file is downloaded once, it's not allowed to be downloaded again. The script checks for this and if the download limit was reached, it redirects to the original page with a GET paramter so the appropriate error is displayed. The HTML that gets returned has the message "No more download attempts are allowed", which is the valid code in that situation. But why the script gets called twice is beyond me. 


    I have the server people looking at the logs to get this information. I've long suspected some htaccess or Apache or other rewrite that somehow makes the URL request or response get screwed up. That's probably the case for the code getting hit twice, but it's odd to me that the HTML would be returned as an attachment; the normal behavior is just to be directed to the page (the page that's made up of the HTML that's being returned).


    Output buffering is 4096, for what it's worth. 


    I'm awaiting information from the server people.

  4. There's no problem with $filename, because again, this works from a desktop browser. I have already examined the variables with logging and of course they are correct, since it's the exact same code from desktop or mobile browser.


    I've tried changing to octet-stream and I've tried dozens of other variations. This may be useful, but it doesn't change the fact that this code works on other servers. It looks like octet-stream is a better choice, and I'll do that, but again, this code works on other servers to the same device and browser.

  5. I will try that, but why would those files download...

    1) Successfully from a desktop browser

    2) Successfully from my server on a mobile browser (instead of using the customer's site)

    3) Unsuccessfully from his server and mobile.




    #2 makes it seem like it's a server thing. The same code runs on my dev server as the customer's server. The same files download for me without issue.

  6. I've written software that lets a file get downloaded by a user click. There is one customer site where downloads are failing but only on Android browser (and possibly other mobile?). Both mp3s and PDFs fail to download, and both file types stop downloading at about 14.61 KB. To clarify, what that means is that my Android phone shows that the mp3 was downloaded, with a file size of 14.61, even though the actual file is 3MB or so.


    The code is pretty standard stuff:

    header( "Content-Description: File Transfer" );
    header( "Content-Type: application/force-download");
    header( "Content-Length: " . filesize( $filename ) );
    header( 'Content-Disposition: attachment; filename="' . $dp->download_filename . '"' );
    readfile( $filename );

    Since this code works on hundreds of sites, and since there's no mobile issue on other sites, a code issue seems unlikely. I think there might be a server-side issue but I don't know what to check. Download issues are often php.ini limits on file size, but since this same file downloads on desktop browsers without issue, a php.ini issue seems unlikely.


    Any ideas on why this would fail on mobile?


  7. I just found code that does this:

    			orig = orig.replace( "<br>", "<br>" );
    			orig = orig.replace( "<BR>", "<br>" );
    			orig = orig.replace( "<bR>", "<br>" );
    			orig = orig.replace( "<Br>", "<br>" );

    I see why it's done this way (to encompass any caps variation on the BR) but since .replace() will only get the first instance, this is just bad all the way around. Also, there's no way to do a toLowerCase() because that will mess up the rest of the string.


    Is there some sort of JS regex way to replace all instances of <br> regardless of the caps? 



  8. You cited the load errors list for:


    1) If the php.ini post size ( 8 ) is smaller than the max file size (16), $_POST is empty and so is $_FILES. There's no way to get an error



    But that doesn't really help answer the question. There IS NO ERROR because $_POST and $_FILES are empty. I realize this is potentially a server issue, but a customer had this issue. Is there any way to know that a post was attempted?

  9. I tried to edit the original post to no avail. Here's clearer information:


    My test for now is simple... test upload a small image file, it's fine. But I have set my max file size to 16MB in php.ini, and I'm intentionally uploading a 19MB file. What is the expected result?


    Here's what I've found:

    1) If the php.ini post size ( 8 ) is smaller than the max file size (16), $_POST is empty and so is $_FILES. There's no way to get an error

    2) If the php.ini post size (20) is larger than the max file size (20), $_FILES[ 'whatever' ][ 'file' ] gives me a correct result.


    Is there a way to get an error that helps a user in scenario #1?

  10. I'm trying to test error conditions for file uploads, but when a file intentionally fails, I'm not even sure how to access the code. Here's a snippet:
    	$file_arr = $_FILES[ 'digifile' ];
    	$fn       = $file_arr[ 'name' ];
    	$temp     = $file_arr[ 'tmp_name' ];
    	$error    = $file_arr[ 'error' ];
    	error_log( 'the error is: ' . $error ); // ** SEE NOTE BELOW
    	if ( $error > 0 ) {
    		$ui->upload_message = "Error during file upload. ";
    		// try to switch the error to show a relevant message
    	} else {			
    		if ( move_uploaded_file( $temp, $full_path ) )
    			// something

    My test for now is simple... test a small image file, it's fine. But I have set my max file size to 16MB in php.ini, and I'm intentionally uploading a 19MB file. What is the expected result?


    Well I can tell you that the result is this code IS NOT REACHED AT ALL! How is that possible? error_log() doesn't get reached. I don't really know what happens when there is an error, but I'd like to show a customer a relevant message if this happened in the real world. There's no boolean result of move_uploaded_file, either, since like I said THE CODE ISN'T REACHED.


    I really don't understand. Any help is appreciated.


  11. Sorry, another question on this, because I'm not sure I asked it correctly the first time: The database column is currently latin1_swedish BUT the encoding used by the application's mysql connection is UTF-8.


    This is why I was wondering about needing to convert data before converting the column.

  12. I've been given a database where some text columns are using latin encoding (or swedish? ugh). I want to update these columns to utf encoding while preserving the data to be accessed correctly after the column type is changed. What are the steps? Do I convert the data FIRST and then alter the column encoding type? Or vice-versa? Or something else?


    Also, is this the best way to update the data?

    convert(cast(convert(column_name using latin1) as binary) using utf8)



  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.