preg_replace_callback returns empty - php

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?

Related

open file on client stored on server

I want to open a server stored html report file on a client machine.
I want to bring back a list of all the saved reports in that folder (scandir).
This way the user can click on any of the crated reports to open them.
So id you click on a report to open it, you will need the location where the report can be opend from
This is my dilemma. Im not sure how to get a decent ip, port and folder location that the client can understand
Here bellow is what Ive been experimenting with.
Using this wont work obviously:
$path = $_SERVER['DOCUMENT_ROOT']."/reports/saved_reports/";
So I though I might try this instead.
$host= gethostname();
$ip = gethostbyname($host);
$ip = $ip.':'.$_SERVER['SERVER_PORT'];
$path = $ip."/reports/saved_reports/";
$files = scandir($path);
after the above code I loop through each file and generate a array with the name, date created and path. This is sent back to generate a list of reports in a table that the user can interact with. ( open, delete, edit)
But this fails aswell.
So im officially clueless on how to approach this.
PS. Im adding react.js as a tag, because that is my front-end and might be useful to know.
Your question may be partially answered here: https://stackoverflow.com/a/11970479/2781096
Get the file names from the specified path and hit curl or get_text() function again to save the files.
function get_text($filename) {
$fp_load = fopen("$filename", "rb");
if ( $fp_load ) {
while ( !feof($fp_load) ) {
$content .= fgets($fp_load, 8192);
}
fclose($fp_load);
return $content;
}
}
$matches = array();
// This will give you names of all the files available on the specified path.
preg_match_all("/(a href\=\")([^\?\"]*)(\")/i", get_text($ip."/reports/saved_reports/"), $matches);
foreach($matches[2] as $match) {
echo $match . '<br>';
// Again hit a cURL to download each of the reports.
}
Get list of reports:
<?php
$path = $_SERVER['DOCUMENT_ROOT']."/reports/saved_reports/";
$files = scandir($path);
foreach($files as $file){
if($file !== '.' && $file != '..'){
echo "<a href='show-report.php?name=".$file. "'>$file</a><br/>";
}
}
?>
and write second php file for showing html reports, which receives file name as GET param and echoes content of given html report.
show-report.php
<?php
$path = $_SERVER['DOCUMENT_ROOT']."/reports/saved_reports/";
if(isset($_GET['name'])){
$name = $_GET['name'];
echo file_get_contents($path.$name);
}

Laravel S3 image upload creates a folder with the filename automatically

I'm using Laravel 5.4.*. I've this simple code in a helper file to upload images/gif in S3 bucket under a folder named say "instant_gifs/". The code is below:
if ( !function_exists('uploadFile') ) {
function uploadFile($fileContent, $fileName, $size='full', $disk='s3')
{
$rv = '';
if( empty($fileContent) ) {
return $rv;
}
if($size == 'full') {
dump($fileName);
$path = Storage::disk($disk)->put(
$fileName,
$fileContent,
'public'
);
}
if ( $path ) {
$rv = $fileName;
}
return $rv;
}
}
From the controller, I'm calling the helper method as below:
$file = $request->gif;
$file_name = 'instant_gifs/' . $user_id . '_' . time() . '_' . $file->getClientOriginalName();
$result = uploadFile($file, $file_name);
In the the $fileName parameter of the helper method, I'm providing the fileName as for example in this format:
"instant_gifs/83_1518596022_giphy.gif"
but after the upload, I see that the file gets stored under this folder
"vvstorage/instant_gifs/83_1518596022_giphy.gif/CRm1o1YEcvX3fAulDeDfwT7DIMCxOKG8WFGcA3lB.gif"
with a random file name
CRm1o1YEcvX3fAulDeDfwT7DIMCxOKG8WFGcA3lB.gif
Whereas, according to the code, it should get stored in this path:
"vvstorage/instant_gifs/83_1518596022_giphy.gif"
Doesn't get any explanation why this is happening. Any clue will be appreciated.
BucketName = vvstorage
Folder I'm mimicking = instant_gifs
After some research & testing, found the issue. put() method expects the 2nd parameter as the file contents or stream not the file object. In my code, I was sending the file as $file = $request->gif; or $file = $request->file('gif'); hoping that Storage class will implicitly get the file contents. But to get the expected result, I needed to call the helper method from the controller as below. Notice the file_get_contents() part.
$file = $request->gif;
$file_name = 'instant_gifs/' . $user_id . '_' . time() . '_' . $file>getClientOriginalName();
$result = uploadFile( file_get_contents($file), $file_name );
Now, I got the image correctly stored under the correct path for example in /instant_gifs/9_1518633281_IMG_7491.jpg.
Now, let me compare/summarize the available methods for achieving the same result:
1) put():
$path = Storage::disk('s3')->put(
'/instant_gifs/9_1518633281_IMG_7491.jpg', #$path
file_get_contents($request->file('gif')), #$fileContent
'public' #$visibility
Got it stored in /vvstorage/instant_gifs/9_1518633281_IMG_7491.jpg
2) putFileAs(): To achieve the same thing withputFileAs(), I needed to write it as below. 1st parameter expects the directory name, I left it blank as I'm mimicking the directory name in s3 through the filename.
$path = Storage::disk('s3')->putFileAs(
'', ## 1st parameter expects directory name, I left it blank as I'm mimicking the directory name through the filename
'/instant_gifs/9_1518633281_IMG_7491.jpg',
$request->file('gif'), ## 3rd parameter file resource
['visibility' => 'public'] #$options
);
Got it stored in /vvstorage/instant_gifs/9_1518633281_IMG_7491.jpg
3) storeAs():
$path = $request->file('gif')->storeAs(
'', #$path
'/instant_gifs/9_1518633281_IMG_7491.jpg', #$fileName
['disk'=>'s3', 'visibility'=>'public'] #$options
);
Got it stored in /vvstorage/instant_gifs/9_1518633281_IMG_7491.jpg
Extras::
4) For storing Thumbnails through put(). Example of stream() ...
$imgThumb = Image::make($request->file('image'))->resize(300, 300)->stream(); ##create thumbnail
$path = Storage::disk('s3')->put(
'profilethumbs/' . $imgName,
$imgThumb->__toString(),
'public'
);
Hope that it helps someone.
1.) Why is there vvstorage in the url?
It is appending that route because your root folder inside of your configuration for S3 is set as vvstorage, so whenever you upload to S3 all files will be prepended with vvstorage.
2.) Why random name even when you passed the name of the file?
Because when using put the file will get a unique ID generated and set as it's file name so no matter what you pass, it won't save the file under the name you wanted. But if you use putFileAs then you can override the default behaviour of put and pass a name of the file.
Hope this clarifies it

PHP : Updating new image still showing the old image

So I am creating a new folder everytime if folder not exists using mdkir.
$dir_name = '../../assets/contestant_double/'.$event_id.'eventPortfolio/';
if(!is_dir($dir_name)){
mkdir('../../assets/contestant_double/'.$event_id.'eventPortolfio/', 0777, true);
}
Now I am trying to update my uploaded image on that folder. And its working fine when i look on that designated directory
$static_name = $event_id."d".$getThed1d2."_contestant_";
$extension = pathinfo($name, PATHINFO_EXTENSION);
$theRealName = $static_name.$lastDigit.".".$extension;
echo $theRealName;
But when i try to get the image why is it still showing up the old image instead the new one?
<img class="img_here_edit" src="../assets/contestant_double/'.$event_id.'eventPortfolio/'.$soc_sql['images'].'" width="100%" >
I doubt but I'm not sure that its on my new created directory mdkir which has 0777 because those of my code are working fine in my other regular folder? How do i solve this
use unlink(''); function to old image it will solve your problem
Why not delete the old image and create and upload a new image with the same name?.
Try sending a random id at the end of image url to get the latest image like this :
<img class="img_here_edit" src="../assets/contestant_double/'.$event_id.'eventPortfolio/'.$soc_sql['images'].'?'.time().'" width="100%" >
what you see is the picture on browser cache, so you have to clear cache of browser. however, you wont do that every time you replace a picture either your users, it is too tedious and unpractical. I had same sutation and what i did was the follown. create filename + time().jpg like this.
So by the time i was going to replace old picture, i loaded from folder, delete it an then place new one. look...
function uploadphoto( $id, $ref ) {
$find = $ref.'_';
$data = $_POST[ 'image' ];
list( $type, $data ) = explode( ';', $data );
list( , $data ) = explode( ',', $data );
$data = base64_decode( $data );
$imageName = $ref.'_'.time().'.jpg'; // new picture name
foreach(glob('uploads/'.$find.'*.*') as $filename){
$localizacion = $_SERVER['DOCUMENT_ROOT'].'/'. $filename ;
chmod('./uploads', 0777);
unlink($localizacion);
}
file_put_contents( 'uploads/' . $imageName, $data );
}

Check if file exists before displaying in Magento PHP?

I am able to get the web path to the file like so:
$filename = 'elephant.jpg';
$path_to_file = $this->getSkinUrl('manufacturertab');
$full_path = $path_to_file . '/' . $filename;
But if the file doesn't exist, then I end up with a broken image link.
I tried this:
if(!file_exists($full_path)) {
Mage::log('File doesn\'t exist.');
} else {
?><img src="<?php echo $full_path ?>" /><?php
}
Of course that didn't work because file_exists does not work on urls.
How do I solve this?
1.)
Can I translate between system paths and web urls in Magento?
e.g. something like (pseudocode):
$system_path = $this->getSystemPath('manufacturertab');
That looks symmetrical and portable.
or
2.)
Is there some PHP or Magento function for checking remote resource existence? But that seems a waste, since the resource is really local. It would be stupid for PHP to use an http method to check a local file, wouldn't it be?
Solution I am currently using:
$system_path = Mage::getBaseDir('skin') . '/frontend/default/mytheme/manufacturertab'; // portable, but not pretty
$file_path = $system_path . '/' . $filename;
I then check if file_exists and if it does, I display the img. But I don't like the asymmetry between having to hard-code part of the path for the system path, and using a method for the url path. It would be nice to have a method for both.
Function
$localPath = Mage::getSingleton( 'core/design_package' )->getFilename( 'manufacturertab/' . $filename, array( '_type' => 'skin', '_default' => false ) );
will return the same path as
$urlPath = $this->getSkinUrl( 'manufacturertab/' . $filename );
but on your local file system. You can omit the '_default' => false parameter and it will stil work (I left it there just because getSkinUrl also sets it internaly).
Note that the parameter for getSkinUrl and getFilename can be either a file or a directory but you should always use the entire path (with file name) so that the fallback mechanism will work correctly.
Consider the situation
skin/default/default/manufacturertab/a.jpg
skin/yourtheme/default/manufacturertab/b.jpg
In this case the call to getSkinUrl or getFilename would return the path to a.jpg and b.jpg in both cases if file name is provided as a parameter but for your case where you only set the folder name it would return skin/yourtheme/default/manufacturertab/ for both cases and when you would attach the file name and check for a.jpg the check would fail. That's why you shold always provide the entire path as the parameter.
You will still have to use your own function to check if the file exists as getFilename function returns default path if file doesn't exist (returns skin/default/default/manufacturertab/foo.jpg if manufacturertab/foo.jpg doesn't exist).
it help me:
$url = getimagesize($imagepath); //print_r($url); returns an array
if (!is_array($url))
{
//if file does not exists
$imagepath=Mage::getDesign()->getSkinUrl('default path to image');
}
$fileUrl = $this->getSkinUrl('images/elephant.jpg');
$filePath = str_replace( Mage::getBaseUrl(), Mage::getBaseDir() . '/', $fileUrl);
if (file_exists($filePath)) {
// display image ($fileUrl)
}
you can use
$thumb_image = file_get_contents($full_path) //if full path is url
//then check for empty
if (#$http_response_header == NULL) {
// run check
}
you can also use curl or try this link http://junal.wordpress.com/2008/07/22/checking-if-an-image-url-exist/
Mage::getBaseDir() is what you're asking for. For your scenario, getSkinBaseDir() will perform a better job.
$filename = 'elephant.jpg';
$full_path = Mage::getDesign()->getSkinBaseDir().'/manufacturertab/'.$filename;
$full_URL=$this->getSkinUrl('manufacturertab/').$filename;
if(!is_file($full_path)) {
Mage::log('File doesn\'t exist.');
} else {
?><img src="<?php echo $full_URL ?>" /><?php
}
Note that for the <img src> you'll need the URL, not the system path. ...
is_file(), rather than file_exists(), in this case, might be a good option if you're sure you're checking a file, not a dir.
You could use the following:
$file = 'http://mysite.co.za/files/image.jpg';
$file_exists = (#fopen($file, "r")) ? true : false;
Worked for me when trying to check if an image exists on the URL

Exempting pdf, doc, and xls from screen grab utility

I'm using the following code and an open service provided by wordpress to grab a screenshot thumbnail of a number of webpages on the fly
<img alt="<?php the_title(); ?>" src="http://s.wordpress.com/mshots/v1/<?php echo urlencode( get_post_meta(get_the_ID(), 'mjwlink-url', true )); ?>?w=300">
Problem is some of the links go to PDF, DOC or XLS files, in those cases I'd like to display a single alternative image.
I have absolutely no idea how to go about using the url in this way + given the fact I'm using urlencode I'm not sure it's even possible - any tips/advice/code appreciated.
Example outputs:
http://s.wordpress.com/mshots/v1/http%3A%2F%2Fwww.reform.co.uk%2Fportals%2F0%2Fdocuments%2Fitcanbedonesingle.pdf?w=300
http://s.wordpress.com/mshots/v1/http%3A%2F%2Fwww.outoftrouble.org.uk%2F?w=300
The thing to do would be to check the file type, even by simply checking what comes after the dot.
You can check this before your statement like this:
$types = array('.pdf', '.doc', '.xls');
if(0 < count(array_intersect(array_map('strtolower', $filename, $types)))) {
//go get the image
} else {
//do whatever else you want to
}
where $types can include any types that you want to process differently, and $filename is the name of the file, obviously.
Taken from here, but slightly modified in your case.
$types = array('pdf', 'doc', 'xls');
$path_parts = pathinfo($filename);
if(!in_array($path_parts['extension'], $types)) {
//go get the image
} else {
//do whatever else you want to
}

Categories