I have this jquery code in a view, relating to my uploads controller:
function screenshot(){
var dataUrl = renderer.domElement.toDataURL("image/png");
$.post("picturepicker", {dataUrl: dataUrl, uploadnumber: 2
}
}
It successfully sends data to this function:
public function picturepicker(){
...
if($this->request->is('post')){
define('UPLOAD_DIR', WWW_ROOT . 'img/'); // increase validation
$img = $_POST['dataUrl']; // Tried $this->request['dataURL'], retrieved 'dataURL' just fine
$upload = $_POST['uploadnumber']; // tried $this->request['uploadnumber'], did not retrieve 'uploadnumber'
$img = str_replace('data:image/png;base64,', '', $img);
$img = str_replace(' ', '+', $img);
$data = base64_decode($img);
$file = UPLOAD_DIR . $upload . '.png'; // UPLOAD_DIR . uniqid() . '.png';
$success = file_put_contents($file, $data);
print $success ? $file : 'Unable to save the file.';
Which works fine, except that every time I ran the javascript, a new database row is created. Since I have no create function, I imagine that somehow jquery is inadvertently calling this function:
public function upload(){
if ($this->request->is('post')) {
//var_dump($this->request->data);
$this->Upload->create();
....
However, I doubt that since the rows are still added even when I delete all references to the create function.
So why might this happen, and how should I fix it? I am suspecting that somehow the jquery code is calling all of my functions, and that I need to put an if block around any of the others that take post data. I have been told that this should not be the case, and that perhaps cake's routing is to blame. Alternatively, I might have missed something in the cake documentation - perhaps cake is set up to make a new DB row for EVERY post request, and I need to tell it not to somehow.
Related
I have a WordPress issue and want to simply write log messages to a text file. I am aware that error_log exists, but want to have a more segregated log file for different messages.
I am using wp_filesystem->put_contents, and it DOES write to the file and succeeds, but it ONLY outputs the last call's data.
I have the following method:
public static function log_message($msg) {
error_log($msg);
require_once(ABSPATH . 'wp-admin/includes/file.php');
global $wp_filesystem;
if ( ! is_a( $wp_filesystem, 'WP_Filesystem_Base') ){
$creds = request_filesystem_credentials( site_url() );
wp_filesystem($creds);
}
$bt = debug_backtrace();
$caller = array_shift($bt);
$logStr = date("Y-m-d hh:ii A",time())." - ".$caller['file'].":".$caller['line']." - ".$msg;
$filePathStr = SRC_DIR.DIRECTORY_SEPARATOR.$logFileName;
$success = $wp_filesystem->put_contents(
$filePathStr,
$logStr,
FS_CHMOD_FILE // predefined mode settings for WP files
);
if(!$success) {
error_log("Writing to file \"".$filePathStr."\" failed.");
} else {
error_log("Writing to file \"".$filePathStr."\" succeeded.");
}
}
I call it using:
log_message("\nTest 1");
log_message("\nTest 2");
log_message("\nTest 3");
The output is ALWAYS ONLY Test 3 with the other invocations being ignored yet, their output appears in the debug.log as well as all the success messages.
Why would this be?
Looking at the WPCodex for the source code of this, it uses fwrite behind the scenes. The file is closed in this code, and I cannot use any "flush" technique.
Is there a way to figure this out?
I found that the source of WP_Filesystem uses file_put_contents (as the name does suggest), and I assumed this is for APPENDING to the file's data.
This is incorrect.
This function is to take data, and then WRITE it to the file, erasing prior data.
Mainly useful for creating resources, downloading a file, etc.
If I want to APPEND to a file, I need to use 'fwrite'.
This post describes that.
This is the example to APPEND to a file:
$filepath = '\path\to\file\';
$filename = 'out.log';
$fullpath = $filepath.$filename;
if(file_exists($fullpath)) {
$file = fopen($filepath.$filename, "a");//a for append -- could use a+ to create the file if it doesn't exist
$data = "test message";
fwrite($file, "\n". $data);
fclose($file);
} else {
error_log("The file \'".$fullpath."\' does not exist.");
}
The fopen docs describe this method and it's modes.
I'm using the storage facade to store an avatar which works fine, but I want to resize my image like I did in previous versions of Laravel.
How can I go about doing this?
Here is what I have so far (doesn't work)
$path = $request->file('createcommunityavatar');
$resize = Image::make($path)->fit(300);
$store = Storage::putFile('public/image', $resize);
$url = Storage::url($store);
Error Message:
Command (hashName) is not available for driver (Gd).
You're trying to pass into putFile wrong object. That method expects File object (not Image).
$path = $request->file('createcommunityavatar');
// returns \Intervention\Image\Image - OK
$resize = Image::make($path)->fit(300);
// expects 2nd arg - \Illuminate\Http\UploadedFile - ERROR, because Image does not have hashName method
$store = Storage::putFile('public/image', $resize);
$url = Storage::url($store);
Ok, now when we understand the main reason, let's fix the code
// returns Intervention\Image\Image
$resize = Image::make($path)->fit(300)->encode('jpg');
// calculate md5 hash of encoded image
$hash = md5($resize->__toString());
// use hash as a name
$path = "images/{$hash}.jpg";
// save it locally to ~/public/images/{$hash}.jpg
$resize->save(public_path($path));
// $url = "/images/{$hash}.jpg"
$url = "/" . $path;
Let's imagine that you want to use Storage facade:
// does not work - Storage::putFile('public/image', $resize);
// Storage::put($path, $contents, $visibility = null)
Storage::put('public/image/myUniqueFileNameHere.jpg', $resize->__toString());
The put method works with the Image intervention output.
The putFile method accepts either an Illuminate\Http\File or Illuminate\Http\UploadedFile instance.
$photo = Image::make($request->file('photo'))
->resize(400, null, function ($constraint) { $constraint->aspectRatio(); } )
->encode('jpg',80);
Storage::disk('public')->put( 'photo.jpg', $photo);
The above code resizes the uploaded file to 400px width while holding the aspect ratio. Then encodes to jpg at 80% quality.
The file is then stored to the public disc.
Note you must provide a filename, not just the directory.
Using Laravel 5.8
I had a similar issue when trying to read an image file with Image when this one was saved and loaded with Storage.
Beside all the answers I wasn't sure why it wasn't working.
Exception when Image was trying to read the file
Intervention\Image\Exception\NotReadableException : Unable to init from given binary data.
Short answer
Adding ->encode()solved the issue
http://image.intervention.io/api/encode
Scenario
Basically I had a test like this
Storage::fake();
$photo = factory(Photo::class)->create();
$file = \Image::make(
UploadedFile::fake()->image($photo->file_name, 300, 300)
);
Storage::disk($photo->disk)
->put(
$photo->fullPath(),
$file
);
And in the controller I had something like this
return \Image::make(
Storage::disk($photo->disk)
->get(
$photo->fullPath()
)
)->response();
Solution
After investigation I realized that any file created by Image and saved by the Storage had a size of 0 octets.
After looking at all the solutions from this post and few hours after, I noticed everyone was using encode() but no one did mention it was that. So I tried and it worked.
Investigating a bit more, Image does, in fact, encode under the hood before saving.
https://github.com/Intervention/image/blob/master/src/Intervention/Image/Image.php#L146
So, my solution was to simple doing this
$file = \Image::make(
\Illuminate\Http\UploadedFile::fake()->image('filename.jpg', 300, 300)
)->encode();
\Storage::put('photos/test.jpg', $file);
testable in Tinker, It will create a black image
The cleanest solution I could find—using the native Storage facade—is the following. I can confirm that this works in Laravel 5.7, using intervention/image version 2.4.2.
$file = $request->file('avatar');
$path = $file->hashName('public/avatars');
$image = Image::make($file)->fit(300);
Storage::put($path, (string) $image->encode());
$url = Storage::url($path);
I do it this way:
Resize and save image somewhere (such as in the public folder).
Create a new File and pass it to Laravel filesystem functions (such as putFileAs).
Delete temporary intervention file
Note: Of course you can modify it according to your needs.
$file = $request->file('portfolio_thumb_image');
$image = Image::make($file);
$image->resize(570, 326, function ($constraint) {
$constraint->aspectRatio();
});
$thumbnail_image_name = pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME).'.'.$file->getClientOriginalExtension();
$image->save(public_path('images/'.$thumbnail_image_name));
$saved_image_uri = $image->dirname.'/'.$image->basename;
//Now use laravel filesystem.
$uploaded_thumbnail_image = Storage::putFileAs('public/thumbnails/'.$portfolio_returned->id, new File($saved_image_uri), $thumbnail_image_name);
//Now delete temporary intervention image as we have moved it to Storage folder with Laravel filesystem.
$image->destroy();
unlink($saved_image_uri);
Make sure to add use Illuminate\Http\File; to top of your file for this to work, and read through the documentation section Automatic Streaming.
This assumes you want all jpegs
$path = $request->file('createcommunityavatar');
$resize = Image::make($path)->fit(300)->encode('jpg');
$filePath = $resize->getRealPath() . '.jpg';
$resize->save($filePath);
$store = Storage::putFile('public/image', new File($resize));
$url = Storage::url($store);
This is how I am doing it in my application with comments to help
// Get the file from the request
$requestImage = request()->file('image');
// Get the filepath of the request file (.tmp) and append .jpg
$requestImagePath = $requestImage->getRealPath() . '.jpg';
// Modify the image using intervention
$interventionImage = Image::make($requestImage)->resize(125, 125)->encode('jpg');
// Save the intervention image over the request image
$interventionImage->save($requestImagePath);
// Send the image to file storage
$url = Storage::putFileAs('photos', new File($requestImagePath), 'thumbnail.jpg');
return response()->json(['url' => $url]);
I've done it with following way, its simple and without any path confusion :
//Get file
$path= $request->file('createcommunityavatar');
// Resize and encode to required type
$img = Image::make($file)->fit(300)->encode('jpg');
//Provide own name
$name = time() . '.jpg';
//Put file with own name
Storage::put($name, $img);
//Move file to your location
Storage::move($name, 'public/image/' . $name);
Try updating the GD extension for the current php version.
If that doesn't help, try saving the resized image on local disk and using Storage::putFile.
You may delete the file once it has been uploaded to your storage path.
The second parameter to your putFile method is an instance of the Image Intervention class. You need to pass this as the second parameter to the putFile method.
$resize->save($absolutePath . 'small/' . $imageName);
You can't store an \Intervention\Image\Image object directly with the Laravel 5 filesystem. What you can do is resize the image from your request, and save it under the same tmp path. Then just store the uploaded (overwritten) file to the filesystem.
Code:
$image = $request->file('createcommunityavatar');
//resize and save under same tmp path
$resize = Image::make($image)->fit(300)->save();
// store in the filesystem with a generated filename
$store = $image->store('image', 'public');
// get url from storage
$url = Storage::url($store);
In my case the error was caused by calling the hashName method on an image instance.
//initially
$image = Image::make(request('image')->getRealPath());
$filename = $image->hashName();
//to fix the error
$image = Image::make(request('image')->getRealPath());
$filename = request('image')->hashName();
First of all, I should say that this is a WordPress based question, which I originally asked on the WordPress StackExchange, here. But I think it's turned into a more PHP-based question so that's why I'm asking here.
So basically, I've written this preg_replace_callback function, which, on saving/publishing the post, will replace all of the image URLs with URLs from the WP Uploads directory. I've had fleeting success with this; sometimes it works, but only on one of the URLs (in my test examples on my site I have 3 img tags, each split up with paragraphs.
Here is my code:
add_filter('content_save_pre', 'getpostimgs'); // content_save_pre filter may be depreceated? => http://adambrown.info/p/wp_hooks/hook/content_save_pre
function getpostimgs() {
global $post;
$postContent = $post->post_content;
$content = preg_replace_callback(
'/<img.+src=[\'"]([^\'"]+)[\'"].*>/i', // pattern to match to (i.e the contents of an <img src="..." /> tag)
function ($match) {
$imgURL = $match[1]; // the second array (#1) (0-based) is the array with the URLs in. First array (#0) has the whole img tag in.
$image_data = file_get_contents($imgURL); // Get image data
$filename = basename($imgURL) . "-" . $post->ID . ".jpg"; // Create image file name
if( wp_mkdir_p( $upload_dir['path'] ) ) { // check upload file exists and the permissions on it are correct
$file = $upload_dir['path'] . '/' . $filename;
} else {
$file = $upload_dir['basedir'] . '/' . $filename;
} // save file to server
file_put_contents( $file, $image_data ); // save the file to the server
return $file;
},
$postContent
);
return $content;
}
I've added some comments along the way to hopefully explain what I'm doing at each stage. I'm not a PHP wizard (I mainly do WordPress PHP) so be nice! Also, as I put in the comments, the WordPress filter I'm using, content_save_pre, which is supposed to edit the content before being saved to the database, has been depreciated. But that's a WordPress issue, so I'll consult the guys on the WordPress Stackexchange about that one.
Anyway, my main problem is that when I hit save, the content is completely wiped. As I said above, I've had fleeting success - sometimes it will replace maybe one of the URLs, other times it won't, and most of the time it simply wipes all the content. I'm assuming there's something wrong with the preg_replace_callback.
Lastly: as you may have seen from the link I posted to the Wordpress StackExchange (right at the top), I originally coded this up by using a preg_match_all to find all the image URLs, then used a foreach loop to go through the array of URLs and had a prey_replace to replace the URLs. That code is here if you want to take a look at that. I changed it based on the advice on this thread (correct answer). But both methods act pretty much the same.
Thanks for any help :)
EDIT: I've updated my code a little, made a few silly mistakes regarding global variables/variable scope and a few syntax/WP errors. Here's my updated code:
function getpostimgs() {
global $post;
$postContent = $post->post_content;
$content = preg_replace_callback(
'/<img.+src=[\'"]([^\'"]+)[\'"].*>/i', // pattern to match to (i.e the contents of an <img src="..." /> tag)
function ($match) {
global $post, $postContent;
$upload_dir = wp_upload_dir(); // Set upload folder
$imgURL = $match[1];
$image_data = file_get_contents($imgURL); // Get image data
$filename = basename($imgURL) . "-" . $post->ID . ".jpg"; // Create image file name
if( wp_mkdir_p( $upload_dir['path'] ) ) { // check upload file exists and the permissions on it are correct
$file = $upload_dir['path'] . '/' . $filename;
} else {
$file = $upload_dir['basedir'] . '/' . $filename;
} // save file to server
file_put_contents( $file, $image_data ); // save the file to the server
return $file;
},
$postContent
);
return $content;
}
add_filter('content_save_pre', 'getpostimgs'); // content_save_pre filter may be depreceated? => http://adambrown.info/p/wp_hooks/hook/content_save_pre
If I call this function on a single.php page or something, it will work, i.e. the Original Image URLs in the post content which is returned have been replaced by Upload Directory URLs, so the regex and stuff is correct. However, it doesn't work when I try to publish/update a post (the content is usually wiped). Any ideas?
I'm getting confused about how to save an image content inside of a database table.
Please see the fourth line of code. I'm sure that this restful method (using POST) is working because getSize() returns the true value.
Also, if I debug what returns the 5th line I get something like the next one:
So, I'm not sure if what am I missing to save this data into the database.
$personId = Input::get('PersonId');
$file = Input::file('media');
$tmppath = $file->getRealPath();
$content = file_get_contents($tmppath); //$file->getSize();
// return $content;
$model = Person::find($personId);
$model->Photo = $content;
$model->save();
$result = array(
"success" => true,
"data" => $personId,
"error" => ""
);
You need to save the file to the server and only store the path in the database.
Write an appropriate method, ideally you can store it in a trait.
private function saveFileToDisk($file, $fileName)
{
$path = public_path() . '/uploads/';
return $file->move($path, $fileName . $file->getClientOriginalExtension());
}
An then pass the file input to your method and provide a name for the file:
$model->Photo = $this->saveFileToDisk(Input::file('media'), $model->Name);
Obvisouly you need to validate you input before all this.
I have a php file for uploading a picture (it uploads the picture, creates its thumbnail and also adds watermark to the picture). The file is being called by AJAX.
It was working on on my localhost on Windows XP with WAMPSERVER 2.0. Now I have installed Windows Vista and suddenly it doesn't work properly (the picture gets uploaded but the thumbnail and watermark parts don't work).
I'm using exactly the same software to test the application on my local machine (WAMPSERVER 2.0) yet it doesn't work.
How to debug this file? Here's how it looks:
<?php
define('BASE_PATH', substr(dirname(dirname(__FILE__)), 0, -22));
// set the include path
set_include_path(BASE_PATH
. '/../../library'
. PATH_SEPARATOR
. BASE_PATH
. '/library'
. PATH_SEPARATOR
. get_include_path());
// autoload classes from the library
function __autoload($class) {
include str_replace('_', '/', $class) . '.php';
}
$configuration = new Zend_Config_Ini(BASE_PATH
. '/application'
. '/configs/application.ini',
'development');
$dbAdapter = Zend_Db::factory($configuration->database);
Zend_Db_Table_Abstract::setDefaultAdapter($dbAdapter);
function _getTable($table)
{
include BASE_PATH
. '/application/modules/default/models/'
. $table
. '.php';
return new $table();
}
$albums = _getTable('Albums');
$media = _getTable('Media');
if (false === empty($_FILES)) {
$tempFile = $_FILES['Filedata']['tmp_name'];
$extension = end(explode('.', $_FILES['Filedata']['name']));
// insert temporary row into the database
$data = array();
$data['type'] = 'photo';
$data['type2'] = 'public';
$data['status'] = 'temporary';
$data['user_id'] = $_REQUEST['user_id'];
$paths = $media->add($data, $extension, $dbAdapter);
// save the photo
move_uploaded_file($tempFile,
BASE_PATH . '/public/' . $paths[0]);
// create a thumbnail
include BASE_PATH . '/library/My/PHPThumbnailer/ThumbLib.inc.php';
$thumb = PhpThumbFactory::create('/' . $paths[0]);
$thumb->adaptiveResize(85, 85);
$thumb->save(BASE_PATH . '/public/' . $paths[1]);
// add watermark to the bottom right corner
$pathToFullImage = BASE_PATH . '/public/' . $paths[0];
$size = getimagesize($pathToFullImage);
switch ($extension) {
case 'gif':
$im = imagecreatefromgif($pathToFullImage);
break;
case 'jpg':
$im = imagecreatefromjpeg($pathToFullImage);
break;
case 'png':
$im = imagecreatefrompng($pathToFullImage);
break;
}
if (false !== $im) {
$white = imagecolorallocate($im, 255, 255, 255);
$font = BASE_PATH . '/public/fonts/arial.ttf';
imagefttext($im,
13, // font size
0, // angle
$size[0] - 132, // x axis (top left is [0, 0])
$size[1] - 13, // y axis
$white,
$font,
'HunnyHive.com');
switch ($extension) {
case 'gif':
imagegif($im, $pathToFullImage);
break;
case 'jpg':
imagejpeg($im, $pathToFullImage, 100);
break;
case 'png':
imagepng($im, $pathToFullImage, 0);
break;
}
imagedestroy($im);
}
echo "1";
}
For generally debugging this, you should break the steps down into functions and test each part in turn.
With regard to Ajax debugging, you might like to try out Zend_Log_Writer_FirePHP. It's an extension for Firebug which reads extra data in headers sent by PHP, which means that the data in your response body doesn't contain debug output, and for things like images, can still be rendered.
Once you've installed FirePHP for Firebug, you can just write the following few lines:
$wFirebug = new Zend_Log_Writer_Firebug();
$firebug = new Zend_Log($wFirebug);
$firebug->info($myArray);
$firebug->info('Got to line 10');
When debugging anything that is related to AJAX I would recommend the following:
Ensure that the file is returning the correct data without any AJAX wrapper around it. Call the file directly with some sample data. Does it return what you require? Does it have syntax errors? This is the first thing you want to check and it will save you a ton of headache.
Ensure your Javascript is parsing the data correctly. Your JS may be expecting JSON but you're returning XML, or your returned data is not formatted the way you think, or you may need to evaluate your returned data in Javascript so it can actually be used. Try some console.log()'s to test what your data looks like.
Try something like Postbin which lets you send POST data. Ensure your POST data is correct and you're sending the right data to your script.
You could just create a simple form with a file input and just use that for easy testing.
That is the simplest way that I see, someone else may have something better in mind.
I find that when working with an action being called via AJAX in ZF, it's always a good idea to make sure that the action works without AJAX first. That is, make your first iteration of developing the feature result in going to a new page to represent the action you're making.
Once you know that your PHP code works, you can then begin to worry about making the AJAX stuff work. In my opinion, at least, being able to output Zend_Debug::dump() on variables when you view another page is a lot easier for initial development.
AJAX by design creates a layer of opacity which can makes it difficult to do this. It gets even harder if you're interfacing with, for instance, a jQuery plugin that requires formatted data that you're just not getting for some reason. So again, PHP first, AJAX second. It takes roughly two seconds in ZF to go from a PHP to an AJAX call, and vice versa.
The easiest solution would be to use FirePHP; install firebug + firephp addon for firefox and include the classes in your project.
(I keep the FirePHP library in /usr/share/php/ so I can include it easily in any project)
Then just do this:
require_once('/path/to/FirePHPCore/FirePHP.class.php');
$fp = FirePHP::getInstance(true);
$fp->log('you can put anything here, vars, objects, arrays, etc');
It will output the response in the FireBug console and is much better than polluting your code with echos and var_dumps when debugging ajax!
Make the AJAX request with a callback function, which checks the data returned (echo'd) from the PHP function. If the data echo'd is some pre-determined success string ("success"?) then all is well, if it's not that, have the callback function output whatever is output by the function in an alert or something.