I have a very, very simple function:
function getUserImage($id) {
if (file_exists(SITE_ROOT . '/images/' . $id)) {
return "http://www.---.net/images/" . $id;
} else {
return "http://www.---.net/images/usericon.png";
}
}
It is being called this way:
<img src="<?php echo getUserImage($row['user_id'].".jpg"); ?>" />
What I am trying to do is show a default icon if the user does not have a profile picture. It is showing the default icon every time even though the correct path is being tested (I have confirmed this). Maybe I am using file_exists() wrong?
file_exists() works at the filesystem level. You're passing in something like /images/whatever, so it'll be looking for a whatever file in an images directory that is at the TOP of the file system, e.g. you're trying to for the equivalent of
c:\images\whatever
instead of where the image actually exists, in your site's document root, e.g.
c:\inetpub\wwwroot\example.com\html\images\whatever
You generally can NOT use a url directly in a file-system context, because the paths you see in a URL very rarely EVER directly map to what's on the server's file system.
function getUserImage($id) {
if (file_exists(SITE_ROOT . '/profile_pics/' . $id)) {
return "http://www.---.net/profile_pics/" . $id;
} else {
return "http://www.---.net/images/usericon.png";
}
}
I was searching in the wrong folder. It should have been profile_pics all along~
Related
I am trying to delete the images from the server using unlink() function. This is deleting the image name from the database, but the image is not deleted from the server, what am i doing wrong?
public function actionDelete()
{
if(Yii::$app->request->isAjax)
{
$id = $_POST['id'];
$product=Product::find()->where(['id'=>$id])->one()->delete();
$delete=CategoryProduct::find()->where(['product_id'=>$id])->all();
foreach($delete as $del)
{
$del->delete();
}
$imgfile="<?php echo Yii::$app->request->baseUrl;?>/web/assets/uploads/<?php echo $product->image;?>";
unlink($imgfile);
echo json_encode(TRUE);die;
}
echo json_encode(FALSE);die;
}
Its is best to set an alias for the upload path (best place will be config/bootstrap.php)so that we can have standard name to all the upload folder. i.e
Yii::setAlias('image_uploads', dirname(dirname(__DIR__)) . '/web/assets/uploads');
You can use the same for saving and deleting the file.
Saving will be like
move_uploaded_file($tmp_file, \Yii::getAlias('#image_uploads/products/') . $product->image);
or
You can use Yii Methods i.e for e.g.
$this->imageFile->saveAs($orignal_file_full_path); // where imageFile in input type file
Deleting will be something like:
unlink (\Yii::getAlias('#image_uploads/products/') . $product->image);
the Core idea is to use real paths for deleting and saving rather then URLs
I am uploading an image and while storing the image, I am setting the Filename like 'assets/Uploads/54f092af271b9.png' but after saving, the Filename fields loses some part. It becomes 'assets/54f092af271b9.png' losing the "Uploads/" directory altogether. Is it supposed to happen?
Here's the codes:
<?php
$img = new Image();
$baseName = pathinfo($file, PATHINFO_BASENAME);
$fileName = 'assets/Uploads/' . $baseName;
var_dump($fileName);
$img->Name = $baseName;
$img->Filename = $fileName;
$img->OwnerID = ($memberID = Member::currentUserID()) ? $memberID : 0;
$img->write();
var_dump($img->Filename); exit;
Output is:
assets/Uploads/54f092af271b9.png
assets/54f092af271b9.png'
Any ideas?
I was able to replicate the issue with the code you provided. After a bit of digging around, here is what I found.
It all starts in the onAfterWrite function in File class (which Image extends). Fired after you called write (obviously), this calls updateFilesystem where this line sets the Filename property with the result of the getRelativePath function call.
At the time of writing, getRelativePath looks like this:
public function getRelativePath() {
if($this->ParentID) {
// Don't use the cache, the parent has just been changed
$p = DataObject::get_by_id('Folder', $this->ParentID, false);
if($p && $p->exists()) return $p->getRelativePath() . $this->getField("Name");
else return ASSETS_DIR . "/" . $this->getField("Name");
} else if($this->getField("Name")) {
return ASSETS_DIR . "/" . $this->getField("Name");
} else {
return ASSETS_DIR;
}
}
Looking at that code, the issue you have comes from ParentID not being set on your record when you wrote it to the DB so the second condition is run instead returning the result of ASSETS_DIR . "/" . $this->getField("Name").
So that is the problem addressed, now for a solution. Silverstripe wants a parent folder, you've just got to give it one.
Fortunately there is a great little function on the Folder class called find_or_make which does what the name says, either finds the folder record in the filesystem and DB or it will generate it for you.
Note: In my own testing, while I had an "Uploads" folder, I did not have a corresponding DB record so this function wrote that for me an returned the result.
I then used the result to give the image I was writing to the DB a ParentID and it made the second var_dump return the same value as the first.
This is all you need to add to your code before calling write:
$parentFolder = Folder::find_or_make('Uploads');
$img->setParentID($parentFolder->ID);
I am trying to understand part of the output I get from this code:
<?php
class DirectoryReader extends DirectoryIterator
{
function __construct($path)
{
parent::__construct($path);
}
function current()
{
return parent::getFileName();
}
function valid()
{
if(parent::valid())
{
if (!parent::isDir())
{
parent::next();
return $this->valid();
}
return TRUE;
}
return FALSE;
}
}
try
{
$it = new DirectoryReader('C:\wamp\www');
while($it->valid())
{
echo $it->current().'<br />';
$it->next();
}
}
catch(Exception $e)
{
echo 'No files Found!<br />';
}
?>
At the code you can see that I pass this path to the constructor: C:\wamp\www,
What I don't understand: before I can see all the folders the first line is ., the second is .., and then I can see the folder names for example:
.
..
someFolder
someOtherFolder
I know that . present the current folder and .. is getting back at the folders hierarchy, but I can't understand why does it print the . then .. and then the folders?
I really want to understand the action of this iterator, if can some one please help me understand I will be very thankful.
The code parent::isDir() returns TRUE for the dot directories, meaning your own valid() method returns TRUE for them as well.
You could edit your method to look at whether isDot() returns TRUE or FALSE and respond accordingly.
function valid()
{
return $this->isDir() && !$this->isDot();
}
In case you do not want to show . and .. (as explained in other excellent answers) this snippet taken directly from the manual page comments.
Shows us all files and catalogues in directory except "." and "..".
<?php
foreach (new DirectoryIterator('../moodle') as $fileInfo) {
if($fileInfo->isDot()) continue;
echo $fileInfo->getFilename() . "<br>\n";
}
Edit
The FilesystemIterator is preferred, over the DirectoryIterator. When using the former, the dot files are skipped by default (there is a flag to control this behaviour).
<?php
foreach (new FilesystemIterator('../moodle') as $fileinfo) {
echo $fileinfo->getFilename() . "<br>\n";
}
That listing is correct, since . and .. are also (virtual) nodes in each directory. If you want to suppress the output of files/folder beginning with a dot (like Apache does in default configuration), you have to implement an appropriate check by yourself in valid() in the given code.
When a directory is built, it is initially populated with the filename parts of two special files: the '.' and '..' files. The filename part for the '.' file is populated with the inode# of the directory file in which the entry has been made; '.' is a hardlink to the file that implements the current directory.
The filename part for the '..' file is populated with the inode# of the directory file that contains the filename part of the current directory file. '..' is a hardlink to the file that implements the immediate parent of the current directory.
Source: http://linuxgazette.net/105/pitcher.html
It prints the . and .. because that class is only checking if the folder is a directory which both . and .. are
furthermore the result is sorted, that's why '.' comes before '..' and 'some_other_directories'.
In my Product Class, there is a function called pictures() which returns the file address of the picture of a product. It's something like this:
public function picture()
{
$file = "images/pictures/products/" . $this->id . ".png";
if(file_exists($file))
return $file;
else
return false;
}
It works fine when running the code on the administration area of the website (which is located on /admin/ directory)
But when I call this function from the index.php which is not on the /admin/ directory it always returns false. What should I do? The only way I figured to solve this is by creating a parameter on the picture() function, like: picture($directory_prefix) then that way I'll call the function with picture("/admin/"). But there's gotta be a better way than this...
Place your resources in a directory under the web root. Then the path would be:
$file = $_SERVER['HTTP_HOST']."/images/pictures/products/" . $this->id . ".png";
Very nasty problem, I made a very long investigation to find out what was the origin of the bug. I made an original post for this, but I deleted it to create a new fresh post. So let's start by the start. Thank you in advance for reading this until the end.
I have a View Helper Pub.php. This one display randomly an ad. $this->pub() is called in the layout.phtml and in the phtml view files. The Helper also increments the number of impression before displaying it.
Pub.php
Class My_View_Helper_Pub extends Zend_View_Helper_Abstract {
public function pub( $place, $format ) {
// Extract the active campaigns, then randomly select one
$campaigns = $model->getActiveCampaigns();
...
// Increase the number of view for this campaign (in MySQL)
$model->increasePrint($campaign->id);
// And display the banner
echo $this->generateHtml($campaign->filename);
}
public function generateHtml($filename){
// Generate the html according to the filename (image, flash, custom tag etc...)
return $code;
}
IncreasePrint()
public function increasePrint($id){
$table = $this->getTable();
$row = $table->find($id)->current();
$row->imp_made = $row->imp_made + 1;
return $row->save();
}
My layout.phtml is also simple :
<html>
<head>
<?= $this->pub(null, 'css') ?>
</head>
<body>
<?= $this->pub(null, 'big_banner' ?>
</body>
Problem : On some actions, ads in the layout are selectionned and incremented twice ! As if the helper was instancied again.
After some search, the problem seems to come from another View Helper : LogoEvent. This helper displays a logo/image by returning proper HTML code.
LogoEvent.php
class My_View_Helper_LogoEvent extends Zend_View_Helper_Abstract
{
public function logoEvent($image, $taille = null){
$image = trim($image);
if ($taille){
$width = "max-width: {$taille}px;";
} else {
$width = '';
}
if (!empty($image)){
return '<img src="/images/agenda/logos/'. $image .'" style="'. $width .'" alt="Logo" />';
} else {
return '<img src="/images/agenda/logos/no-logo.png" style="'. $width .'" alt="No Logo" />';
}
}
}
The double-incrementation happens when the file doesn't exist on my hard disk.
Really weird... I tried this :
echo $this->logoEvent( 'existing_image.jpg', '100');
// No problem, everything works fine.
echo $this->logoEvent( 'unexisting_image.jpg', '100');
// => problem.
But
echo htmlentities($this->logoEvent( 'unexisting_image.jpg', '100'));
// No problem, everything works fine.
Someone has better knowledge than me to find out what could be the problem or a way to find it...
Thank you !
I'm almost certain that your problem is from .htaccess, where, be default in ZF, is set to send all non-existing files (the -s condition) to index.php, thus your application will fire up again (possibly into the ErrorController, for 404).
Add this in .htaccess instead, see how it fits (it omits certain files to be routed to index.php):
RewriteRule !\.(js|ico|gif|jpg|png|css)$ index.php [NC,L]