Почему WP Filesystem API не может прочитать googlefonts.json?

22 окт. 2014 г., 18:49:25
Просмотры: 1.76K
Голосов: 2

Я унаследовал сайт, построенный на теме Highgrade (southcentral), которая использует фреймворк Redux.

В интерфейсе и админ-панели появляется следующая ошибка:

Warning: Invalid argument supplied for foreach() in /Volumes/Data/Users/me/Sites/reference360.eu/wordpress/wp-content/themes/southcentral/highgrade/framework/inc/fields/typography/field_typography.php on line 772

Я пробовал изменять права доступа и владельца для googlefonts.json, но безрезультатно.

Проблема, похоже, кроется в фреймворке Redux - см. эту ветку на github.

Отладка в классе typography.php:

 if (!isset($this->parent->fonts['google']) || empty($this->parent->fonts['google'])) {
            $this->parent->fonts['google'] = json_decode($wp_filesystem->get_contents(ReduxFramework::$_dir . 'inc/fields/typography/googlefonts.json'), true);
            var_dump(ReduxFramework::$_dir . 'inc/fields/typography/googlefonts.json');
            var_dump($wp_filesystem->get_contents(ReduxFramework::$_dir . 'inc/fields/typography/googlefonts.json')); exit;
            $this->parent->font_groups['google'] = array(
                'id'        => 'google',
                'text'      => __('Google Webfonts', 'redux-framework'),
                'children'  => array(),
            );
            foreach ($this->parent->fonts['google'] as $font => $extra) {
                $this->parent->font_groups['google']['children'][] = array(
                    'id'    => $font,
                    'text'  => $font
                );
            }
        }
    }

У кого-нибудь есть идеи, что может вызывать эту проблему? Файл существует и находится по указанному пути. Среда разработки - OSX Mavericks.

ОБНОВЛЕНИЕ:

Изменение владельца всей директории WordPress на _www:_www решает проблему, но это очевидно не самое лучшее решение.

4
Комментарии

Почему ты пытаешься использовать $wp_filesystem->get_contents здесь? Просто используй обычный php file_get_contents вместо этого.

Otto Otto
22 окт. 2014 г. 20:34:32

Я не использую. Автор темы использует. Я хочу понять проблему, а не обходить её костылями.

codecowboy codecowboy
22 окт. 2014 г. 20:35:01

Ну так скажи автору, что он делает-это-неправильно и замени эти вызовы на file_get_contents. Я напишу более подробный ответ здесь.

Otto Otto
22 окт. 2014 г. 20:35:41

Ответ Отто должен быть выбран как ответ на данный вопрос. Хотя, вероятно, можно добавить дополнительный контекст о том, что делать, когда использование file_get_contents() невозможно из-за правил WordPress.

Tim Malone Tim Malone
8 мар. 2018 г. 00:14:55
Все ответы на вопрос 4
8

Не обязательно использовать WP_Filesystem для каждой мелочи, и в данном случае правильное решение — использовать обычный file_get_contents.

WP_Filesystem — это обёртка над различными способами безопасного взаимодействия с файловой системой... но она не предназначена для всего.

По сути, код WP_Filesystem был создан, чтобы позволить WordPress обновлять себя.

В таких случаях владение файлами имеет большое значение. Многие серверы работают от имени пользователя "www" (например), а не реального владельца PHP-файлов. Если бы WordPress записывал файл напрямую в таком случае, результирующий файл принадлежал бы "www", а не настоящему владельцу. Это может привести к проблемам безопасности, особенно на shared-хостинге.

Поэтому WP_Filesystem абстрагирует файловые операции. Он может читать и записывать файлы способами, которые сохранят владение файлами. Если он может записать напрямую и владение останется корректным, он сделает это. Но если нет — ему потребуются учётные данные для какого-либо метода, например FTP. Используя учётные данные, он может войти через этот путь и записать файлы от имени правильного владельца.

Это означает, что перед использованием WP_Filesystem его нужно настроить. Необходимо выполнить тест, и если тест не пройден, то нужно получить учётные данные от пользователя. Без них он не сможет работать.

В вашем случае, поскольку «изменение владельца всей директории WordPress на _www:_www» решило проблему, это именно то, что происходит. Тест на запись файла с сохранением владения не проходит. Изменяя владельца существующих файлов, вы меняете условия для этого теста.

Но правда в том, что в данном случае нет причин использовать WP_Filesystem вообще. Вы читаете файл. Вы можете прочитать его напрямую. Владение здесь не имеет значения. Поэтому действительно стоит просто использовать file_get_contents. Использование WP_Filesystem для этого бессмысленно.

Подробнее о WP_Filesystem с точки зрения его использования: http://ottopress.com/2011/tutorial-using-the-wp_filesystem/

22 окт. 2014 г. 20:43:23
Комментарии

Я нахожу это немного противоречивым — выступать за использование file_get_contents(), в то время как оно запрещено правилами репозитория. Что если это публичная тема в репозитории? Я понимаю, что темы вне репозитория могут (и делают, включая меня) просто "забить" на это правило, но думаю, что это важный контекст для ответа, и случай с темой в репозитории не покрывается рекомендацией использовать эту функцию.

Rarst Rarst
22 окт. 2014 г. 21:58:02

@Otto, значит, WP Filesystem выполняет тест на запись файла перед тем, как сделать $wp_filesystem->get_contents(ReduxFramework::$_dir . 'inc/fields/typography/googlefonts.json') в моём случае? Если бы я знал, куда он пытается записать файл, я мог бы просто изменить права на эту директорию, так что эта информация была бы полезной

codecowboy codecowboy
22 окт. 2014 г. 22:05:21

Также, похоже, что всё, что делает WP_Filesystem_Direct::file_get_contents — это обёртка с подавлением ошибок над php-шной функцией file_get_contents()

codecowboy codecowboy
22 окт. 2014 г. 22:23:00

@codecowboy Глобальная переменная global $wp_filesystem не будет установлена до тех пор, пока вы не вызовете функцию WP_Filesystem(), которая фактически выполняет проверку для каждого из доступных методов. Если прямой метод работает, то он назначается этой переменной. Поэтому вы не можете вызывать $wp_filesystem->get_contents(), пока не вызовите WP_Filesystem() хотя бы один раз.

Otto Otto
22 окт. 2014 г. 23:30:53

@Rarst Если это касается темы в репозитории, я бы рекомендовал полностью переписать это, чтобы не приходилось каждый раз читать и парсить этот .json файл. Вместо того чтобы оставлять его как json файл, вы можете прочитать его один раз, пропустить через json_decode, вывести результат через print_r и поместить это в PHP файл, который затем можно просто подключить для настройки любой переменной, которую он содержит. Зачем каждый раз тратить время на чтение и парсинг файла, если можно сделать это всего один раз?

Otto Otto
22 окт. 2014 г. 23:32:45

@Rarst Что касается более общего случая "чтения файла в теме", я не могу придумать действительно веской причины, по которой тема должна это делать. Мы разрешаем использовать file() специально для таких случаев, но, по правде говоря, это возникало всего несколько раз, и в тех случаях было относительно просто использовать альтернативный подход, который устранял необходимость чтения файла вообще.

Otto Otto
22 окт. 2014 г. 23:34:34

@Otto Я имел в виду, что в форме "использовать обычный file_get_contents()" ответу не хватает контекста, например, правил репозитория. Если кто-то просто использует это, а потом получает отказ при попытке отправить в репозиторий — они посчитают такой совет плохим.

Rarst Rarst
22 окт. 2014 г. 23:36:28

@Rarst Я понимаю твою точку зрения, но не согласен с ней. Он задал вопрос о конкретном фрагменте кода. Мой ответ отражает только это. Он не задавал вопрос, который потребовал бы гораздо более сложного ответа с проверкой темы, плагином Theme Check и официальным бесплатным репозиторием. Он хочет исправить свою проблему и немного узнать о WP_Filesystem, а не понять, как работает вся структура.

Otto Otto
22 окт. 2014 г. 23:42:44
Показать остальные 3 комментариев
3

@codecowboy, какую версию Redux вы используете? В новых версиях мы даже не используем googlefonts.json подобным образом.

Я рекомендую вам просто установить Redux Framework из репозитория плагинов WordPress (http://wordpress.org/plugins/redux-framework/), и эта проблема решится, так как плагин переопределит версию Redux, встроенную в вашу тему.

22 окт. 2014 г. 21:20:42
Комментарии

Спасибо за это. Я попробую это как быстрое решение, которое не сломает возможные будущие обновления темы.

codecowboy codecowboy
22 окт. 2014 г. 21:59:59

Версия Redux, кажется, 3.2.8.1

codecowboy codecowboy
22 окт. 2014 г. 22:00:36

Мы очень стараемся, чтобы обновления не ломали темы, и если такое происходит, мы добавляем совместимость. Мы считаем, что установка плагина - ваш лучший вариант.

Dovy Dovy
2 нояб. 2014 г. 17:39:07
0

После некоторой отладки выяснилось, что на самом деле WP_Filesystem пытается установить FTP-соединение с временным файлом во время выполнения проверок:

public function get_contents( $file ) {
        $tempfile = wp_tempnam($file); // Создаем временный файл
        $temp = fopen($tempfile, 'w+'); // Открываем временный файл для записи

        if ( ! $temp )
            return false; // Если не удалось открыть файл, возвращаем false

        if ( ! @ftp_fget($this->link, $temp, $file, FTP_BINARY ) ) // Пытаемся получить файл по FTP
            return false; // Если не удалось, возвращаем false, и массив Google Fonts остаётся пустым

        fseek( $temp, 0 ); // Перемещаем указатель в начало файла
        $contents = ''; // Инициализируем переменную для содержимого

        while ( ! feof($temp) ) // Читаем файл до конца
            $contents .= fread($temp, 8192); // Добавляем прочитанные данные в переменную

        fclose($temp); // Закрываем файл
        unlink($tempfile); // Удаляем временный файл
        return $contents; // Возвращаем содержимое файла
    }

На моей локальной машине с OSX это не работает, тогда как на целевом сервере всё проходит. Не совсем понятно, почему изменение владельца всей директории Wordpress на _www:_www позволяет ftp_fget отработать успешно, учитывая, что он пытается прочитать временный файл в /var/tmp.

23 окт. 2014 г. 09:15:46
8
-2

Для сведения, последняя версия Redux больше не использует этот конкретный метод для загрузки шрифтов Google. Во-вторых, Отто питает определенную неприязнь к ребятам из Redux, так что воспринимайте его слова с долей скепсиса. Мы постоянно видим ошибки в проверке темы, которые гласят:

ПРЕДУПРЕЖДЕНИЕ: функция file_put_contents найдена в файле class.redux_filesystem.php. Для работы с файлами следует использовать методы WP_Filesystem вместо прямых вызовов файловой системы PHP.

Серьёзно? То есть, Отто? Ты придумываешь стандарты и рекомендации на ходу? В этом есть смысл, учитывая, что вся основа $wp_filesystem выглядит так, будто её собирали по кусочкам дети, которые не имели ни малейшего понятия, что они делают. Какие уж там стандарты!

22 окт. 2014 г. 21:13:38
Комментарии

Я говорил не напрямую о вашей теме, а о предоставленном коде. Я ничего не знаю о вашем фреймворке как таковом. Никогда не изучал его подробно.

Otto Otto
22 окт. 2014 г. 21:17:40

Кроме того, использование file_get_contents не разрешено для тем в каталоге WordPress.org, в основном потому что множество вредоносных программ используют эту функцию. Плагин Theme Check специально ориентирован на эти стандарты.

Тем не менее, вместо того чтобы читать .json файл и декодировать его каждый раз, гораздо логичнее один раз декодировать его и включить полученный PHP-массив непосредственно в код.

Otto Otto
22 окт. 2014 г. 21:19:14

Нет, это не моя тема, и, честно говоря, сэр, я не верю вам насчёт фреймворка, учитывая недавние события с ним.

kprovance kprovance
22 окт. 2014 г. 21:19:26

@kprovance Не уверен, что он питает ненависть, он высказывался в общих чертах.

Отто, так как ты предлагаешь нам найти постоянное решение помимо того, что мы уже сделали? Мы пытаемся использовать WP_Filesystem, но если он не срабатывает, используем file_get_contents. Это приемлемо? До сих пор всё работало нормально.

Dovy Dovy
22 окт. 2014 г. 21:22:16

Ребята из Redux могут не соглашаться со мной и использовать то, что лучше всего подходит для них и их пользователей. Меня это совершенно не беспокоит.

Otto Otto
22 окт. 2014 г. 21:22:57

Отто, пожалуйста, напишите мне на email или в Skype. dovy@reduxframework.com. Skype: DovyDigital

Я хотел бы разрешить все вопросы и получить ваш честный совет.

Dovy Dovy
22 окт. 2014 г. 21:24:18

Пожалуйста, обсудите это в другом месте. Stack Exchange по своей природе не является форумом, тем более для решения межличностных конфликтов.

Rarst Rarst
22 окт. 2014 г. 21:51:04
Показать остальные 3 комментариев