SitePoint Sponsor

User Tag List

Results 1 to 20 of 20
  1. #1
    SitePoint Enthusiast
    Join Date
    Feb 2007
    Posts
    71
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    PDF download got garbage

    Hi experts,

    The PDF download is not working. It is supposed to let user to download & save to disc, but the book content was displayed in the page as garbage, here is the code:
    ------------------------------------------
    $book = mysql_fetch_array( $books );
    $bookName = $book[ 'name' ];
    $mimeType = $book[ 'mimetype' ];
    $bookContent = $book[ 'content' ];
    $bookSize = strlen( $bookContent );
    $disposition = 'attachment';
    echo "<p>bookName=$bookName,mimeType=$mimeType,booksize=$bookSize</p>";

    if( strpos( $_SERVER[ 'HTTP_USER_AGENT' ], 'MSIE 5' ) ||
    strpos( $_SERVER[ 'HTTP_USER_AGENT' ], 'Opera 7' ) )
    {
    $mimeType = 'application/x-download';
    }

    header( "content-disposition:$disposition; filename=$bookName" );
    header( "content-type:$mimeType" );
    header( "content-length:$bookSize" );

    echo $bookContent;
    ----------------------------------------------------------
    test link:
    http://books.chnmates.com/delivery.php?tranId=151127125
    -----------------------------------------------------------
    Can you help?
    Thanks a lot.

  2. #2
    SitePoint Wizard TheRedDevil's Avatar
    Join Date
    Sep 2004
    Location
    Norway
    Posts
    1,198
    Mentioned
    4 Post(s)
    Tagged
    1 Thread(s)
    You should not sent any other data than the headers and the content of the book.

    Before your headers you got a echo that show some information about the book, remove that one.

    In addition you should have more headers, for example that its a binary download, that the browser should not cache it etc.

  3. #3
    SitePoint Enthusiast
    Join Date
    Feb 2007
    Posts
    71
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    $bookContent = $book[ 'content' ];
    $bookSize = strlen( $bookContent );
    $disposition = 'attachment';
    //echo "<p>bookName=$bookName,mimeType=$mimeType,booksize=$bookSize</p>";

    if( strpos( $_SERVER[ 'HTTP_USER_AGENT' ], 'MSIE 5' ) ||
    strpos( $_SERVER[ 'HTTP_USER_AGENT' ], 'Opera 7' ) )
    {
    $mimeType = 'application/x-download';
    }

    header( "content-disposition:$disposition; filename=$bookName" );
    header( "content-type:$mimeType" );
    header( "content-length:$bookSize" );
    header("Cache-Control: no-cache, must-revalidate");
    header('Content-Transfer-Encoding: binary');

    echo $bookContent;

    // update the download record
    $ships = $ships + 1;
    $sql = "UPDATE transactions SET shipCount='$ships' WHERE id='$tranId'";
    mysql_query( $sql );

  4. #4
    SitePoint Enthusiast
    Join Date
    Feb 2007
    Posts
    71
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    See the above code, I have commented out all echo (and exit functions) exept the one for bookContent, I still got garbage displayed other than a download/save dialogue.

    See the link: http://books.chnmates.com/delivery.php?tranId=151127125

  5. #5
    Non-Member Kalon's Avatar
    Join Date
    Aug 2010
    Location
    At my computer
    Posts
    2,012
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    if they're all in pdf format an easier option could be to just generate links for the books with the href pointing to the path to the pdf file on the server. the path would be stored in the db table.

    when the link is clicked, the file is opened in the browser (if adobe reader is installed) and the user can then save it to wherever they like on their local pc.

    you can also put a link on the page pointing directly to the adobe reader download page.

  6. #6
    SitePoint Enthusiast
    Join Date
    Feb 2007
    Posts
    71
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks for the quick reply.
    My book content is stored in the MySQL table other than a disc.
    My php source code is copied from Kevin Yank's book: Buld your own database driving website using php & mysql.

    How can I do it with the database retrieved content for book?

  7. #7
    Non-Member Kalon's Avatar
    Join Date
    Aug 2010
    Location
    At my computer
    Posts
    2,012
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Charlie123 View Post
    Thanks for the quick reply.
    My book content is stored in the MySQL table other than a disc.
    My php source code is copied from Kevin Yank's book: Buld your own database driving website using php & mysql.

    How can I do it with the database retrieved content for book?
    sorry , but I can't help you with that situation because I would never do it that way and so don't know the answer.

    I always store the physical file (pdf, image, .doc or whatever) on disk and store only the file's meta data in the database.

  8. #8
    SitePoint Wizard TheRedDevil's Avatar
    Join Date
    Sep 2004
    Location
    Norway
    Posts
    1,198
    Mentioned
    4 Post(s)
    Tagged
    1 Thread(s)
    Quote Originally Posted by Charlie123 View Post
    See the above code, I have commented out all echo (and exit functions) exept the one for bookContent, I still got garbage displayed other than a download/save dialogue.

    See the link: http://books.chnmates.com/delivery.php?tranId=151127125
    As I mentioned, you need to remove the data your echoing before the headers.

    The code below is sent before the headers you set, and before the pdf information. If you do as I recommended, your system will work.

    So in short: 1) First set the headers 2) Then send the file data

    HTML Code:
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
    "http://www.w3.org/TR/html4/strict.dtd">
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
      <title>下载书籍</title>
      <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
    </head>
    
    <body>
      <!--h1谢谢购买,欢迎下载! h1-->

  9. #9
    SitePoint Enthusiast
    Join Date
    Feb 2007
    Posts
    71
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks, TheRedDevil,

    What should I do exactly with this piece of code:
    -------------------------------------------------
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
    "http://www.w3.org/TR/html4/strict.dtd">

    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <title>下载书籍</title>
    <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
    </head>

    <body>
    <!--h1谢谢购买,欢迎下载! h1-->

    <?PHP
    $tranId = $_GET[ 'tranId' ];
    .....................................................
    echo $bookContent;

    // update the download record
    $ships = $ships + 1;
    $sql = "UPDATE transactions SET shipCount='$ships' WHERE id='$tranId'";
    mysql_query( $sql );
    ?>
    <!p谢谢下载。p-->
    </body></html>

    -------------------------------------------------------------

  10. #10
    SitePoint Wizard TheRedDevil's Avatar
    Join Date
    Sep 2004
    Location
    Norway
    Posts
    1,198
    Mentioned
    4 Post(s)
    Tagged
    1 Thread(s)
    If you want to provide the information you got in your database as a downloadable file, then you need to remove the code.

    I am not sure how else to explain this, you need to REMOVE all text/code/spaces etc I.e. not even any whitespace should be sent from the script.

    The only thing you want to send out is, the various headers and then afterwards you should send the file data.

  11. #11
    SitePoint Enthusiast
    Join Date
    Feb 2007
    Posts
    71
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    <?PHP
    $tranId = $_GET[ 'tranId' ];
    .........
    $bookContent = $book[ 'content' ];
    $bookSize = strlen( $bookContent );
    $disposition = 'attachment';

    if( strpos( $_SERVER[ 'HTTP_USER_AGENT' ], 'MSIE 5' ) ||
    strpos( $_SERVER[ 'HTTP_USER_AGENT' ], 'Opera 7' ) )
    {
    $mimeType = 'application/x-download';
    }

    header( "content-disposition:$disposition; filename=$bookName" );
    header( "content-type:$mimeType" );
    header( "content-length:$bookSize" );
    //header("Cache-Control: no-cache, must-revalidate");
    //header('Content-Transfer-Encoding: binary');

    echo $bookContent;

    // update the download record
    $ships = $ships + 1;
    $sql = "UPDATE transactions SET shipCount='$ships' WHERE id='$tranId'";
    mysql_query( $sql );

    ?>
    ---------------------------------------------
    Hi expert,
    I am stuck here. I have cut the PHP file to be like the above without any html code, I still got garbage displayed on the screen, any further help please?
    Thanks in advance. link: http://books.chnmates.com/delivery.php?tranId=151127125
    Charlie

  12. #12
    SitePoint Wizard TheRedDevil's Avatar
    Join Date
    Sep 2004
    Location
    Norway
    Posts
    1,198
    Mentioned
    4 Post(s)
    Tagged
    1 Thread(s)
    If you take a look on the source of the page, you will see this at the top:

    Top of page:

    %PDF-1.3%
    1 0 obj [/PDF /Text /ImageB /ImageC /


    As you can see it seems to be a linebreak at the top. Are you certain there is no white space at all on the page that is outside the php code?

    Also in the code you have this "........." what exactly do you mean by that, if you mean that there is more code there, then that might be where your issue lies.

    Keep looking for the whitespace and you will fix the problem.

    Good Luck

  13. #13
    SitePoint Enthusiast
    Join Date
    Feb 2007
    Posts
    71
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    <?PHP
    $tranId = $_GET[ 'tranId' ];

    $dbconn = @mysql_connect( 'localhost', 'xxx', 'xxx' );
    @mysql_select_db( 'chnmates_com_-_books' );
    $sql = "SELECT id, shipCount, bookId FROM transactions WHERE id='$tranId'";

    $tranList = @mysql_query( $sql );
    $tran = @mysql_fetch_array( $tranList );

    $bookId = $tran[ 'bookId' ];
    $ships = $tran[ 'shipCount' ];
    $tranId = $tran[ 'id' ];
    $sql = "SELECT name, mimetype, content FROM books WHERE id='$bookId'";
    $books = @mysql_query( $sql );

    $book = @mysql_fetch_array( $books );
    $bookName = $book[ 'name' ];
    $mimeType = $book[ 'mimetype' ];
    $bookContent = $book[ 'content' ];
    $bookSize = strlen( $bookContent );
    $disposition = 'attachment';

    header( "content-disposition:$disposition; filename=$bookName" );
    header( "content-type:$mimeType" );
    header( "content-length:$bookSize" );

    echo $bookContent;

    ?>

    Hi TheRedDevil,
    Thanks for reply, the above is the full, complete PHP file exept the user name/password removed, I still got the garbage displayed other than dowloand/save, I really don't know what's wrong, can you have a look?
    http://books.chnmates.com/delivery.php?tranId=151127125

  14. #14
    SitePoint Wizard TheRedDevil's Avatar
    Join Date
    Sep 2004
    Location
    Norway
    Posts
    1,198
    Mentioned
    4 Post(s)
    Tagged
    1 Thread(s)
    I cant see any direct errors in that code, but you do have whitespace somewhere.
    Turn on error reporting and see if that will help you out.

    This is the headers you are sending out now, as you can see it does not contain the headers you set by PHP. This indicate you are getting error messages when you try to set the headers.

    HTTP/1.1 200 OK
    Date: Wed, 01 Dec 2010 18:55:07 GMT
    Server: Apache
    X-Powered-By: PHP/4.3.9
    Vary: Host,Accept-Encoding
    Content-Encoding: gzip
    Keep-Alive: timeout=15, max=100
    Connection: Keep-Alive
    Transfer-Encoding: chunked
    Content-Type: text/html

  15. #15
    SitePoint Enthusiast
    Join Date
    Feb 2007
    Posts
    71
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Oh. Thanks for the tip. I did find the error log that reads something like this:
    "Cannot modify header information"
    I googled for a while I saved the PHP file as ansi code other than utf-8 code. The problem solved. I got download/save pop up.
    Thanks again.

  16. #16
    SitePoint Wizard TheRedDevil's Avatar
    Join Date
    Sep 2004
    Location
    Norway
    Posts
    1,198
    Mentioned
    4 Post(s)
    Tagged
    1 Thread(s)
    No problems, Im glad you got it working.

    If you dont mind, what editor/IDE do you use? Im just asking as we always use UTF-8 in our company for the files, and we dont have any problems. So it might be located towards the editor you use.

  17. #17
    SitePoint Enthusiast
    Join Date
    Feb 2007
    Posts
    71
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I use simple notepad built in Windows & use Filezilla for upload. I want utf-8 as I want to display some chinese characters after download. Not sure how to solve this.

    In regarding Kalon's alternative, how would you stop people from doing multiple downloads? File safety issue?

    Thanks.

  18. #18
    SitePoint Wizard TheRedDevil's Avatar
    Join Date
    Sep 2004
    Location
    Norway
    Posts
    1,198
    Mentioned
    4 Post(s)
    Tagged
    1 Thread(s)
    You should use a proper editor, then you wont have that problem with the charset.

    Give Netbeans a try http://www.netbeans.com/ its a free editor.

    For the question regarding stopping people from doing multiple download, that one is harder to do. However I am not sure why you would want to do this? As the same person would not download the same file multiple times?

  19. #19
    SitePoint Enthusiast
    Join Date
    Feb 2007
    Posts
    71
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks for the tip. I just downloaded netbeans for PHP only package & followed its project wizard to use defaul encoding of utf-8, retyped in my delivery.php file, saved. Then uploaded to web host. Download/save window poped up in browser. Great. Not sure why notepad got me wrong when file saved as utf-8 encode.

    I also changed the "echo book['content'];" which was from database to "echo readfile('filename');" whcih directly reads the disc file. They all worked.

    I used database content for download because I think it is safer to protect your book files. Any comment?
    I used a download count for each transaction id in database so no multiple downloads is allowed. I don't want people to distribute the download link. Any comment.

    This is a great discussion, thanks a lot.
    Charlie

  20. #20
    SitePoint Wizard TheRedDevil's Avatar
    Join Date
    Sep 2004
    Location
    Norway
    Posts
    1,198
    Mentioned
    4 Post(s)
    Tagged
    1 Thread(s)
    If your saving the files in the database or not is a preference. Both has its advantages and disadvantages.

    The problem with download counters is that its not certain the user managed to successfully download the file. It might be a better idea to just allow logged in members to download.


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •