1

I have the following code to sort the items based on a timestamp.

$arr = [];
foreach(glob('*.json') AS $item) {
    $data = json_decode(file_get_contents($item), true);
    $arr[] = [
        'taken' => $data['taken'],
        'file-name' => $data['file-name'],
        'account' => (empty($data['account']) ? null : $data['account'])
    ];
}

usort($arr, function($x, $y) { return $x['taken'] - $y['taken']; });

Here is the content of 4 of these JSON files I have in my folder:

{"hash":"1b668ef9398fe5fc9f68a3ad87d04a77","account":null,"file-name":"DSC00045","place":null,"taken":1663759434,"uploaded":1759397192},{"hash":"bccfb4221adc1e00b4fa34eef309d025","account":null,"file-name":"DSC00170","place":null,"taken":1663760473,"uploaded":1759397201},{"hash":"5aa05170b8e6c21b947db1a20b5a93ac","account":null,"file-name":"DSC00230","place":null,"taken":1663773888,"uploaded":1759397227},{"hash":"8de553beeda575d16377e62e77183507","account":null,"file-name":"DSC00318","place":null,"taken":1547596822,"uploaded":1759397265}

I want to get the previous and next item based on taken (which is the timestamp).

Currently I have made a mess and used the following to get the current item:

foreach($arr_test AS $test) {
    if($test['file-name'] == $get_image) {
        $current = $test;
    }
}

var_dump($current);

$get_item is the variable for (isset($_GET['img']) ? safetag($_GET['img']) : null) which contains the file name.

But now I am stuck. I have no clue what so ever how to get the previous and next item based on the timestamp.

My goal is to sort all items from the first foreach based on taken, and then get current, previous, and next file name based on when the photos were taken no matter how they are sorted in the folder. It's for a photo gallery.

3
  • 1
    You should work with the image index, not its name. Then getting the previous and next images becomes trivial. Commented Oct 4 at 7:23
  • If you have many images, consider caching the result of the sort. Commented Oct 4 at 7:24
  • Yes, @Olivier. I have an cache.json file :) Commented Oct 4 at 14:29

2 Answers 2

3

If I undertand your requirements correctly, you want to display the photos according to the taken timestamp (in ascending order) in your photo gallery and you already have the data in json format

One of the methods is to

  1. parse the json into an array (by json_decode)
  2. sort the array by taken (by array_multisort)
  3. get the file names of the sorted array

So the code will be

<?php

$json1 = '[{"hash":"1b668ef9398fe5fc9f68a3ad87d04a77","account":null,"file-name":"DSC00045","place":null,"taken":1663759434,"uploaded":1759397192},{"hash":"bccfb4221adc1e00b4fa34eef309d025","account":null,"file-name":"DSC00170","place":null,"taken":1663760473,"uploaded":1759397201},{"hash":"5aa05170b8e6c21b947db1a20b5a93ac","account":null,"file-name":"DSC00230","place":null,"taken":1663773888,"uploaded":1759397227},{"hash":"8de553beeda575d16377e62e77183507","account":null,"file-name":"DSC00318","place":null,"taken":1547596822,"uploaded":1759397265}
]';

$data = json_decode($json1);

$taken = array_column($data, 'taken');

array_multisort(
    $taken, // The column to sort by
    SORT_ASC, // Sort in ascending order
    $data // The multi-dimensional array to be sorted
);

foreach ($data as $value) {
    // Code to execute for each $value
     echo ($value->{'file-name'});
     echo "\n";
   }

See demo

Remarks:

(1) Since file-name contains an hyphen, direct access using the -> operator is not possible because the hyphen is interpreted as a subtraction operator. To access such properties, bracket notation with the key name enclosed in single or double quotes must be used

(2) In real life the file name should have the extension , for an image it may be jpg or png , so the file name is usually DSC00230.jpg instead of DSC00230

(3) change SORT_ASC to SORT_DESC if you want to sort by descending order

(4) Since now we have a sorted array, simply change the array index to get the "previous" and "next" photo, such as:

// assuming current index is 2

$var=2;
echo "Current:". $data[$var]->{'file-name'};
echo "\n";
echo "Previous one:".$data[$var-1]->{'file-name'};
echo "\n";
echo "Next one:".$data[$var+1]->{'file-name'};
echo "\n";

See demo

Sign up to request clarification or add additional context in comments.

Comments

0

The crux of it: Get the first level key of the first row containing a specified column value in a 2d array

After sorting your rows by taken, the above demonstrates that from PHP8.4, there is a functional-style, most-efficient, elegant way to return the first level index of the first qualifying row in your multidimensional array. Demo

$arr = [];
foreach (glob('*.json') as $item) {
    $data = json_decode(file_get_contents($item), true);
    $arr[] = [
        'taken' => $data['taken'],
        'file-name' => $data['file-name'],
        'account' => $data['account'] ?? null // default to null if not declared
    ];
}
usort($data, fn($a, $b) => $a['taken'] <=> $b['taken']); // use 3-way comparison

$getImage = 'DSC00170';
$currentIndex = array_find_key($data, fn($row) => $row['file-name'] === $getImage);

if ($currentIndex === null) {
    echo 'No match';
} else {
    printf("Previous: %s\n", $data[$currentIndex - 1]['file-name'] ?? 'not available');
    printf("Current: %s\n", $data[$currentIndex]['file-name']);
    printf("Next: %s\n", $data[$currentIndex + 1]['file-name'] ?? 'not available');
}

I do not recommend calling array_column() to set up array_multisort() because it implements two sets of loops; versus usort() which directly sorts in one loop. Also SORT_ASC is the default sorting direction, so the call can be safely reduced to array_multisort(array_column($data, 'taken'), $data);

If you don't have PHP8.4, you can find the polyfill in my sandbox demo. Otherwise you should use a break in your row searching loop after the first match is found.

Your script should be designed to cover all edge cases such as: no match, no previous row, and no next row.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.