i have this code:
$album_name = $row['album'];
if(!file_exists("cdcovers/$album_name.jpg") && filesize($album_name) > 5){
//gravar as imagens
$imageString = file_get_contents(LastFMArtwork::getArtwork($row['artist'], $row['album'], true, "large"));
$save = file_put_contents('/home/link/public_html/cdcovers/'.$row['album'].'.jpg',$imageString);
}
but i gives an error(Warning: filesize(): stat failed for...) if the image is not there,
my ideia was if the file exists and is bigger then 5kb then do nothing if it is 4kb or below save image, even if a file exists with 0kb.
Base on what I understand you want to create an image if it does not exist or update the image if it is smaller than 5kb.
In short, filesize will yield the warning if you give it a file that does not exists but there are a few more issues with the original code:
The condition block is wrong. The function filesize returns the size in bytes and 5kb is ~5,000 bytes.
The wrong comparison operator is also been use. The less than operator < should be used instead greater than operator >.
The code attempts to check the size of a file when it does not exist.
You are referencing different file paths in the condition block.
I modified the sample code to store the absolute path to the image in a variable and reference it where needed, fixed the bytes comparison and updated the condition block requirements to prevent the filesize warning.
Please review the updated code below:
$albumCoverImg = '/home/link/public_html/cdcovers/' . $row['album'] . '.jpg';
$minSize = 5 * 1000; // 5KB
$fileExist = is_file($albumCoverImg);
if (!$fileExist || ($fileExist && filesize($albumCoverImg) < $minSize)) {
//gravar as imagens
$imageString = file_get_contents(LastFMArtwork::getArtwork($row['artist'], $row['album'], true, "large"));
$save = file_put_contents($albumCoverImg, $imageString);
}
You have to check if the file exists before to check its size.
If "cdcovers/$album_name.jpg" and $album_name are different files, you also have to check the second.
if (!file_exists("cdcovers/$album_name.jpg") &&
file_exists($album_name) &&
filesize($album_name) > 5) {
If the files are the same, it's the error (missing folder and file extension).
Also, you save the file with an absolute path : '/home/link/public_html/cdcovers/'.$row['album'].'.jpg'. It could differ from "cdcovers/$album_name.jpg" (depending of the current folder's script execution). You may use the absolute path, of __dir__ constant to be relative to your current folder.
You may use variables to store filename and limit errors by writing them multiple times :
$filename = '/home/link/public_html/cdcovers/'.$row['album'].'.jpg' ;
if (!file_exists($filename) ||
(file_exists($filename) && filesize($filename) < 5000)) {
file_put_contents($filename, ...);
}
Please also note that filesize() returns the size in bytes, not in Kb.
Related
I wrote some code below, at the moment I'm testing so there's no database queries in the code.
The code below where it says if(filesize($filename) != 0) always goes to else even though the file is not 0 bytes and has 16 bytes of data in there. I am getting nowhere, it just always seems to think file is 0 bytes.
I think it's easier to show my code (could be other errors in there but I'm checking each error as I go along, dealing with them one by one). I get no PHP errors or anything.
$filename = 'memberlist.txt';
$file_directory = dirname($filename);
$fopen = fopen($filename, 'w+');
// check is file exists and is writable
if(file_exists($filename) && is_writable($file_directory)){
// clear statcache else filesize could be incorrect
clearstatcache();
// for testing, shows 0 bytes even though file is 16 bytes
// file has inside without quotes: '1487071595 ; 582'
echo "The file size is actually ".filesize($filename)." bytes.\n";
// check if file contains any data, also tried !==
// always goes to else even though not 0 bytes in size
if(filesize($filename) != 0){
// read file into an array
$fread = file($filename);
// get current time
$current_time = time();
foreach($fread as $read){
$var = explode(';', $read);
$oldtime = $var[0];
$member_count = $var[1];
}
if($current_time - $oldtime >= 86400){
// 24 hours or more so we query db and write new member count to file
echo 'more than 24 hours has passed'; // for testing
} else {
// less than 24 hours so don't query db just read member count from file
echo 'less than 24 hours has passed'; // for testing
}
} else { // WE ALWAYS END UP HERE
// else file is empty so we add data
$current_time = time().' ; ';
$member_count = 582; // this value will come from a database
fwrite($fopen, $current_time.$member_count);
fclose($fopen);
//echo "The file is empty so write new data to file. File size is actually ".filesize($filename)." bytes.\n";
}
} else {
// file either does not exist or cant be written to
echo 'file does not exist or is not writeable'; // for testing
}
Basically the code will be on a memberlist page which currently retrieves all members and counts how many members are registered. The point in the script is if the time is less than 24 hours we read the member_count from file else if 24 hours or more has elapsed then we query database, get the member count and write new figure to file, it's to reduce queries on the memberlist page.
Update 1:
This code:
echo "The file size is actually ".filesize($filename)." bytes.\n";
always outputs the below even though it's not 0 bytes.
The file size is actually 0 bytes.
also tried
var_dump (filesize($filename));
Outputs:
int(0)
You are using:
fopen($filename, "w+")
According to the manual w+ means:
Open for reading and writing; place the file pointer at the beginning of the file and truncate the file to zero length. If the file does not exist, attempt to create it.
So the file size being 0 is correct.
You probably need r+
Sorry I know this question is closed but I am writing my own answer so it might be useful for someone else
if use c+ in fopen function ,
fopen($filePath , "c+");
then the filesize() function return size of file
and you can use clearstatcache($filePath) to clear the cache of this file.
notice: when we use c+ in fopen() and then use the fread(), function reserve the file content and place our string at the end of file content
I want to rename all files in a folder with random numbers or characters.
This my code:
$dir = opendir('2009111');
$i = 1;
// loop through all the files in the directory
while ( false !== ( $file = readdir($dir) ) ) {
// do the rename based on the current iteration
$newName = rand() . (pathinfo($file, PATHINFO_EXTENSION));
rename($file, $newName);
// increase for the next loop
$i++;
}
// close the directory handle
closedir($dir);
but I get this error:
Warning: rename(4 (2).jpg,8243.jpg): The system cannot find the file specified
You're looping through files in the directory 2009111/, but then you refer to them without the directory prefix in rename().
Something like this should work better (though see the warning about data loss below):
$oldName = '2009111/' . $file;
$newName = '2009111/' . rand() . (pathinfo($file, PATHINFO_EXTENSION));
rename($oldName, $newName);
Of course, you may want to put the directory name in a variable or make other similar tweaks. I'm still not clear on why you're trying to do this, and depending on your goals there may be better ways of reaching them.
Warning! The approach you are using could cause data loss! A $newName could be generated that is the same name as an existing file, and rename() overwrites target files.
You should probably make sure $newName doesn't exist before you rename().
in my php page I have <input type='file' name='aimage[]' id='aimage' />
and a snippet code to get this file as :
foreach($_FILES["aimage"]["tmp_name"] as $file)
{
/*** get the image info. ***/
if(is_uploaded_file($file) && getimagesize($file) != false){
$size = getimagesize($file);
/*** assign our variables ***/
$type = $size['mime'];
$imgfp = fopen($file, 'rb');
$size = $size[3];
// $name = $file['name'];
$maxsize = 99999999;
/*** check the file is less than the maximum file size ***/
//if($_FILES['aimage']['size'] < $maxsize )
// {
/*** connect to db ***/
$formvars['file'] = fread($imgfp, getimagesize($file));
Although using foreach, I got error as Warning: fread() expects parameter 2 to be long, array given in. what's cause of this error? How can I check only images uploaded to site and other files detected by code?
The error is caused by the second parameter of fread() : getimagesize($file)) which returns an array and not a long. getimagesize returns an array(width, height)
Maybe you want to use filesize($file) instead
From the getimagesize documentation:
Returns an array with up to 7 elements. Not all image types will
include the channels and bits elements.
Index 0 and 1 contains respectively the width and the height of the
image.
Note: Some formats may contain no image or may contain multiple
images. In these cases, getimagesize() might not be able to properly
determine the image size. getimagesize() will return zero for width
and height in these cases. Index 2 is one of the IMAGETYPE_XXX
constants indicating the type of the image.
Index 3 is a text string with the correct height="yyy" width="xxx"
string that can be used directly in an IMG tag.
mime is the correspondant MIME type of the image. This information can
be used to deliver images with the correct HTTP Content-type header:
Example #1 getimagesize() and MIME types
I am currently in the process of writing a mobile app with the help of phonegap. One of the few features that I would like this app to have is the ability to capture an image and upload it to a remote server...
I currently have the image capturing and uploading/emailing portion working fine with a compiled apk... but in my php, I am currently naming the images "image[insert random number from 10 to 20]... The problem here is that the numbers can be repeated and the images can be overwritten... I have read and thought about just using rand() and selecting a random number from 0 to getrandmax(), but i feel that I might have the same chance of a file overwriting... I need the image to be uploaded to the server with a unique name every-time, no matter what... so the php script would check to see what the server already has and write/upload the image with a unique name...
any ideas other than "rand()"?
I was also thinking about maybe naming each image... img + date + time + random 5 characters, which would include letters and numbers... so if an image were taken using the app at 4:37 am on March 20, 2013, the image would be named something like "img_03-20-13_4-37am_e4r29.jpg" when uploaded to the server... I think that might work... (unless theres a better way) but i am fairly new to php and wouldn't understand how to write something like that...
my php is as follows...
print_r($_FILES);
$new_image_name = "image".rand(10, 20).".jpg";
move_uploaded_file($_FILES["file"]["tmp_name"], "/home/virtual/domain.com/public_html/upload/".$new_image_name);
Any help is appreciated...
Thanks in advance!
Also, Please let me know if there is any further info I may be leaving out...
You may want to consider the PHP's uniqid() function.
This way the code you suggested would look like the following:
$new_image_name = 'image_' . date('Y-m-d-H-i-s') . '_' . uniqid() . '.jpg';
// do some checks to make sure the file you have is an image and if you can trust it
move_uploaded_file($_FILES["file"]["tmp_name"], "/home/virtual/domain.com/public_html/upload/".$new_image_name);
Also keep in mind that your server's random functions are not really random. Try random.org if you need something indeed random. Random random random.
UPD: In order to use random.org from within your code, you'll have to do some API requests to their servers. The documentation on that is available here: www.random.org/clients/http/.
The example of the call would be: random.org/integers/?num=1&min=1&max=1000000000&col=1&base=10&format=plain&rnd=new. Note that you can change the min, max and the other parameters, as described in the documentation.
In PHP you can do a GET request to a remote server using the file_get_contents() function, the cURL library, or even sockets. If you're using a shared hosting, the outgoing connections should be available and enabled for your account.
$random_int = file_get_contents('http://www.random.org/integers/?num=1&min=1&max=1000000000&col=1&base=10&format=plain&rnd=new');
var_dump($random_int);
You should use tempnam() to generate a unique file name:
// $baseDirectory Defines where the uploaded file will go to
// $prefix The first part of your file name, e.g. "image"
$destinationFileName = tempnam($baseDirectory, $prefix);
The extension of your new file should be done after moving the uploaded file, i.e.:
// Assuming $_FILES['file']['error'] == 0 (no errors)
if (move_uploaded_file($_FILES['file']['tmp_name'], $destinationFileName)) {
// use extension from uploaded file
$fileExtension = '.' . pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION);
// or fix the extension yourself
// $fileExtension = ".jpg";
rename($destinationFileName, $destinationFileName . $fileExtension);
} else {
// tempnam() created a new file, but moving the uploaded file failed
unlink($destinationFileName); // remove temporary file
}
Have you considered using md5_file ?
That way all of your files will have unique name and you would not have to worry about duplicate names. But please note that this will return same string if the contents are the same.
Also here is another method:
do {
$filename = DIR_UPLOAD_PATH . '/' . make_string(10) . '-' . make_string(10) . '-' . make_string(10) . '-' . make_string(10);
} while(is_file($filename));
return $filename;
/**
* Make random string
*
* #param integer $length
* #param string $allowed_chars
* #return string
*/
function make_string($length = 10, $allowed_chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890') {
$allowed_chars_len = strlen($allowed_chars);
if($allowed_chars_len == 1) {
return str_pad('', $length, $allowed_chars);
} else {
$result = '';
while(strlen($result) < $length) {
$result .= substr($allowed_chars, rand(0, $allowed_chars_len), 1);
} // while
return $result;
} // if
} // make_string
Function will create a unique name before uploading image.
// Upload file with unique name
if ( ! function_exists('getUniqueFilename'))
{
function getUniqueFilename($file)
{
if(is_array($file) and $file['name'] != '')
{
// getting file extension
$fnarr = explode(".", $file['name']);
$file_extension = strtolower($fnarr[count($fnarr)-1]);
// getting unique file name
$file_name = substr(md5($file['name'].time()), 5, 15).".".$file_extension;
return $file_name;
} // ends for is_array check
else
{
return '';
} // else ends
} // ends
}
http://php.net/stream_copy_to_stream $maxlength parameter allows to limit the number of bytes to copy.
How to tell if the limit was breached, ie. not the whole file was downloaded?
With regards to Yousuf Memon comment (http://mattgemmell.com/2008/12/08/what-have-you-tried/), my approach to the issue is simple logic:
public function download($size_limit)
{
if($this->temp_file)
{
throw new UploadRemoteImageException('Resource has been downloaded already.');
}
$this->temp_file = tempnam(sys_get_temp_dir(), $this->temp_file_prefix);
$src = fopen($this->url, 'r');
$dest = fopen($this->temp_file, 'w+');
stream_copy_to_stream($src, $dest, $size_limit+1000);
if(filesize($dest) > $size_limit)
{
// The file size limit has been breached.
}
// [..]
}
This works by simply adding more bytes on top of the user defined limit. Then when the stream is closed, it check if the file is larger than the user defined size limit (, which can be because we added the 1000 bytes on top).
However, I can't tell with confidence if this will always work, as I assume it also depends on the chunk size.