foreach two arrays in php? - php

I have two arrays like this
$slike = Array('artist2-1.jpg', 'artist2-2.jpg', 'artist2-3.jpg', 'artist2-4.jpg');
$slikethumb = Array('artist2-1_thumb.jpg',
'artist2-2_thumb.jpg',
'artist2-3_thumb.jpg',
'artist2-4_thumb.jpg');
When I foreach two arrays I want to get this output on view
echo'<a href='.$slike.'><img src='.$slikethumb.'></a>';
I know how to foreach one array, but what I have to do to combine two arrays in one foreach?

If those arrays are sorted correctly and both have same number of elements:
foreach($slike as $i => $value){
echo'<a href='.$value.'><img src='.$slikethumb[$i].'></a>';
}

Edit:
Considering your related question, You might want to think about scanning your directoy using glob and a more specific pattern, something along the lines of:
$sLike = glob('{0,1,2,3,4,5,6,7,8,9}.jpg',GLOB_BRACE);
//selects all .jpg files with names ending with number.jpg, so no _thumb.jpg files
Then, with this in mind and in light of your comment. How to remove the file extensions:
$sLike = array();//the array from dir scan
$clean = array();
foreach($sLike as $file)
{
$clean[] = substr($file, 0, strpos($file, '.')*-1);//get file name
}
$format = '<img src="%1$s_thumb.jpg" />';//output format
foreach($clean as $like)
{
    printf($format, $like);
}
Or, with a more liberal pattern used for the glob call, and if you want to go with option 2 (the one with different extensions per file):
$sLike = array();//the array from dir scan
$clean = array();
foreach($sLike as $file)
{
$endOffset = strpos($file, '.')*-1;
$clean[] = array(
substr($file, 0, $endOffset),//get file name
substr($file,$endOffset)//get extension, includes the . char!
);
}
$format = '<img src="%1$s_thumb%2$s" />';//output format
foreach($clean as $like)
{
echo vsprintf($format, $like);
}
That's about it...
What I'd do is use but a single array. The base string is the same for both images:
$slike=array(
'artist2-1',
'artist2-2',
'artist2-3',
'artist2-4'
);//remove extensions
$format = '<img src="%1$s_thumb.jpg" />';//output format
foreach($slike as $like)
{
printf($format, $like);
}
That will give you what you want, without there ver being a need for 2 arrays, as you can see on this codepad.
Benefits of this approach:
only constructs 1 array, not 2
uses printf which translates internally to a fprintf(stdout, "<your format>", zval*$like); in C, which is fast.
No excess fat: there's very little repetition. You could even change the format to artist2-%s.jpg"><img src="artist2-%s_thumb.jpg" />, and only stores the numbers in the array, but that's taking it absurdly far.
Short, and concise code
Of course, there are caveats:
less readable & maintainable code
If ever you add 1 image with a different extension (png), you'll have to refactor...
The choice is yours. If different extensions is likely to happen, you could change the code above to something like:
$slike=array(
array('artist2-1','jpg'),
array('artist2-2','png'),
array('artist2-3','gif'),
array('artist2-4','jpeg'),
);//remove extensions
$format = '<img src="%1$s_thumb.%2$s" />';//output format
foreach($slike as $like)
{
echo vsprintf($format, $like);
}
As you can see on this codepad, that'll work like a charm, too

If same number of elements in both array & sorted then,
foreach($slikethumb as $key => $val) {
echo '<a href='.$slike[$key].'><img src='.$val.'></a>';
}

You can use for loop
for($i = 0; $i< count($slike); $i++)
{
$slike_val = $slike[$i];
$slikethumb_val = $slikethumb[$i];
echo'<a href='.$slike_val.'><img src='.$slikethumb_val.'></a>';
}

You will try
foreach($slike as $key=>$slike_val)
echo'<a href='.$slike_val.'><img src='.$slikethumb[$key].'></a>';

Try like this:
<?php
$slike = array('artist2-1.jpg', 'artist2-2.jpg', 'artist2-3.jpg', 'artist2-4.jpg');
$slikethumb = array('artist2-1_thumb.jpg', 'artist2-2_thumb.jpg', 'artist2-3_thumb.jpg', 'artist2-4_thumb.jpg');
foreach($slike as $key1 => $value1)
{
echo $value1."--------->".$slikethumb[$key1]."<br />";
}
?>
Thanks

foreach ($slike as $key=>$img) {
print '<a href='.$img.'><img src='.$slikethumb[$key].'></a>';
}
Or if you want one which is not based on the ordering....
foreach ($slike as $key=>$img) {
list($name, $ext)=explode('.', $img);
$thumb=$name . '_thumb.' . $ext;
if (in_array($thumb, $slikethumb)) {
print '<a href='.$img.'><img src='.$thumb.'></a>';
} else {
...?
}
}

Related

PHP - get single file based on user

I'm having trouble getting my code to work the way I want.
I'm using scandir to get all files from the directory. This gives me a list with pdf files linked to a product, but the problems comes with the posibllity of pdf files multiple languages. Like so:
1096_EN.pdf
867_PT.pdf
914_EN.pdf
914_NL.pdf
Before _ is ID and after language. And I want the user to only see one file per product.
my code looks likes this:
$files = scandir($dir);
foreach ($files as $file)
{
$exp_file = explode("_", $file);
// check file for given ID
if($exp_file[0] == $_GET['iD']){
// check file for userlanguage
if($exp_file[1] == $lang){
echo $file;
}
// check file in english
elseif($exp_file[1] == "EN"){
echo $file;
}
// return available file in other language
else{
echo $file;
}
}
}
In case of 914 and NL the code returns two files. In case of 914 and PT i only get 1 file, 914_EN.pdf and in case of 867 and NL there will be zero files.
What is the best way to filter my files and return the best matched file? I personally think the error is in the for loop, but I cant find a proper way out..
thanks
If you want to have just the single items, you should keep a backlog of which you have already processed, as the foreach loop will go from for example 914_EN.pdf to 914_NL.pdf, while the checks have already been completed for 914_EN.pdf, so when you get to 914_NL.pdf, it just reruns the checks and thinks it is okay.
if working with multiple same values, you can first cleanse the array to get what you wanted. You can take a look at this, if this what you want. Cheers!
$files = array("1096_EN.pdf", "867_PT.pdf", "914_EN.pdf", "914_NL.pdf");
$new_exp_file = array();
foreach ($files as $file) {
$exp_file = explode("_", $file);
$new_exp_file[] = $exp_file[0];
}
$new_exp_file_arr_ = array_values(array_unique($new_exp_file));
for($i = 0, $file_ctr = count($new_exp_file_arr_); $i < $file_ctr; $i++) {
if($new_exp_file_arr_[$i] == "914") {
echo $new_exp_file_arr_[$i] . "<br>";
echo "<ul>";
foreach ($files as $file) {
$exp_file = explode("_", $file);
if($new_exp_file_arr_[$i] == $exp_file[0]) {
echo "<li>" . $exp_file[1] . "</li>";
}
}
echo "</ul>";
}
}
this seems to work for me? Using a regex probably not as efficient as the above methods though.
$_GET['iD'] = 1096;
$ptn = "^((\d+)\_([a-zA-Z]+)\.([a-zA-Z]+))^";
$aFiles = array('1096_EN.pdf','867_PT.pdf','914_EN.pdf','914_NL.pdf');
$lang = "EN";
foreach ($aFiles as $sFileName)
{
preg_match($ptn, $sFileName, $aFileParts);
var_dump($aFileParts);
// check file for given ID
if($aFileParts[2] == $_GET['iD']){
// check file for userlanguage
if(strtolower($aFileParts[3]) == strtolower($lang)){
echo $sFileName;
break;
}
// return available file in other language
else{
echo $sFileName;
}
}
}
I've solved my problem by the following:
if(glob($_GET['iD']."_".$_GET['t']."*.pdf"))
{
$file = glob($_GET['iD']."_".$_GET['t']."*.pdf");
echo $file[0];
}
else
{
if(glob($_GET['iD']."_EN*.pdf"))
{
$file = glob($_GET['iD']."_EN*.pdf");
echo $file[0];
}
else
{
$file = glob($_GET['iD']."*.pdf");
echo $file[0];
}
}
No more looping, just checking for different files with wildcards. Works like a charm. I.m.o. much cleaner with larger lists of files..

PHP - search and replace then sort and echo

I've managed (well, stackoverflow has shown me how) to search a directory on my server and echo and image. The trouble is the images in the folder are named by an IP camera yy_mm_dd_hh_mm where dd (and other date digits) have either one or two digits. I need them to have a preceeding zero so that I don't end up with, for example, an image taken at 9:50am being treated as a higher value than the photo taken more recently, at 10:05am. (I want it to treat it as 09_50 and 10_05 to fix the issue).
I've looked at search and replace but cannot get this to work within my current code:
function webcam_image () {
foreach (glob( "../camera/IPC_IPCamera*.jpg") as $f ) {
$list[] = $f;
}
sort($list);
echo array_pop($list);
}
example file = IPC_IPCamera_13_7_24_9_57_45.jpg
any help would be much appreciated!
Thanks
Ali
I would ignore the file name altogether and use a DirectoryIterator, fetching the files actual modified date. Something like this might work.
$files = array();
$iterator = new \DirectoryIterator('/path/to/dir');
foreach ($iterator as $file) {
if(! $file->isDot()) $files[$file->getMTime()] = $file->getFilename();
}
ksort($files);
print_r($files);
Take a look here for more information: http://php.net/manual/en/class.directoryiterator.php
If I have understood you correctly, you could handle this by preg_replaceing the files.
So you could loop through your files and do the following
$newFilename = preg_replace('/_([0-9])_/', '_0$1_', $oldFilename);
rename($oldFilename, $newFilename);
You can try something like:
function webcam_image () {
foreach (glob( "../camera/IPC_IPCamera*.jpg") as $f ) {
$digits = explode('_', substr(substr($f, 13), 0, -4));
foreach($digits as &$digit){
$digit = sprintf("%02d", $digit);
}
unset($digit);
$list[] = 'IPC_IPCamera_' . implode('_', $digits) . '.jpg';
}
sort($list);
echo array_pop($list);
}
You can use sprintf()
$list[] = $f;
with the following
$list[] = sprintf("%02s", $f);

read file matching lines using array using php

I want to be able to read through a plain text file and match a number of lines without the need to iterate over the text file multiple times. I am passing in an array with a list of strings I would like to match, which ideally, I would like to put into an array.
I can achieve the desired result using the code below, but it necessitates the reading of the text file multiple times.
function readFile($line){
$contents = file("test.txt");
if(preg_match("/$line*/i", $val)){
return($val);
}
}
Ideally, I would like to do the following:
// pass an array to the funciton which will parse the file once and match on the elements defined.
$v = readFile(array("test_1", "test_2", "test_2", "test_3"));
// return an array with the matched elements from the search.
print_r($v);
Any help would be much appreciated.
Thanks all!
$val = array();
foreach ($contents as $file) {
foreach ($line as $l) {
if (stristr($file, $l)) {
$val[] = $file;
break; // Don't need to check the other $line values
}
}
}
$val = array();
foreach ($contents as $file) {
foreach ($line as $l) {
if (stristr($file, $l) {
$val[] = $file;
}
}
}
Even if you want to stick with preg_match, the "*" is unnecessary.

PHP how to get all files(only html files) in all subdirectories and index each html page

For a homework assignment, I have to get all the .htm and .html files in the current and all sub directories, and I have to index them by counting all the words that appear in the files individually.
Here is how I would count the file once I find an html file in a directory:
$file = '.html';
$index = indexer($file);
echo '<pre>'.print_r($index,true).'</pre>';
function indexer($file) {
$index = array();
$find = array('/\r/','/\n/','/\t/','!',',','.','"',';', ':');
$replace = array(' ',' ',' ',' ',' ',' ',' ',' ',' ');
$string = file_get_contents($file);
$string = strip_tags($string);
$string = strtolower($string);
$string = str_replace($find, $replace, $string);
$string = trim($string);
$string = explode(' ', $string);
natcasesort($string);
$i = 0;
foreach($string as $word) {
$word = trim($word);
$ignore = preg_match('/[^a-zA-Z]/', $word);
if($ignore == 1) {
$word = '';
}
if( (!empty($word)) && ($word != '') ) {
if(!isset($index[$i]['word'])) {
$index[$i]['word'] = $word;
$index[$i]['count'] = 1;
} elseif( $index[$i]['word'] == $word ) {
$index[$i]['count'] += 1;
} else {
$i++;
$index[$i]['word'] = $word;
$index[$i]['count'] = 1;
}
}
}
unset($work);
return($index);
}
I just need to figure out first how to find all the htm or html files in the directories and then start using the above code on each htm/html file. Any help will be appreciated, thanks!
Well, because this is a homework assignment, I won't give you the code. But I can point you in the right direction. Usually for this type of thing, people with use a recursive function. Where a function calls itself.
This function should do the following:
Count all the lines of all the htm, and html files in the current directory.
Add these numbers up, and then add them to a global variable outside the function (just use global, you could return the number of lines each call, and add them up, but that is a pain in the butt)
call this function again for every folder in the current directory (just loop through them)
once you are back at the very start, reset the global variable, and return its value
The RecursiveDirectoryIterator is the best class in PHP to do this. It's flexible and fast.
Other alternative methods (not recursive) are described in "Directory to array with PHP". In my answer to that question, I timed the different methods given by other answers, but all of the solutions in PHP code are slower than using the PHP's SPL classes.
Here's an alternative using RecursiveIteratorIterator, RecursiveDirectoryIterator and pathinfo().
<?php
$dir = '/';
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir), RecursiveIteratorIterator::CHILD_FIRST);
foreach ( $iterator as $path )
if ( $path->isFile() && preg_match('/^html?$/i', pathinfo($path->getFilename(), PATHINFO_EXTENSION)) )
echo $path->getPathname() . PHP_EOL;
If you need to get the current working directory, you can use getcwd() (i.e. $dir = getcwd();).
To get the length of the content, you can do a few things. You could retrieve the contents of the file using file_get_contents and use strlen to calculate the length or str_word_count to count the words. Another option could be to use $path->getSize().
If you use an array to store the names and the sizes, you can then use a custom function and uasort to sort the array by sizes.
A more complete example:
<?php
function sort_by_size($a, $b)
{
if ( $a['size'] == $b['size'] )
return 0;
return ( $a['size'] < $b['size'] ? -1 : 1 );
}
$dir = '/';
$files = array();
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir), RecursiveIteratorIterator::CHILD_FIRST);
foreach ( $iterator as $path )
if ( $path->isFile() && preg_match('/^html?$/i', pathinfo($path->getFilename(), PATHINFO_EXTENSION)) )
$files[] = array(
'name' => $path->getPathname(),
'size' => $path->getSize()
);
uasort($files, sort_by_size);
The $files array can then be looped through using a foreach loop. It will contain both the pathname and the size.
Try Using glob function.
$files = glob('*.htm*');
foreach($files as $file) {
//code here
}
Edited:
function readDir($path) {
$files = glob($path . '*.*');
foreach ($files as $file) {
if (is_dir($file)) {
$html_files = array_merge((array) readDir($file . '/'), (array) $html_files);
}
if (in_array(strtolower(end(explode('.', $file))), array('html', 'htm'))) {
$html_files[] = $file;
}
}
return $html_files;
}
Just edited the answer, Try this. (Note: I haven't Not tested the code on any site.)
Thanks
Do you have any restrictions on the functions/classes you can use? If not, then check out RecursiveDirectoryIterator it will let you go through dirs recursively iterating over all the items in the directory. You could then match the extension on each item and if it matches basically do your counting.
An alternative approach to this would be to use glob while iterating over the directories which allows you to do a *.html search like you would use with with the *nix utility find.
As far as counting you might want to take look at str_word_count.

PHP Last Array Key Issue

I have this simple code for pasting images from a directory, I've sorted them into an array but the problem I can't seem to work out is how to get the last array to be different.
This is my code so far:
foreach($images as $image){
echo("{image : '$image'}, ");
}
I'm looking to keep print the single items in the array but on the last one I'd like to not have the comma.
Any help would be great,
Thanks!
Simple.
function doit($image) {
return "{image: '$image'}"
}
$images = array_map('doit',$images);
$images = implode(', ',$images);
echo "{image : '".implode("'}, {image : '",$images)."'}";
Try:
<?php
$buffer = array();
foreach($images as $image){
$buffer[] = "{image : '$image'}";
}
echo implode(', ', $buffer);
Try using the key and the length of the array:
$arrLength = count($images);
foreach($images as $key=>$image){
echo("{image : '$image'}");
if($key < $arrLength - 1){ echo ", "; }
}
Or use an array_map:
function make_array($n)
{
return "{image: '$n'}"
}
$map = array_map("make_array", $images);
$new_array = implode(', ', $map);
You could do this attractively with a do..while loop:
$image = current($images);
do {
echo "{image : '$image'}";
} while (($image = next($images) && (print " ,"));
Note that you have to use print not echo there, as echo does not behave as a function.
The second part of the conditional only executes if the first part passes, so " ," will only be printed if another image exists.
If there is the possibility (as in, even the vaguest possibility) that your array may contain values that aren't non-empty strings, you'll need to be more verbose:
} while (
(false !== ($image = next($images)) &&
(print " ,")
);
I'm not convinced this is very readable, however, even split over multiple lines, so if this is the case I'd go for one of the other approaches.
Either use an if statement and check if it's the last and echo accordingly, or concatenate without echoing, trim the result after it's generated, and echo.
You could do if and else statements, where if its the last image print without comma else if it isn't print with comma.
$last = array_pop(array_keys($images));
foreach($images as $key => $image) {
if ($key == $last) {
... last image ,don't output comma
}
}

Categories