Intereting Posts
Перенаправить произвольный субдомен на страницу с помощью $ _get info Поиск возможных комбинаций чисел для суммы (с учетом числа, выбранного для выбора) Захват вывода FFMPEG пытаясь загрузить файл с помощью загруженного файла ajax, но в поврежденном php ajax jquery Извлечь текст из строки до ":", если существует? Как обработать <div> как форму <input> Получение данных из базы данных sql и отображение в таблицах. Отображение определенных данных в соответствии с установленными флажками. Очистить содержимое сайта С помощью безопасного входа в систему Транслитерировать любой конвертируемый utf8 char в эквивалент ascii Как преобразовать императивные единицы длины в метрику? Добавить данные в файл .JSON с помощью PHP Получите минимальное ID и максимальное значение ID в MySQL php Композитор не находит локальную зависимость vcs Применение различных CSS для 10 результатов запроса Как я могу без проблем запускать NSArray из NSDictionaries внутри NSDictionary?

Параметр fgetcsv / fputcsv $ escape полностью нарушен

обзор

fgetcsv и fputcsv поддерживают аргумент $escape , однако он либо сломан, либо я не понимаю, как он должен работать. Игнорируйте тот факт, что вы не видите параметр $escape зарегистрированный на fputcsv , он поддерживается в PHP-источнике, есть небольшая ошибка, которая препятствует его fputcsv в документацию.

Функция также поддерживает параметры $delimiter и $enclosure , по умолчанию – запятую и двойную кавычку соответственно. Я бы ожидал, что параметр $escape должен быть передан, чтобы иметь поле, содержащее любой из этих метасимволов (обратная косая черта, запятая или двойная кавычка), однако это, конечно, не так. (Теперь я понимаю, что, читая Википедию , они должны быть заключены в двойные кавычки).

Что я пробовал

Возьмем, к примеру, ловушку, которая затронула многочисленные плакаты в разделе комментариев из документации fgetcsv . Случай, когда мы хотели бы написать одну обратную косую черту в поле.

 $r = fopen('/tmp/test.csv', 'w'); fwrite($r, '"\"'); fclose($r); $r = fopen('/tmp/test.csv', 'r'); var_dump(fgetcsv($r)); fclose($r); 

Это возвращает false . Я также попробовал "\\" , однако это также возвращает false . Заполнение обратной косой черты с некоторым туманным текстом дает fgetcsv импульс, который ему нужен … "hi\\there" и "hi\there" оба разбора и имеют одинаковый результат, но результат имеет только 1 обратную косую черту, так что точка $escape вообще?

Я наблюдал такое же поведение, когда не включал обратную косую черту в двойных кавычках. Запись файла CSV, содержащего строку \ и \\ , имеет тот же результат при fgetcsv , 1 обратная косая черта.

Давайте спросим PHP, как он может кодировать обратную косую черту как поле в CSV, используя fputcsv

 $r = fopen('/tmp/test.csv', 'w'); fputcsv($r, array('\\')); fclose($r); echo file_get_contents('/tmp/test.csv'); 

Результатом является двойная кодовая замкнутая обратная косая черта (и я пробовал 3 версии PHP> 5.5.4, когда предположительно добавлялась поддержка $enclose fputcsv в fputcsv ). fgetcsv этого заключается в том, что fgetcsv не может даже прочитать его правильно в моих заметках выше, он возвращает false … Я ожидал, что fputcsv не будет заключать обратную косую черту в двойных кавычках или fgetcsv , чтобы читать "\" как fputcsv написал это … или действительно в моем, по-видимому, неправильном мышлении, для fputcsv чтобы fputcsv написал двойную кавычку, заключенную пару обратных косых черт, и чтобы fgetcsv мог правильно ее разобрать!

Воспроизводимый тест

Попробуйте написать одну цитату в файл с помощью fputcsv , а затем прочитать ее через fgetcsv .

 $aBackslash = array('\\'); // Write a single backslash to a file using fputcsv $r = fopen('/tmp/test.csv', 'w'); fputcsv($r, $aBackslash); fclose($r); // Read the file using fgetcsv $r = fopen('/tmp/test.csv', 'r'); $aFgetcsv = fgetcsv($r); fclose($r); // Compare the read value from fgetcsv to our original value if(count(array_diff($aBackslash, $aFgetcsv))) echo "PHP CSV support is broken\n"; 

Вопросов

Сделав шаг назад, у меня есть некоторые вопросы

  • В чем смысл параметра $escape ?
  • Учитывая свободное определение CSV-файлов, можно ли сказать, что PHP правильно их поддерживает?
  • Каков «правильный» способ кодирования обратной косой черты в файле CSV?

Задний план

Первоначально я обнаружил это, когда сотрудник предоставил мне CSV-файл, созданный на Python, который написал одиночную обратную косую черту, заключенную в двойные кавычки, и после того, как fgetcsv не смог ее прочитать. У меня был gaul, чтобы спросить его, может ли он использовать стандартную функцию Python. Мало ли я знаю, что инструментарий PHP CSV – запутанный беспорядок! (FWIW: разработчик Python говорит мне, что использует модуль записи CSV).

Из быстрого обзора документации Python по параметрам формата CSV escape-символ, используемый в закрытых значениях (т. Е. Внутри двойных кавычек), является другой двойной цитатой.

Для PHP escape-символом по умолчанию является обратная косая черта (^) ; чтобы соответствовать поведению Python, вам нужно использовать это:

 $data = fgetcsv($r, 0, ',', '"', '"'); 

(^) На самом деле fgetcsv() обрабатывает как $enclosure||$enclosure и $escape||$enclosure таким же образом, поэтому аргумент $escape используется, чтобы избежать обработки обратной косой черты как специального символа.

(^^) Установка параметра $length в 0 вместо фиксированного жесткого предела делает его менее эффективным.

EDIT 2

Поэтому после сна и перехвата кода, оказывается, что fputcsv не принимает параметр escape, и я был глуп. Я обновил код ниже до правильного рабочего кода. Один и тот же базовый принцип применяется, параметр escape должен изменить параметр escape, чтобы вы могли загрузить CSV с обратной косой чертой, не считая их escape-символами. Хитрость заключается в использовании символа, который не содержится в csv. Вы можете сделать это, grepping файла для определенного символа, пока не найдете тот, который не возвращается.

РЕДАКТИРОВАТЬ

Хорошо, поэтому вердикт заключается в том, что он проверяет escape-символ, а затем никогда не прекращает проверку. Итак, если он найдет это, это ускользнет. Так просто.

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

Здесь я превратил ваш пример кода в рабочий код:

 $aBackslash = array('\\'); // Write a single backslash to a file using fputcsv $r = fopen('/tmp/test.csv', 'w'); fputcsv($r, $aBackslash, ',', '"'); // EDIT 2: Removed escape param that causes PHP Notice. fclose($r); // Read the file using fgetcsv $r = fopen('/tmp/test.csv', 'r'); $aFgetcsv = fgetcsv($r, ',', '"', '#'); fclose($r); // Compare the read value from fgetcsv to our original value if(count(array_diff($aBackslash, $aFgetcsv))) echo "PHP CSV support is broken\n"; else echo "PHP WORKS!\n"; 

Одним из важных моментов является то, что как fgetcsv и fputcsv должны иметь одинаковые параметры, иначе возвращаемый массив не будет соответствовать исходному массиву.

ОРИГИНАЛЬНЫЙ ОТВЕТ

Вы очень верны. Это не соответствует языку. Я пробовал каждую перестановку косых черт, о которой я могу думать, и я до сих пор не добился успешного ответа от CSV. Он всегда возвращается, как говорит ваш пример.

Я думаю, что упоминалось @deceze в том, что в вашем примере вы используете array('\\') который на самом деле является строковым литералом «\», который PHP интерпретирует как таковой, и передает «\» в CSV, который затем возвращается путь. Это возвращает ошибочный ответ \" , который, как я уже говорил выше, определенно ошибочен.

Мне удалось найти работу, чтобы результат был действительно уместным:

Во-первых, для вашего примера нам нужно будет сгенерировать /tmp/test.csv с «\» в качестве тела или немного изменить массив. Самый простой способ – просто изменить массив на:

 array('"\\\\"'); 

После этого мы должны немного изменить запрос fgetcsv.

 $aFgetcsv = fgetcsv($r); $aFgetcsv = array_map('stripslashes', $aFgetcsv); 

Делая это, мы говорим PHP о том, чтобы удалить первую косую черту, создав таким образом строку в $ aFgetcsv "\"