Search code examples
phpwoocommercedownloadfile-get-contents

Check if PDF File is available before downloading?


We are using Woocommerce for our ecom website and in order to automatically generate government-approved invoices for customers we use a certified online invoicing software.

I am making an API request to this invoicing software in order to retrieve the generated invoice document from their database, this is the code:

// On Order complete > Get document ID from order > access Moloni invoicing API > get document link GETPDFLINK > Sanitize the string and get Hash > generate the final document link > access it and download the PDF

function download_moloni_document_id( $order_id, $order ) {

    // Retreive from the Database table moloni_api the access token from column main_token
    global $wpdb;
$table_name = "db_invoicing_api";
$retrieve_data = $wpdb->get_results( "SELECT * FROM $table_name WHERE id = 1" );
foreach ($retrieve_data as $retrieved_data) {
    $maintoken = $retrieved_data->main_token; 
     }
    
    
    // Get document ID from the order
$documentid = get_post_meta($order->id, '_moloni_sent', true);

    
    // Connect to moloni API and getpdflink
    $url = "https://api.moloni.pt/v1/documents/getPDFLink/?access_token=$maintoken";
    
    
    $postData = array(
   'company_id' => '12345',
   'document_id' => $documentid );
    
    
    $arguments = array(
        'method' => 'POST',
         'headers'  => array(
        'Content-type: application/x-www-form-urlencoded'
    ),
        'body' => $postData,
    );

    $response = wp_remote_post( $url, $arguments );

    if ( is_wp_error( $response ) ) {
        $error_message = $response->get_error_message();
        return "Something went wrong: $error_message";
    } else {
        echo '<pre>';
        var_dump( wp_remote_retrieve_body( $response ) );
        echo '</pre>';
        
        // jsondecode the string received by the API to remove backslashes, get and parse the URL and extract the HASH key
        $response2 = wp_remote_retrieve_body($response);
parse_str(parse_url(json_decode($response2, true)['url'], PHP_URL_QUERY), $result);
$hash = $result['h'];
    
        
// Assemble the Invoice HTML download URL with the Hash and document ID
$fileUrlpdf = "https://www.moloni.pt/downloads/index.php?action=getDownload&h=$hash&d=$documentid&e=$loginmail&i=1&t=n";        
        
    
$pdforderid = $order->id;
    // Save the file with document id name to server location

$saveTopdf = "ftp://myserver/INVOICES/evo-$pdforderid.PDF";
    
file_put_contents(
    $saveTopdf,
    file_get_contents($fileUrlpdf)
);

    
} }
add_action( 'woocommerce_order_status_completed', 'download_moloni_document_id', 20, 2 );

In the end you can see I use

file_put_contents(
$saveTopdf,
file_get_contents($fileUrlpdf) );

in order to visit the link, retrieve the PDF and download it. This works well then the link is generated successfully and sends to a direct download of the invoice PDF The problem I have is is, sometimes there is an issue and the invoice PDF is not generated, this makes it so that the final link $fileUrlpdf does not lead to a download but instead to a web page with an error message saying something like "No Documents Found" which leads this code to download a PDF of dozens of pages containing the source code/HTML of that page. This is a problem because the PDFs (invoices) are later automatically printed by our system, so we sometimes end up with hundreds of pages of HTML code instead of the invoices.

I have tried to solve this in the following way through conditions:

  • to check if the download/PDF file exists

     if (file_exists($fileUrlpdf)) {
        file_put_contents(
         $saveTopdf,
         file_get_contents($fileUrlpdf));  } 
    
  • one that would check the $response array for the error message and not proceed (because

     $invalid = 'No Documents Found'; if (strpos($response, $valid) !== false) {echo 'No Documents found'; else { *download the PDF* } }
    

I have also considered the possibility of

  • checking if the page $fileUrlpdf would contain "No Documents Found", to not download it but I haven't been able to figure this one out either.

Bear with me as you can see my experience with PHP is limited so I would like to ask, what would be the best practice here? What approach would you suggest?

Thank you very much in advance for the attention and advice.


Solution

  • Either look at using the API to fetch the invoice/document and handle errors that way moloni.pt/dev

    Or you could look at checking the Content-Type of the response headers as shown below

    get_headers

    $fileUrlpdf = "https://www.moloni.pt/downloads/index.php?action=getDownload&h=$hash&d=$documentid&e=$loginmail&i=1&t=n";
    $fileHeaders = get_headers($fileUrlpdf, true)
    
    if($fileHeaders['Content-Type'] === 'application/pdf') {
        // PDF response
    }