Вопрос:

PHP массив файлов в строку json, отображающий только первый файл правильно

php arrays json cakephp

104 просмотра

2 ответа

179 Репутация автора

У меня есть немного кода, который сканирует данный каталог и выводит содержимое в массив, пример массива выглядит следующим образом;

Array
(
    [0] => docker-vs-vagrant.png
    [floor] => Array
        (
            [moretesting] => Array
                (
                    [0] => Webserver_requests_graph.jpg
                )

        )

    [plans] => Array
        (
            [0] => Screen Shot 2017-10-09 at 7.08.52 pm.png
        )

    [1] => screenshot.png
    [screenshots] => Array
        (
        )

    [test] => Array
        (
            [0] => Screen_Shot_2017-10-09_at_4_52_32_pm.png
        )

    [test2] => Array
        (
            [0] => testScreen Shot 2017-10-09 at 7.08.52 pm.png
        )

)

Как вы можете заметить, файлы, отмеченные ключами [0] и [1], находятся в корневом каталоге, а все остальное организовано в структуру папок.

Код, который я использую для генерации этого массива, выглядит следующим образом;

function dirToArray($dir) {
    $contents = array();

    foreach (scandir($dir) as $node) {
        if ($node == '.' || $node == '..') continue;

        if (is_dir($dir . '/' . $node)) {
            $contents[$node] = $this->dirToArray($dir . '/' . $node);
        } else {
            $contents[] = $node;
        }
    }

    return $contents;
}

После этого я использую встроенную функцию cakephp, чтобы сгладить массив так, чтобы он выглядел следующим образом;

Array
(
    [0] => docker-vs-vagrant.png
    [floor.moretesting.0] => Webserver_requests_graph.jpg
    [plans.0] => Screen Shot 2017-10-09 at 7.08.52 pm.png
    [1] => screenshot.png
    [test.0] => Screen_Shot_2017-10-09_at_4_52_32_pm.png
    [test2.0] => testScreen Shot 2017-10-09 at 7.08.52 pm.png
)

После этого мне нужно отформатировать его в json, чтобы мой javascript api мог читать, функция для этого заключается в следующем;

function flatArrayToJsonString($flatArray)
{
    $arrayId = 1;
    $final_array = [[0, '/', '/', false]];

    foreach ($flatArray as $key => $val) {
        if ($key == '0') {
            $final_array[] = [$arrayId, '/' . $val, $val, true];
            $arrayId++;
        } else {
            $exploded_key = explode('.', $key);
            foreach ($exploded_key as $k => $v) {
                if ($v == '0') {
                    $dots = '.. ';
                    for ($i = 0; $i < count(array_slice($exploded_key, 0, $k)); $i++) {
                        $dots .= '.. ';
                    }
                    $final_array[] = [$arrayId, '/' . join('/', array_slice($exploded_key, 0, $k)) . '/' . $val, $dots . $val, true];
                    $arrayId++;
                } else {
                    $dots = '.. ';
                    for ($i = 0; $i < count(array_slice($exploded_key, 0, $k)); $i++) {
                        $dots .= '.. ';
                    }
                    $final_array[] = [$arrayId, '/' . join('/', array_slice($exploded_key, 0, $k + 1)), $dots . $v, false];
                    $arrayId++;
                }
            }
        }
    }

    return json_encode($final_array);
}

Окончательный результат, который мне возвращают, следующий:

[
    [0,"\/","\/",false],
    [1,"\/docker-vs-vagrant.png","docker-vs-vagrant.png",true],
    [2,"\/floor",".. floor",false],
    [3,"\/floor\/moretesting",".. .. moretesting",false],
    [4,"\/floor\/moretesting\/Webserver_requests_graph.jpg",".. .. .. Webserver_requests_graph.jpg",true],
    [5,"\/plans",".. plans",false],
    [6,"\/plans\/Screen Shot 2017-10-09 at 7.08.52 pm.png",".. .. Screen Shot 2017-10-09 at 7.08.52 pm.png",true],
    [7,"\/1",".. 1",false],
    [8,"\/test",".. test",false],
    [9,"\/test\/Screen_Shot_2017-10-09_at_4_52_32_pm.png",".. .. Screen_Shot_2017-10-09_at_4_52_32_pm.png",true],
    [10,"\/test2",".. test2",false],
    [11,"\/test2\/testScreen Shot 2017-10-09 at 7.08.52 pm.png",".. .. testScreen Shot 2017-10-09 at 7.08.52 pm.png",true]
]

Это прекрасно работает, только если в корневом каталоге или в любом из подкаталогов находится 1 файл.

Но как только другой файл добавляется, он ломается.

Вы можете видеть, что следующее значение;

[1] => screenshot.png

находится не в том месте, и в конечном выводе ломается, отображается как;

[7,"\/1",".. 1",false],

поскольку я пытаюсь отобразить иерархию, это должно отображаться так;

[1,"\/docker-vs-vagrant.png","docker-vs-vagrant.png",true],
[2,"\/screenshot.png","screenshot.png",true],

Описание окончательного результата выглядит следующим образом;

[id, fullpath, displayname, leaf]

где лист означает, если это файл или каталог.

Я сожалею, что такой большой пост, но я поставлен в тупик о том, как это исправить.

Любая помощь будет принята с благодарностью.

Автор: BigJobbies Источник Размещён: 09.11.2017 12:04

Ответы (2)


1 плюс

4241 Репутация автора

Решение

Проблема с вашим кодом в том, что он подготовлен для работы только с одним файлом в папке. Это не только сломается, если у вас есть более одного файла в корневой папке, но то же самое произойдет для подпапок.

Это также сломается, если любая из ваших папок содержит подпапку с именем «0».

Следующий код исправляет эти проблемы:

function flatArrayToJsonString($flatArray)
{
    $arrayId = 1;
    $final_array = [[0, '/', '/', false]];
    ksort($flatArray, SORT_STRING);  // Sort the flat array by keys

    foreach ($flatArray as $key => $val) {
        $exploded_key = explode('.', $key);
        foreach ($exploded_key as $k => $v) {
            if ($k == sizeof($exploded_key)-1) { // last element of exploded key is always a file
                $dots = '.. ';
                for ($i = 0; $i < count(array_slice($exploded_key, 0, $k)); $i++) {
                    $dots .= '.. ';
                }
                $final_array[] = [$arrayId, '/' . join('/', array_slice($exploded_key, 0, $k)) . '/' . $val, $dots . $val, true];
                $arrayId++;
            } else {
                $dots = '.. ';
                for ($i = 0; $i < count(array_slice($exploded_key, 0, $k)); $i++) {
                    $dots .= '.. ';
                }
                $final_array[] = [$arrayId, '/' . join('/', array_slice($exploded_key, 0, $k + 1)), $dots . $v, false];
                $arrayId++;
            }
        }
    }

    return json_encode($final_array);
}

Я попытался изменить ваш код как можно меньше, чтобы сделать его функциональным. Тем не менее, есть гораздо лучшие способы решения вашей проблемы.

Обратите внимание, что ваш код с самого начала имеет недостатки. Сглаживать массив с помощью Hash::flatten()не очень хорошая идея, так как это приведет к разрыву кода, если имена ваших папок содержат точку . Вы можете использовать другой разделитель (например, символ или строку, которые, как вы знаете, ваша файловая система не будет использовать). Тем не менее, всегда лучше работать с ассоциативными массивами или объектами.

Вы должны исследовать другие варианты, например, делать все за один раз при переборе файловой системы (как предложено @ndm в комментариях).

Автор: Inigo Flores Размещён: 12.11.2017 11:21

0 плюса

183 Репутация автора

Вам особенно нужно сплющить массив? Потому что если нет, вы могли бы буквально просто иметь это:

function flatArrayToJsonString($flatArray)
{
    return json_encode($flatArray); //returns string
}

а затем сделать соответствующее форматирование в JavaScript.

Однако я не рекомендую выравнивать исходный массив, так как он имеет структуру / иерархию каталогов в макете исходного массива, прежде чем выровнять его с помощью cakephp.

Изменить: Кроме того, иметь идентификатор не имеет смысла во многих сценариях, потому что файлы и каталоги могут быть добавлены или удалены, что делает недействительными любые идентификаторы, первоначально отправленные через php. Возможно, вам следует пересмотреть свой текущий подход к проблеме

Автор: Al.UrBasebelon Tomeh Размещён: 13.11.2017 09:30
Вопросы из категории :
32x32