pdf extension not allowed when adding an attachment to xero with API - php

Wonder if anyone can explain what rstrictions Xero has for adding a pdf file I creted using mPDF. I have managed to use a png file and uploaded it to an invoice but cannot get past this block.
public function attachPDF( $invoice ) {
try {
$company = Company::find( $invoice->company_id );
list( $xeroTenantId, $accountingApi, $identityApi ) = VivattiXero::getApiConnection( $company, false );
$filename = 'AUTH#' . sprintf( '%08d', $invoice->id ) . '.pdf';
//$filename = 'favicon.png';
$guid = $invoice->invoice_id;
$contents = $invoice->getPDF( \Mpdf\Output\Destination::FILE, true, $filename );
$handle = fopen( $filename, "r" );
$contents = fread( $handle, filesize( $filename ) );
fclose( $handle );
//unlink( $filename );
$result['apiResponse'] = $accountingApi->createInvoiceAttachmentByFileName( $xeroTenantId, $guid, $filename, $contents, true );
$result['message'] = 'PDF was attached to invoice #' . sprintf( '%08d', $invoice->id );
$result['success'] = true;
}catch (\XeroAPI\XeroPHP\ApiException $e) {
$error = AccountingObjectSerializer::deserialize(
$e->getResponseBody(),
'\XeroAPI\XeroPHP\Models\Accounting\Error',
[]
);
$result['message'] = "ApiException - " . $error->getElements()[0]["validation_errors"][0]["message"];
$result['success'] = false;
}
return $result;
}
}
Has anyone successfully uploaded a pdf to xero? anyone with a mpdf pdf?
thanks

Related

Wordpress and crontab

I have built a Wordpress plugin that polls an api, this api along with other data, returns URLs to images (the user polling the api owns these images). Moving the images from the api server to my server is time consuming but needs to be done as we want Wordpress to create multiple sizes of the images - thus we need to utilise it's upload functionality. Sometimes the data may return 500+ results each result could multiple images.
I am wanting to offset the image retrieval into a daily CRON job, however I cannot seem to get the cron to run, I have done the following in my code,
wp-config.php
define('DISABLE_WP_CRON', true);
I register a scheduled event in my plugin code like this,
wp_schedule_event( time(), 'daily', 'process_images_hourly' );
This theoretically should put this function (below) into a job list.
function process_images_hourly()
{
global $wpdb;
$results = $wpdb->get_results( "SELECT * FROM wp_autotrader_image_process WHERE process_status = 'Unprocessed';");
$processed_id = [];
foreach($results as $result) {
if(isset($result->image_url)) {
$upload_dir = wp_upload_dir();
$attachment_array = [];
if( !class_exists( 'WP_Http' ) ) {
include_once( ABSPATH . WPINC . '/class-http.php' );
}
$http = new WP_Http();
$file = file_get_contents($result->image_url);
$finfo = new finfo(FILEINFO_MIME_TYPE);
$ext = $finfo->buffer($file);
if(strpos($ext, 'jpeg') || strpos($ext, 'jpg')) {
$type = '.jpg';
} elseif(strpos($ext, 'png')) {
$type = '.png';
} elseif(strpos($ext, 'gif')) {
$type = '.gif';
}
$response = $http->request( $result->image_url );
//die(print_r($image['secure']['href']));
if( $response['response']['code'] != 200 ) {
die(print_r($response['response']));
return false;
}
$upload = wp_upload_bits( basename($result->image_url), null, $response['body'] );
if( !empty( $upload['error'] ) ) {
die(print_r($upload));
return false;
}
$file_path = $upload['file'];
$file_name = basename( $file_path );
$file_type = wp_check_filetype( $file_name );
$attachment_title = sanitize_file_name( pathinfo( $file_name, PATHINFO_FILENAME ) );
$wp_upload_dir = wp_upload_dir();
$post_info = array(
'guid' => $wp_upload_dir['url'] . '/' . $file_name . $type,
'post_mime_type' => $finfo->buffer($file),
'post_title' => $attachment_title,
'post_content' => '',
'post_status' => 'inherit',
);
$attach_id = wp_insert_attachment( $post_info, $file_path );
require_once( ABSPATH . 'wp-admin/includes/image.php' );
$attach_data = wp_generate_attachment_metadata( $attach_id, $file_path );
wp_update_attachment_metadata( $attach_id, $attach_data );
$attachment_array[] = $attach_id;
update_field( 'gallery', $attachment_array , $result->post_id );
$wpdb->delete( 'wp_autotrader_image_process', array( 'id' => $result->id ));
}
}
}
I then have cronjob on my server that does this,
*/15 * * * * curl https://Xxxxxx.xxxxxxxxx.com/wp-cron.php > /dev/null 2>&1 >/dev/null 2>&1
This runs the wp-cron file every fifteen minutes.
However I don't think my function is running, can anyone explain to why, or how set this up properly?
Thanks
add this code:
add_action( 'call_process_images_hourly', 'process_images_hourly' );
and update:
wp_schedule_event( time(), 'daily', 'call_process_images_hourly' );

Error http uploading images on Wordpress

I'm working with Imagick and I don't know what happens because when I upload an file "png" or "jpg" It returns:
Error HTTP
but when I upload an file "jpge" it works perfectly.
This is the code on functions.php:
add_filter( 'wp_generate_attachment_metadata', 'generate_watermarked_image' );
function watermark_image( $filename, $upload_dir ) {
$original_image_path = trailingslashit( $upload_dir['path'] ) . $filename;
$image_resource = new Imagick( $original_image_path );
$watermark_resource = new Imagick( get_stylesheet_directory() . '/images/logo.png' );
$image_resource->compositeImage( $watermark_resource, Imagick::COMPOSITE_DEFAULT, 0, 0 );
return save_watermarked_image( $image_resource, $original_image_path );
}
function save_watermarked_image( $image_resource, $original_image_path ) {
$image_data = pathinfo( $original_image_path );
$new_filename = $image_data['filename'] . '-watermarked.' . $image_data['extension'];
$watermarked_image_path = str_replace($image_data['basename'], $new_filename, $original_image_path);
if ( ! $image_resource->writeImage( $watermarked_image_path ) )
return $image_data['basename'];
unlink( $original_image_path ); // Because that file isn't referred to anymore
return $new_filename;
}
I'm sorry for my english.

yii2 REST api for file upload

Im trying to upload a file image/file type from mobile app and store that image in the backend. Im using Yii2 framework API to do this. And im using postman to check the API. Im running the below in my action.
/*Uploading documents*/
public function actionUploading_doc() {
$uploads = \yii\web\UploadedFile::getInstanceByName('upfile');
print_r($uploads);exit;
if (empty($uploads)){
return "Must upload at least 1 file in upfile form-data POST";
}
foreach ($uploads as $file){
$filename = time() . $image->name;
$path = "uploads/" . $filename;
$file->saveAs($path);
}
}
When i run this as POST method from postman.. and print the value of $uploads im getting empty value. It mean its not coming to controller.
Please help me in solving this.
For me this is what i did without the UploadFile class
/*Uploading documents*/
public function actionUploading() {
$uploads = \yii\web\UploadedFile::getInstanceByName('upfile');
\yii::$app->request->enableCsrfValidation = false;
$filename = $uploads->name;
$path = "http://localhost/projects/YiiRestful/api/web/uploads/".$filename;
$putdata = fopen("php://input", "r");
// make sure that you have /web/upload directory (writeable)
// for this to work
$path = "uploads/".$filename;
$fp = fopen($path, "w");
while ($data = fread($putdata, 1024))
fwrite($fp, $data);
/* Close the streams */
fclose($fp);
fclose($putdata);
}
I would try something like this... (not tested)
public function actionUploadingDoc() { // good practice to use camel case for methods
$uploads = \yii\web\UploadedFile::getInstances('upfile');
if (empty($uploads)){
return false;
// handle error reporting somewhere else
}
$path = 'uploads/'; // set your path
foreach ($uploads as $upload){
$filename = $path . time() .'_'. $upload->name ;
$upload->saveAs($filename);
}
return true;
}
You can use base64 string to uplod. define function inside controller like this
public function base64_to_jpeg($base64_string, $output_file) {
$path="your/real/path/";
// open the output file for writing
$ifp = fopen( $path.$output_file, 'wb' );
// split the string on commas
// $data[ 0 ] == "data:image/png;base64"
// $data[ 1 ] == <actual base64 string>
$data = explode( ',', $base64_string );
if(count($data)>1) {
$dataText=$data[ 1 ];
} else {
$dataText=$base64_string;
}
// we could add validation here with ensuring count( $data ) > 1
fwrite( $ifp, base64_decode( $dataText ) );
// clean up the file resource
fclose( $ifp );
return $output_file;
}
And use inside action as
public function actionUpload(){
$imgName=md5(uniqid()).'.jpg';
$this->base64_to_jpeg($base64_string, $imgName);
}

Download random files as zip

I posted my code a few days back and I am now at this point with it. I have acquired the random files however, when they zip it becomes a zip.cpgz file after unzipping. I am sure that this has something to do with the way I used array in my loop but I am not quite sure of how to fix this.
<?php
//./uploads
$dir = "./uploads";
$nfiles = glob($dir.'*.{aiff}', GLOB_BRACE);
$n=1;
while ($n<=10){
$n ++;
$arr[$n] = rand(2, sizeof($nfiles)-1);
print($arr[$n]);
print(" ");
}
$zip = new ZipArchive();
$zip_name = "zipfile.zip";
if($zip->open($zip_name, ZIPARCHIVE::CREATE)!==TRUE){
$error .= "* Sorry ZIP creation failed at this time";
}
foreach($arr as $file){
$path = "./uploads".$file;
$zip->addFromString(basename($path), file_get_contents($path));
}
$zip->close();
header('Content-Type: application/zip');
header('Content-disposition: attachment; filename='.$zip_name);
readfile('zipfile.zip');
?>
Also if you are kinda lost here is my website I am trying to implement it on. (click the download button)
Recently helped another user get something similar to work ( without the random selection ) and you might find the following useful. This does search a directory for a particular file extension and then randomly select 10 files which get zipped and sent. Change the $sourcedir and $ext to suit - hope it helps.
/* From David Walsh's site - modified */
function create_zip( $files = array(), $destination = '', $overwrite = false ) {
if( file_exists( $destination) && !$overwrite ) { return false; }
$valid_files = array();
if( is_array( $files ) ) {
foreach( $files as $file ) if( file_exists( $file ) ) $valid_files[] = $file;
}
if( count( $valid_files ) ) {
$zip = new ZipArchive();
if( $zip->open( $destination,$overwrite ? ZIPARCHIVE::OVERWRITE : ZIPARCHIVE::CREATE ) !== true) return false;
foreach( $valid_files as $file ) $zip->addFile( $file, pathinfo( $file, PATHINFO_FILENAME ) );
$zip->close();
return file_exists( $destination );
}
return false;
}
/* Simple function to send a file */
function sendfile( $filename=NULL, $filepath=NULL ){
if( file_exists( $filepath ) ){
if( !is_file( $filepath ) or connection_status()!=0 ) return FALSE;
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Pragma: no-cache");
header("Expires: ".gmdate("D, d M Y H:i:s", mktime( date("H")+2, date("i"), date("s"), date("m"), date("d"), date("Y")))." GMT");
header("Content-Type: application/octet-stream");
header("Content-Length: ".(string)( filesize( $filepath ) ) );
header("Content-Disposition: inline; filename={$filename}");
header("Content-Transfer-Encoding: binary\n");
if( $file = #fopen( $filepath, 'rb' ) ) {
while( !#feof( $file ) and ( connection_status()==0 ) ) {
print( fread( $file, 1024*8 ) );
flush();
}
#fclose( $file );
}
return( ( connection_status()==0 ) and !connection_aborted() );
}
}
/* Select a random entry from the array */
function pick( $arr ){
return $arr[ rand( 0, count( $arr )-1 ) ];
}
/* The directory to which the zip file will be written before sending */
$target=__DIR__.'\zipfile.zip';
/* The directory you wish to scan for files or create an array in some other manner */
$sourcedir = 'C:\Temp\temp_uploads';
/* File extension to scan for */
$ext='txt';
/* Placeholder to store files*/
$output=array();
/* Scan the dir, or as mentioned, create an array of files some other way */
$files=glob( realpath( $sourcedir ) . DIRECTORY_SEPARATOR . '*.'.$ext );
/* Pick 10 random files from all possible files */
do{
$rnd=pick( $files );
$output[ $rnd ] = $rnd;
}while( count( $output ) < 10 );
/* streamline array */
$output=array_values($output);
if( $target ) {
/* Zip the contents */
$result=create_zip( $output, $target, true );
/* Send the file - zipped! */
if( $result ) {
$res=call_user_func( 'sendfile', 'zipfile.zip', $target );
if( $res ) unlink( $target );
}
}
You sure it doens't work? I've donwloaded your zip file and extracted it and I got UploadsX files. So I don't get a zip.cpgz file.

Laravel: Save Base64 .png file to public folder from controller

I send a png image file to controller in base64 via Ajax. I've already test and sure that controller has received id but still can't save it to public folder.
Here is my controller
public function postTest() {
$data = Input::all();
//get the base-64 from data
$base64_str = substr($data->base64_image, strpos($data->base64_image, ",")+1);
//decode base64 string
$image = base64_decode($base64_str);
$png_url = "product-".time().".png";
$path = public_path('img/designs/' . $png_url);
Image::make($image->getRealPath())->save($path);
// I've tried using
// $result = file_put_contents($path, $image);
// too but still not working
$response = array(
'status' => 'success',
);
return Response::json( $response );
}
Intervention Image gets binary data using file_get_content function:
Reference : Image::make
Your controller should be look like this:
public function postTest() {
$data = Input::all();
$png_url = "product-".time().".png";
$path = public_path().'img/designs/' . $png_url;
Image::make(file_get_contents($data->base64_image))->save($path);
$response = array(
'status' => 'success',
);
return Response::json( $response );
}
$data = Input::all();
$png_url = "perfil-".time().".jpg";
$path = public_path() . "/img/designs/" . $png_url;
$img = $data['fileo'];
$img = substr($img, strpos($img, ",")+1);
$data = base64_decode($img);
$success = file_put_contents($path, $data);
print $success ? $png_url : 'Unable to save the file.';
$file = base64_decode($request['image']);
$safeName = str_random(10).'.'.'png';
$success = file_put_contents(public_path().'/uploads/'.$safeName, $file);
print $success;
This is an easy mistake.
You are using public_path incorrectly. It should be:
$path = public_path() . "/img/designs/" . $png_url;
Also, I would avoid your method of sending the image. Look at a proper upload in a form and use Laravel's Input::file method.
My solution is:
public function postTest() {
$data = Input::all();
//get the base-64 from data
$base64_str = substr($data->base64_image, strpos($data->base64_image, ",")+1);
//decode base64 string
$image = base64_decode($base64_str);
Storage::disk('local')->put('imgage.png', $image);
$storagePath = Storage::disk('local')->getDriver()->getAdapter()->getPathPrefix();
echo $storagePath.'imgage.png';
$response = array(
'status' => 'success',
);
return Response::json( $response );
}
what am i doing is using basic way
$file = base64_decode($request['profile_pic']);
$folderName = '/uploads/users/';
$safeName = str_random(10).'.'.'png';
$destinationPath = public_path() . $folderName;
file_put_contents(public_path().'/uploads/users/'.$safeName, $file);
//save new file path into db
$userObj->profile_pic = $safeName;
}
Store or save base64 images in the public folder image and return file path.
$folderPath = public_path() . '/' . 'images/';
$image_parts = explode(";base64,", $image);
$image_type_aux = explode("image/", $image_parts[0]);
$image_type = $image_type_aux[1];
$image_base64 = base64_decode($image_parts[1]);
$uniqid = uniqid();
$file = $folderPath . $uniqid . '.' . $image_type;
file_put_contents($file, $image_base64);
return $file;
Actually, Input::all() returns an array of inputs so you have following:
$data = Input::all();
Now your $data is an array not an object so you are trying to access the image as an object like:
$data->base64_image
So, it's not working. You should try using:
$image = $data['base64_image'];
Since it's (base64_image) accessible from $_POST then Input::file('base64_image') won't work because Input::file('base64_image') checks the $_FILES array and it's not there in your case.
Here is my solution for the file upload from base_64.
public static function uploadBase64File(Request $request, $requestName = 'imageData', $fileName = null, $uploadPath = 'uploads/images/')
{
try {
$requestFileData = $request->$requestName;
// decode the base64 file
$file = base64_decode(preg_replace(
'#^data:([^;]+);base64,#',
'',
$request->input($requestName)
));
if (in_array($file, ["", null, ' '])) {
return null;
}
//handle base64 encoded images here
if ($fileName == null) {
$fileName = Str::random(10);
}
$extension = '.' . explode('/', explode(':', substr($requestFileData, 0, strpos($requestFileData, ';')))[1])[1];
$filePath = $uploadPath . '' . $fileName . '' . $extension;
// dd($extension);
if (!File::exists(public_path($uploadPath))) {
File::makeDirectory(public_path($uploadPath), 0777, true);
}
// dd($filePath);
$ifImageUploadSuccessful = File::put(public_path($filePath), $file);
if (!$ifImageUploadSuccessful) {
return null;
}
return '/' . $filePath;
// throw new Exception("Unable To upload Image");
} catch (Exception $e) {
// dd($e);
throw new Exception($e->getMessage());
}
}
I'v done it!!
I replaced
$data->base64_image to $_POST['base64_image'] and then use
$result = file_put_contents($path, $image);
instead of Image::make($image->getRealPath())->save($path);
But this doesn't look like a laravel ways. I you have another way that look more elegant please tell me!

Categories