I'm declaring the following function to get a random image from a directory. I want to use the same function in same code to get random image from a different directory. Now the problem is that I have to change $path but I have already used it in declaration while i want to use the different path when I use the function 2nd time
Declaration part
function getImagesFromDir($path) {
$images = array();
if ( $img_dir = #opendir($path) ) {
while ( false !== ($img_file = readdir($img_dir)) ) {
// checks for gif, jpg, png
if ( preg_match("/(\.gif|\.jpg|\.png)$/", $img_file) ) {
$images[] = $img_file;
}
}
closedir($img_dir);
}
return $images;
}
I use it this way 1st time
$root = '';
$path = 'frames/';
$imgList = getImagesFromDir($root . $path);
$img = getRandomFromArray($imgList);
How shud i use it 2nd time so that it chooses image from different directory.
Probably you don't call the function twice, but declare it twice.
declaration:
function getImagesFromDir($path) {
$images = array();
if ( $img_dir = #opendir($path) ) {
while ( false !== ($img_file = readdir($img_dir)) ) {
// checks for gif, jpg, png
if ( preg_match("/(\.gif|\.jpg|\.png)$/", $img_file) ) {
$images[] = $img_file;
}
}
closedir($img_dir);
}
return $images;
}
calls:
$images1 = getImagesFromDir("/var/www/images1");
$images2 = getImagesFromDir("/var/www/images2");
if you write
function getImagesFromDir($path) ....
again anywhere it gets redeclared and PHP don't supports this
this also happens if you require the file, which declares the function, more than once.
-- edit ---
$strRoot = '';
$astrImages = array();
$astrImages[] = array( 'path' => 'frames/', 'image' => '' );
$astrImages[] = array( 'path' => 'etc1/', 'image' => '' );
$astrImages[] = array( 'path' => 'etc2/', 'image' => '' );
$astrImages[] = array( 'path' => 'etc3/', 'image' => '' );
foreach( $astrImages as $nIndex => $astrImage )
{
$imgList = getImagesFromDir($strRoot . $astrImage['path']);
$astrImages[$nIndex]['image'] = getRandomFromArray($imgList);
}
Related
I want to get an array of immediate sub-directories based on the current path from a given list of paths. Here is an example list of paths and the desired result:
$dirs = [
'/chris',
'/chris/usa',
'/david',
'/',
'/chris/canada/2022',
'/david/uk',
];
$current_path = "/chris";
// Required result:
$sub_dirs = ['/usa', '/canada'];
The current path could be anything from / to the last sub directory, in which case I would end up with an empty $sub_dirs.
My best attempt at it is this:
$dirs = [
'/chris',
'/chris/usa',
'/david',
'/',
'/chris/canada/2022',
'/david/uk',
];
$sub_dirs = [];
$current_path = "/";
foreach($dirs as $dir){
if(strstr($dir, $current_path)){
$sub_dirs[] = str_replace($current_path, '', $dir);
}
}
The above fails at two things. If the $current_path = "/" then the returned array is just paths without slashes since I strip them out with strstr() and if the $current_path = "/chris" then I still get the sub-directories.
How should I correctly solve it?
Thank you!
You can search for /chris/ to get only sub directories.
To get only the first directory of matching paths, you could use explode(), and get the first.
As of PHP8, you can use str_starts_with()
$dirs = ['/chris', '/chris/usa', '/david', '/', '/chris/canada/2022', '/david/uk'];
$current_path = "/";
$sub_dirs = [];
foreach($dirs as $dir)
{
// Ensure $dir starts with path + '/' (sub dir of $current_path)
if (!str_starts_with($dir, $current_path)) {
continue;
}
// Get the relative path from $current_path
$relPath = substr($dir, strlen($current_path));
// Get the first dir of this path
[$dir2] = explode('/', ltrim($relPath,'/'));
// skip same directory
if (empty($dir2)) {
continue;
}
// Store and add removed slash
$sub_dirs[] = '/' . $dir2;
}
var_export(array_unique($sub_dirs));
Output
array (
0 => '/usa',
1 => '/canada',
)
I like the approach of creating a tree out of the paths (adapted from this answer).
Then it's easier to get the children based on a path.
function buildTree($paths)
{
// Create a hierarchy where keys are the labels
$rootChildren = [];
foreach ($paths as $path) {
$branch = explode("/", $path);
$children = &$rootChildren;
foreach ($branch as $label) {
if ($label) {
if (!isset($children[$label])) {
$children[$label] = [];
}
$children = &$children[$label];
}
}
}
// Create target structure from that hierarchy
function recur($children)
{
$result = [];
foreach ($children as $label => $grandchildren) {
$result[$label] = recur($grandchildren);
}
return $result;
}
return recur($rootChildren);
}
function findChildren($tree, $path)
{
$branch = explode("/", $path);
$pointer = $tree;
foreach ($branch as $label) {
if ($label) {
$pointer = $pointer[$label];
}
}
return array_keys($pointer);
}
$dirs = [
'/chris',
'/chris/usa',
'/david',
'/',
'/chris/canada/2022',
'/david/uk',
];
$tree = buildTree($dirs);
print_r($tree);
$current_path = "/chris";
print_r(findChildren($tree, $current_path));
Output:
Array
(
[chris] => Array
(
[usa] => Array
(
)
[canada] => Array
(
[2022] => Array
(
)
)
)
[david] => Array
(
[uk] => Array
(
)
)
)
Array
(
[0] => usa
[1] => canada
)
I feel like I have a bit shorter answer than the previous ones, but not sure if it's the most efficient one though.
$dirs = [
'/chris',
'/chris/usa',
'/david',
'/',
'/chris/canada/2022',
'/david/uk',
];
$current_path = "/chris";
$sub_dirs = array_map(function($s) { return '/'.explode("/", $s)[2]; },array_filter($dirs, function($dir) use ($current_path) {
return substr($dir, 0, strlen($current_path) + 1) === $current_path . '/';
}));
print_r($sub_dirs); // Output: Array ( [1] => /usa [4] => /canada )
I have a image named Dark-Green.jpg but the output of function is DARK-GREEN.jpg so the image is not displaying due to case-sensitive.
So how can I fetch the image?
UPDATE
Below is my output of the array.
$output = Array
(
[WE05-5040*L] => Array
(
[qty] => 1
[stitching_category] => 2
[sku_image] => skuimages/WE05/DARK-GREEN.jpg
)
)
Then I am using this array in foreach loop like below.
foreach ($output as $ok => $op) {
$itemQty = $op['qty'];
$itemImagePath = $op['sku_image'];
echo "{$ok} has qty: {$itemQty} and the image as below.";
echo "<img src='{$itemImagePath}' width='50%' />"
}
Try this:
function getFile ($filename){
$files = glob($dir . '/*');
$filename = strtolower($filename);
foreach($files as $file) {
if (strtolower($file) == $filename){
return $file;
}
}
return false;
}
I was trying to update my userprofile with the following controller but the problem is if i update only profile picture it shows the above error..But if i update every value it update successfully. How do i update the userProfile without updating every value :
public function updateUser(Request $request)
{
$this->validate($request, [
'profile_picture' => 'dimensions:width=400,height=400',
'cover_picture' => 'dimensions:width=800,height=400',
'avatar' => 'dimensions:width=80,height=80',
]);
if (\Auth::check())
{
$user= User::find(\Auth::id());
}
$files= [];
if($request->file('profile_picture')) $files[] = $request->file('profile_picture');
if($request->file('cover_picture')) $files[] = $request->file('cover_picture');
if($request->file('avatar')) $files[] = $request->file('avatar');
foreach($files as $file)
{
if(!empty($file))
{
$filename = time().str_random(20). '.' . $file->getClientOriginalExtension();
$file->move('users/',$filename);
$filenames[]=$filename;
}
}
$user->profile_picture = $filenames[0];
$user->cover_picture = $filenames[1];
$user->avatar = $filenames[2];
$user->save();
return redirect::back()->with('Warning',"Profile Updated Successfully");
}
I don't think it's wise using a positional array like this, As you've discovered, what if someone only wants to update their avatar. I feel your assignment into $files[] is redundant and you could go straight into your processing code.
Basically your current implementation means $files can be of a variable length, how do you know which is 0, 1 or 2 etc ?
With my approach, the code is now looping over each type of picture, and assigns it into the user with $user->$type directly by the same matching type property.
foreach( array( 'profile_picture', 'cover_picture', 'avatar' ) as $type)
{
if( $request->file( $type ) )
{
$filename = time() . str_random(20) . '.' . $request->file( $type )->getClientOriginalExtension();
$request->file( $type )->move( 'users/', $filename );
$user->$type = $filename;
}
}
If you find you need to map a different $source to the $type variable, you could do this with an additional array index...
foreach( array(
'profile_picture' => 'profile_picture',
'cover_picture' => 'cover_picture',
'avatar' => 'avatar'
) as $source => $type)
{
if( $request->file( $source ) )
{
$filename = time() . str_random(20) . '.' . $request->file( $source )->getClientOriginalExtension();
$request->file( $source )->move( 'users/', $filename );
$user->$type = $filename;
}
}
I finally came up with a solution mate.
You can try to Include a var_dump of $filenames. I suppose that $filenames[1] doesn't exist at all.
Can someone explain to me why I cannot delete the images that I was able to successfully import in the first half of the function
function delete_files($target) {
foreach(glob($target.'*.*') as $v){
unlink($v);
}
}
function importImagesforSlideShow()
{
$array = $_REQUEST["data"];
$slidePath = '../../images/carousel-slides/';
$url = $array[0];
$images = $array[1];
$imageExtQualifier = $array[2];
if (!file_exists($slidePath)) {
mkdir($slidePath, 0777, true);
}
foreach ($images as $imageName) {
$context = stream_context_create(array(
'http' => array(
'ignore_errors' => true,
'header' => "User-Agent:MyAgent/1.0\r\n"
)
));
$urlLoc = $url . $imageName . $imageExtQualifier;
$img = $imageName . '.jpg';
file_put_contents($slidePath . $img, file_get_contents($urlLoc, FALSE, $context));
}
// not working
delete_files(__DIR__ . $slidePath);
echo json_encode($images);
}
UPDATE:
Salty: I think you are on to something. This does nto look right
G:\PleskVhosts\abc.com\xyz.com\scripts\php../../images/carousel-slides/
it should be something like:
G:\PleskVhosts\abc.com\xyz.com\images/carousel-slides/
How to fix?
I am using this function to upload images, and it is working except in one part. Where there are more then one image for upload, all images get their name from the first image (overwrite is set to off, so CI is adding number at the end of the name). How can I solve this problem?
function img_upload($folder) {
$this->path = './public/img/' . $folder;
$imgs = array();
$count = 0;
foreach($_FILES as $key => $value):
$img_name = is_array($value['name']) ? $value['name'][$count] : $value['name'];
$img_name = $this->char_replace($img_name, '_');
$count++;
$config = array(
'allowed_types' => 'jpg|jpeg|png|gif',
'upload_path' => $this->path,
'file_name' => $img_name
);
$this->CI->load->library('image_lib');
$this->CI->image_lib->clear();
$this->CI->load->library('upload', $config);
if($key != 'logo'):
if (!$this->CI->upload->do_upload($key)) {
} else {
$image = $this->CI->upload->data();
$imgs[] = $image['file_name'];
}
endif;
endforeach;
if(empty($imgs)):
return FALSE;
else:
return implode(',', $imgs);
endif;
}
Function char_replace is working without a problem.
function char_replace($text, $rep_simbol = " ")
{
$char = array('!', '&', '?', '/', '/\/', ':', ';', '#', '<', '>', '=', '^', '#', '~', '`', '[', ']', '{', '}');
return $name = str_replace($char, $rep_simbol, $text);
}
$this->CI->upload->do_upload($key) expects $_FILES['key'] to only contain one file.
What you can do is, make a copy of $_FILES, loop through it, and for each file set the values of $_FILES['key'].
function img_upload($folder) {
$this->path = './public/img/' . $folder;
$imgs = array();
// Copy of $_FILES
$thisFiles = $_FILES;
// Loop through copy of $_FILES
foreach($theFiles as $key => &$value){
// Create the $_FILES array for each individual file,
// so that do_upload can read it correctly
if(!is_array($value['name'])){
// If it's not an array, make it one,
// this will make our future code easier
foreach($value as $kv => &$val){
$val = array($val);
}
}
// Loop through each file and upload each one
foreach($value['name'] as $count=>$img_name){
$img_name = $this->char_replace($img_name, '_');
foreach($_FILES[$key] as $k => &$v){
// CodeIgniter will think this is the $_FILES array
$v = $theFiles[$key][$k][$count];
}
$config = array(
'allowed_types' => 'jpg|jpeg|png|gif',
'upload_path' => $this->path,
'file_name' => $img_name
);
$this->CI->load->library('image_lib');
$this->CI->image_lib->clear();
$this->CI->load->library('upload', $config);
if($key != 'logo'){
if (!$this->CI->upload->do_upload($key)) {
}
else {
$image = $this->CI->upload->data();
$imgs[] = $image['file_name'];
}
}
}
}
return !empty($imgs) ? implode(',', $imgs) : FALSE;
}
NOTE: This is untested.