Validate a base64 decoded image in laravel - php

Im trying to get a image from a PUT request for update a user picture(using postman), and make it pass through a validation in Laravel 5.2, for making the call in postman use the following url:
http://localhost:8000/api/v1/users?_method=PUT
and send the image string in the body, using a json like this:
{
"picture" : "data:image/png;base64,this-is-the-base64-encode-string"
}
In the controller try a lot of differents ways for decode the image and try to pass the validation:
First I tried this:
$data = request->input('picture');
$data = str_replace('data:image/png;base64,', '', $data);
$data = str_replace(' ', '+', $data);
$image = base64_decode($data);
$file = app_path() . uniqid() . '.png';
$success = file_put_contents($file, $image);
Then I tried this:
list($type, $data) = explode(';', $data);
list(, $data) = explode(',', $data);
$data = base64_decode($data);
$typeFile = explode(':', $type);
$extension = explode('/', $typeFile[1]);
$ext = $extension[1];
Storage::put(public_path() . '/prueba.' . $ext, $data);
$contents = Storage::get(base_path() . '/public/prueba.png');
Try to use the intervention image library (http://image.intervention.io/) and don't pass:
$image = Image::make($data);
$image->save(app_path() . 'test2.png');
$image = Image::make(app_path() . 'test1.png');
This is the validation in the controller:
$data = [
'picture' => $image,
'first_name' => $request->input('first_name'),
'last_name' => $request->input('last_name')
];
$validator = Validator::make($data, User::rulesForUpdate());
if ($validator->fails()) {
return $this->respondFailedParametersValidation('Parameters failed validation for a user picture');
}
this is the validation in the User-model:
public static function rulesForUpdate() {
return [
'first_name' => 'max:255',
'last_name' => 'max:255',
'picture' => 'image|max:5000|mimes:jpeg,png'
];
}

If you are using Intervention anyways, then you can leverage it for a custom validation rule. I have one called "imageable". It basically makes sure that the input given will be able to be converted to an Intervention image. Base64 data image strings will pass. A string of "foo" will not.
Validator::extend('imageable', function ($attribute, $value, $params, $validator) {
try {
ImageManagerStatic::make($value);
return true;
} catch (\Exception $e) {
return false;
}
});
This obviously just checks that the input is able to be converted to an image. However, it should show you as a use-case how you can leverage Intervention and any of it's methods to create a custom rule.

You can extend the Validator class of Laravel.
Laravel Doc
But anyway try this
Validator::extend('is_png',function($attribute, $value, $params, $validator) {
$image = base64_decode($value);
$f = finfo_open();
$result = finfo_buffer($f, $image, FILEINFO_MIME_TYPE);
return $result == 'image/png';
});
Don't forget the rules:
$rules = array(
'image' => 'is_png'
);

inside extend function add this
$res= mime_content_type($value);
if ($res == 'image/png' || $res == 'image/jpeg') {
return $res;
}

Related

laravel - check and update queued job status to db

Currently I am setting up a queue to insert data from CSV files to the DB using file upload. The queue and data extraction is working currently, but I am looking for a way to check whether the job has been completed, failed or still in process. Is it possible to achieve this and update the status of uploaded file in other DB table as well?
Jobs
Redis::throttle('upload-csv')->allow(1)->every(20)->then(function () {
dump('Processing this file:---',$this->file);
$data = array_map('str_getcsv',file($this->file));
foreach($data as $row){
CSVDataList::updateOrCreate([
'KEY_1' => $row[0],
],[
'KEY_2' => $row[1],
'KEY_3' => $row[2],
'KEY_4' => $row[3],
]);
}
dump('Done for this file:---',$this->file);
unlink($this->file);
}, function () {
return $this->release(10);
});
Controller
$request->validate([
'file' => 'required|mimes:csv,txt'
]);
$filename = $file->getClientOriginalName();
$file = file($request->file->getRealPath());
$data = array_slice($file,1);
$parts = (array_chunk($data,5000));
foreach($parts as $index=>$part){
$fileName = resource_path('pending-files/'.date('y-m-d-H-i-s').$index.'.csv');
file_put_contents($fileName,$part);
}
(new CSVDataList())->importToDb($filename);
session()->flash('status','Queued for importing..');
return redirect('file-upload');
Function in Model
public function importToDb($filename)
{
$path = resource_path('pending-files/*.csv');
$files = glob($path);
foreach($files as $file){
ProcessCsvUpload::dispatch($filename,$file);
}
}

undefined variable while i defined it

so im trying to make sure that if i upload an imagefile (a profile update for my user) that i'm fetching the filepath but i get an Undefined variable:imagePath error.
so i tried to dd my imagepath but it came out with noting while i do define it.
i want to put the filepath here
$data = request()->validate([
'title' => 'required',
'description' => 'required',
'url' => 'url',
'image' => '', //filepath here
]);
here i define it.
if(request('image'))
{
$imagePath = request('image')->store('profile', 'public'); //here i define the variable
$image = Image::make(public_path("storage/{$imagePath}"))->fit(1000, 1000); // here i try to use it
$image->save();
}
dd(array_merge(
$data,
['image' => $imagePath] //the error occurs here while trying to merge
));
so i expected this array merge to give me a readable path but i get an error instead. i might've made a spelling mistake somewehre as english is not my first language but i read over my code and it all looks to be okay.
remove the {}
$image = Image::make(public_path("storage/$imagePath"))->fit(1000, 1000);
or concatenate separately
$image = Image::make(public_path('storage/'.$imagePath))->fit(1000, 1000);
Let's say $imagePath = 'randomString', the code will try to get the variable named randomString if you use it like this {$imagePath}.
We use this trick to call dynamic variables.
$textVariable = 'this text';
$text2 = 'textVariable';
echo ${$text2}; // will echo "this text"
try this
if($request->image)
{
$imagePath = $request->image->store('profile', 'public'); //here i define the variable
$image = Image::make(public_path("storage/".$imagePath))->fit(1000, 1000); // here i try to use it
$image->save();
}
dd(array_merge(
$data,
['image' => $imagePath] //the error occurs here while trying to merge
));
I just change your request('image') to $request->image and remove the {} here $image = Image::make(public_path("storage/".$imagePath))->fit(1000, 1000);
I assume that you're in controller and you have Request $request
Hope it helps.
else {
$sqlit_del_imgs = explode(",", "$delelte_product_images");
foreach($split_del_prd_imgs as $img_name) {
unlink("products_img/" . $_GET["prd_id"] ."/" . $img_name);
}

Inserting data by sending PUT request in CodeIgniter (Phil Sturgeon Rest Server)

There is a difference between a PUT and POST request I send through a REST CLIENT in my API. It is implemented in CodeIgniter with Phil Sturgeon's REST server.
function station_put(){
$data = array(
'name' => $this->input->post('name'),
'number' => $this->input->post('number'),
'longitude' => $this->input->post('longitude'),
'lat' => $this->input->post('latitude'),
'typecode' => $this->input->post('typecode'),
'description' => $this->input->post('description'),
'height' => $this->input->post('height'),
'mult' => $this->input->post('mult'),
'exp' => $this->input->post('exp'),
'elevation' => $this->input->post('elevation')
);
$id_returned = $this->station_model->add_station($data);
$this->response(array('id'=>$id_returned,'message'=>"Successfully created."),201);
}
this request successfully inserts data into the server BUT - it renders the rest of the values NULL except for the id.
But if you change the function name into station_post, it inserts the data correctly.
Would somebody please point out why the PUT request does not work? I am using the latest version of google chrome.
Btw this API will be integrated to a BackBone handled app. Do I really need to use PUT? Or is there another workaround with the model saving function in backbone when using post?
Finally answered. Instead of $this->input->post or $this->input->put, it must be $this->put or $this->post because the data is not coming from a form.
Codeigniter put_stream also failing to fetch put data, therefore I had to handle php PUT request and I found this function useful enough to save someone's time:
function parsePutRequest()
{
// Fetch content and determine boundary
$raw_data = file_get_contents('php://input');
$boundary = substr($raw_data, 0, strpos($raw_data, "\r\n"));
// Fetch each part
$parts = array_slice(explode($boundary, $raw_data), 1);
$data = array();
foreach ($parts as $part) {
// If this is the last part, break
if ($part == "--\r\n") break;
// Separate content from headers
$part = ltrim($part, "\r\n");
list($raw_headers, $body) = explode("\r\n\r\n", $part, 2);
// Parse the headers list
$raw_headers = explode("\r\n", $raw_headers);
$headers = array();
foreach ($raw_headers as $header) {
list($name, $value) = explode(':', $header);
$headers[strtolower($name)] = ltrim($value, ' ');
}
// Parse the Content-Disposition to get the field name, etc.
if (isset($headers['content-disposition'])) {
$filename = null;
preg_match(
'/^(.+); *name="([^"]+)"(; *filename="([^"]+)")?/',
$headers['content-disposition'],
$matches
);
list(, $type, $name) = $matches;
isset($matches[4]) and $filename = $matches[4];
// handle your fields here
switch ($name) {
// this is a file upload
case 'userfile':
file_put_contents($filename, $body);
break;
// default for all other files is to populate $data
default:
$data[$name] = substr($body, 0, strlen($body) - 2);
break;
}
}
}
return $data;
}

How do I write an image, along with other data, to my database using php and mysql

Hello: I have a web form that submits data to my db. I am able to create a signature image and save it within my directory. I want to save/store that signature image in my mysql db along with the record so I can call it later.
Written in CodeIgniter 2.0
here are my model and controller.
public function sig_to_img()
{
if($_POST){
require_once APPPATH.'signature-to-image.php';
$json = $_POST['output'];
$img = sigJsonToImage($json);
imagepng($img, 'signature.png');
imagedestroy($img);
$form = $this->input->post();
var_dump($form);
$this->coapp_mdl->insert_signature($form);
}
}
public function insert_signature($data)
{
$sig_hash = sha1($data['output']);
$created = time();
$ip = $_SERVER['REMOTE_ADDR'];
$data = array(
'first_name' => $data['fname'],
'last_name' => $data['lname'],
'signator' => $data['name'],
'signature' => $data['output'],
'sig_hash' => $sig_hash,
'ip' => $ip,
'created' => $created
);
return $this->db->insert('signatures', $data);
}
I found the function below on php.net but apparently I am doing something wrong or various things wrong. Does anyone know how to accomplish this functionality?
$imagefile = "changethistogourimage.gif";
$image = imagecreatefromgif($imagefile);
ob_start();
imagepng($image);
$imagevariable = ob_get_contents();
ob_end_clean();
Got it - For those curious here are the changes to my controller:
public function sig_to_img()
{
if($_POST){
require_once APPPATH.'signature-to-image.php';
$json = $_POST['output'];
$img = sigJsonToImage($json);
// Save to file
$file_name = trim(str_replace(" ","_",$_POST['name']));//name to used for filename
imagepng($img, APPPATH."../images/signatures/".$file_name.'.png');
$sig_name = $file_name.'.png'; //pass to model
// Destroy the image in memory when complete
imagedestroy($img);
$form = $this->input->post();
var_dump($form);
$this->coapp_mdl->insert_signature($form, $sig_name);
}
}

setting album art of a mp3 with php

I am looking for the best or any way to set the Album Art of mp3s using PHP.
Suggestions?
Album art is a data frame identified as “Attached picture” due ID3v2 specification, and
getID3() now is only one way to write all possible data frames in ID3v2 with pure PHP.
Look at this source:
http://getid3.sourceforge.net/source/write.id3v2.phps
Search for this text in the source:
// 4.14 APIC Attached picture
there's a piece of code responsible for writing album art.
Another way, that seems to be not as slow as pure PHP, is to use some external application, that will be launched by PHP script. If your service designed to work under a high load, binary compiled tool will be a better solution.
A better (faster) way to do this would be through an external application and the PHP exec() function to fun a command. I would recommend eyeD3.
Not sure this is still an issue but:
the amazingly complete getid3() (http://getid3.org) project will solve all your problems. Check out this forum post for more info.
Rather than just share the code for album art update, I an going to post my entire MP3 wrapper class of getID3 here so you can use as you wish
Usage
$mp3 = new Whisppa\Music\MP3($mp3_filepath);
//Get data
$mp3->title
$mp3->artist
$mp3->album
$mp3->genre
//set properties
$mp3->year = '2014';
//change album art
$mp3->set_art(file_get_contents($pathtoimage), 'image/jpeg', 'New Caption');//sets front album art
//save new details
$mp3->save();
Class
<?php
namespace Whisppa\Music;
class MP3
{
protected static $_id3;
protected $file;
protected $id3;
protected $data = null;
protected $info = ['duration'];
protected $tags = ['title', 'artist', 'album', 'year', 'genre', 'comment', 'track', 'attached_picture', 'image'];
protected $readonly_tags = ['attached_picture', 'comment', 'image'];
//'popularimeter' => ['email'=> 'music#whisppa.com', 'rating'=> 1, 'data'=> 0],//rating: 5 = 255, 4 = 196, 3 = 128, 2 = 64,1 = 1 | data: counter
public function __construct($file)
{
$this->file = $file;
$this->id3 = self::id3();
}
public function update_filepath($file)
{
$this->file = $file;
}
public function save()
{
$tagwriter = new \GetId3\Write\Tags;
$tagwriter->filename = $this->file;
$tagwriter->tag_encoding = 'UTF-8';
$tagwriter->tagformats = ['id3v2.3', 'id3v1'];
$tagwriter->overwrite_tags = true;
$tagwriter->remove_other_tags = true;
$tagwriter->tag_data = $this->data;
// write tags
if ($tagwriter->WriteTags())
return true;
else
throw new \Exception(implode(' : ', $tagwriter->errors));
}
public static function id3()
{
if(!self::$_id3)
self::$_id3 = new \GetId3\GetId3Core;
return self::$_id3;
}
public function set_art($data, $mime = 'image/jpeg', $caption = 'Whisppa Music')
{
$this->data['attached_picture'] = [];
$this->data['attached_picture'][0]['data'] = $data;
$this->data['attached_picture'][0]['picturetypeid'] = 0x03; // 'Cover (front)'
$this->data['attached_picture'][0]['description'] = $caption;
$this->data['attached_picture'][0]['mime'] = $mime;
return $this;
}
public function __get($key)
{
if(!in_array($key, $this->tags) && !in_array($key, $this->info) && !isset($this->info[$key]))
throw new \Exception("Unknown property '$key' for class '" . __class__ . "'");
if($this->data === null)
$this->analyze();
if($key == 'image')
return isset($this->data['attached_picture']) ? ['data' => $this->data['attached_picture'][0]['data'], 'mime' => $this->data['attached_picture'][0]['mime']] : null;
else if(isset($this->info[$key]))
return $this->info[$key];
else
return isset($this->data[$key]) ? $this->data[$key][0] : null;
}
public function __set($key, $value)
{
if(!in_array($key, $this->tags))
throw new \Exception("Unknown property '$key' for class '" . __class__ . "'");
if(in_array($key, $this->readonly_tags))
throw new \Exception("Tying to set readonly property '$key' for class '" . __class__ . "'");
if($this->data === null)
$this->analyze();
$this->data[$key] = [$value];
}
protected function analyze()
{
$data = $this->id3->analyze($this->file);
$this->info = [
'duration' => isset($data['playtime_seconds']) ? ceil($data['playtime_seconds']) : 0,
];
$this->data = isset($data['tags']) ? array_intersect_key($data['tags']['id3v2'], array_flip($this->tags)) : [];
$this->data['comment'] = ['http://whisppa.com'];
if(isset($data['id3v2']['APIC']))
$this->data['attached_picture'] = [$data['id3v2']['APIC'][0]];
}
}
Note
There isn't any error handling code yet. Currently, I am just relying on exceptions when I try to run any operations.
Feel free to modify and use as fit. Requires PHP GETID3
Install getId3 using composer composer require james-heinrich/getid3
Then Use this code to update your id3 tags
// Initialize getID3 engine
$getID3 = new getID3;
// Initialize getID3 tag-writing module
$tagwriter = new getid3_writetags;
$tagwriter->filename = 'path/to/file.mp3';
$tagwriter->tagformats = array('id3v2.4');
$tagwriter->overwrite_tags = true;
$tagwriter->remove_other_tags = true;
$tagwriter->tag_encoding = 'UTF-8';
$pictureFile = file_get_contents("path/to/image.jpg");
$TagData = array(
'title' => array('My Title'),
'artist' => array('My Artist'),
'album' => array('This Album'),
'comment' => array('My comment'),
'year' => array(2018),
'attached_picture' => array(
array (
'data'=> $pictureFile,
'picturetypeid'=> 3,
'mime'=> 'image/jpeg',
'description' => 'My Picture'
)
)
);
$tagwriter->tag_data = $TagData;
// write tags
if ($tagwriter->WriteTags()){
return true;
}else{
throw new \Exception(implode(' : ', $tagwriter->errors));
}
You can look into the getID3() project. I can't promise that it can handle images but it does claim to be able to write ID3 tags for MP3s so I think it will be your best bet.
Here is the basic code for adding an image and ID3 data using getID3. (#frostymarvelous' wrapper includes equivalent code, however I think that it is helpful to show the basics.)
<?php
// Initialize getID3 engine
$getID3 = new getID3;
// Initialize getID3 tag-writing module
$tagwriter = new getid3_writetags;
$tagwriter->filename = 'audiofile.mp3';
$tagwriter->tagformats = array('id3v2.3');
$tagwriter->overwrite_tags = true;
$tagwriter->remove_other_tags = true;
$tagwriter->tag_encoding = $TextEncoding;
$pictureFile=file_get_contents("image.jpg");
$TagData = array(
'title' => 'My Title',
'artist' => 'My Artist',
'attached_picture' => array(
array (
'data'=> $pictureFile,
'picturetypeid'=> 3,
'mime'=> 'image/jpeg',
'description' => 'My Picture'
)
)
);
?>
#carrp the $Tagdata code won't work unless each value property is an array e.g.
$TagData = array(
'title' => ['My Title'],
'artist' => ['My Artist'],
'attached_picture' => array(
array (
'data'=> $pictureFile,
'picturetypeid'=> 3,
'mime'=> 'image/jpeg',
'description' => 'My Picture'
)
)
);
Use this inbuilt function of PHP,
<?php
$tag = id3_get_tag( "path/to/example.mp3" );
print_r($tag);
?>
I don't think it's really possible with PHP. I mean, I suppose anything is possible but it may not be a native PHP solution. From the PHP Docs, I think the only items that can be updated are:
Title
Artists
Album
Year
Genre
Comment
Track
Sorry man. Maybe Perl, Python, or Ruby might have some solution.
I'm not sure if you are familiar with Perl (I personally don't like it, but, it's good at things like this...). Here's a script that seems to be able to pull in and edit album art in an MP3: http://www.plunder.com/-download-66279.htm

Categories