Проблема с чтением чисел из Excel с помощью PHPExcel

#php #phpexcel

#php #phpexcel

Вопрос:

Я пытаюсь прочитать число из excelsheet с помощью PHPExcel.

У меня есть код, который считывает данные:

 $objReader = PHPExcel_IOFactory::createReaderForFile($upload_file);
$objReader = PHPExcel_IOFactory::createReader('Excel2007');
$objReader->setReadDataOnly(true);
$objPHPExcel = $objReader->load($upload_file);
$objWorksheet = $objPHPExcel->getActiveSheet();
$data = array();

$i = 0;

foreach ($objWorksheet->getRowIterator() as $row) {
    if ($i < 1) {
    $i  ; 
    continue; //Skip heading titles
}
$cellIterator = $row->getCellIterator();        
$cellIterator->setIterateOnlyExistingCells(false);      
foreach ($cellIterator as $cell) {          
    $data [$i] [] = $cell->getValue();          
}       
$i   ;
  

Код работает. Я прочитал Excel, и все данные прекрасно сохранены в массиве $ data.
Проблема в том, что в столбце A я получил число (4078500264822). Которое он возвращает как «4078500264820» (см. Последний 0). Неважно, как я это читаю. если я печатаю всю строку, я вижу, что значение неверно. когда я использую такие функции, как «getCalculatedValue», результат тот же.

Я думаю, это как-то связано с тем, как поле сохраняется в Excel. У меня это сохранено как тип «Число». Где как в другой строке. У меня сохранен тот же номер. на этот раз в виде «текста» (excel выдает уведомление об этом). PHPExcel может прочитать это число. У меня есть лист с 40 записями. где в 26 ячейках их последнее число заменяется на 0. Вы можете найти усеченный файл (всего 2 строки) здесь -> http://dl.dropbox.com/u/1458083/excel.xlsx

Ответ №1:

Или, может быть, просто попробуйте ini_set(«точность», «15»); значение по умолчанию равно 12. У меня сработало.

Ответ №2:

На какой платформе вы работаете?

На моем Mac, используя (64-разрядный) интерпретатор PHP из MacPorts с PHPExcel 1.7.6, я, кажется, получаю правильные значения:

 array (
  1 => 
  array (
    0 => 4078500264822,
    1 => '02648-32.000.00',
    2 => 'Wand-slangenbox automatic',
    3 => '20m slang, rolt zichzelf gelijkmatig op na gebruik. Geïntegreerde draaggreep voor 
comfortabel transport, inclusief montagemateriaal en wand-/vloerhouder.',
    4 => 17400,
    5 => 119.95,
    6 => '',
    7 => 12,
  ),
  2 => 
  array (
    0 => '4078500888707',
    1 => '08887-20.000.00',
    2 => 'Accu gras-buxusschaar set',
    3 => 'Eenvoudig gras en buxus in vorm knippen zonder storende kabels. De messen kunnen worden verwisseld zonder gereedschap, het is bijzonder gemakkelijk, snel en veilig. Laat tevens op tijd zien wanneer de accu weer moet worden opgeladen. ',
    4 => 16340,
    5 => 69.95,
    6 => 79.95,
    7 => 12,
  ),
)
  

Каков результат при запуске:

 $ php -r 'echo PHP_INT_MAX;'
  

Если это 2147483647, то попробуйте 64-разрядный интерпретатор. Или отправьте запрос в PHPExcel, чтобы исправить приведение.

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

1. Это самая странная вещь. PHP_INT_MAX возвращает 2147483647 нет как моей живой (Linux), так и тестовой среды (тестирование localhost, Windows). Попытка точно такого же импорта работает на локальном хосте, хотя. Сохранение числа в виде «текста» не решает проблему. К сожалению, просто перейти на 64-битную среду невозможно в реальном времени: (

Ответ №3:

Если значение хранится в виде строки в Excel, то оно будет сохранено в виде строки при загрузке в PHPExcel (при условии, что вы используете связующее значение по умолчанию… расширенный привязчик значений, безусловно, вызовет у вас проблемы, поскольку его назначение — обрабатывать преобразование в более подходящий тип данных). Если оно хранится в виде числа в Excel, то точность теряется еще до того, как оно загружено в PHPExcel.

Однако, что вы могли бы сделать, это установить собственную привязку значений (расширяющую привязку значений по умолчанию) с помощью метода bindValue (), который проверяет ссылку на столбец считываемой ячейки (чтобы увидеть, является ли это столбцом A), и заставляет PHPExcel сохранять это значение в виде строки (даже если числовое значение было прочитано из файла Excel).

Редактировать

Это связующее должно делать то, что я предложил, заставляя PHPExcel загружать все значения в столбце A в виде строк.

 class SpecialValueBinder extends PHPExcel_Cell_DefaultValueBinder implements PHPExcel_Cell_IValueBinder
{
    public function bindValue(PHPExcel_Cell $cell, $value = null)
    {
        if ($cell->getColumn() == 'A') {
            $value = PHPExcel_Shared_String::SanitizeUTF8($value);
            $cell->setValueExplicit($value, PHPExcel_Cell_DataType::TYPE_STRING);
            return true;
        }

        // Not bound yet? Use parent...
        return parent::bindValue($cell, $value);
    }
}


/**  Tell PHPExcel that we want to use our Special Value Binder  **/
PHPExcel_Cell::setValueBinder( new SpecialValueBinder() );
  

Убедитесь, что вы определили связующее и сообщите PHPExcel использовать его перед выполнением load()

ПРАВКА 2

Как и криш, я запустил ваш код на (используя 32-разрядный PHP в Windows). var_dump() возвращает значение 4078500264822 в виде числа с плавающей точкой, чего я и ожидал (значение слишком велико, чтобы его можно было сохранить как 32-разрядное целое число), и, повторяя его, отображает то же самое правильное значение без потери точности.

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

1. Вы говорите, что «Точность теряется еще до того, как она загружена в PHPExcel». Означает ли это, что я просто должен принудительно использовать столбец A с типом text? Я протестировал еще немного, и, похоже, действительно, что при загрузке я получаю значение float: float(4078500264820). если я заставлю столбец быть текстовым, это сработает. (также ваш код преобразует его в строку. но, как вы говорите. точность уже потеряна).

2. Я не согласен с этим. Я проверял источник excel.xlsx файл, и Excel сохраняет полное значение, потому что оно фактически хранится полностью как значение открытого текста в файле worksheet XML. Если бы вы использовали файл xls, то он был бы сохранен в виде 64-разрядного файла с плавающей запятой, что привело бы к неточностям в самом Excel. Поскольку тип ячейки является числовым, PHPExcel по умолчанию преобразует ее в значение с плавающей точкой при загрузке файла (поскольку 32-разрядное целое число не может содержать значение такого размера), и это приведение может привести к потере точности.

3. Специальная привязка заставляет значение обрабатываться как текст (точно так, как оно считывается из файла xlsx), а не преобразовывать его в float, как указывает тип, это должно быть. Поскольку здесь нет приведения к плавающему значению, строковое значение, которое хранится в xml файла xlsx, сохраняется «как есть», поэтому точность не теряется.

4. Еще немного тестировал. кажется, что данные столбца A уже являются плавающими, прежде чем они войдут в bindValue. если я использую var_dump значение $ перед его преобразованием, это уже значение с плавающей точкой с неправильным числом. Я предполагаю, что это приведено в функции $objReader-> load(). могу ли я переопределить это там, чтобы рассматривать все как строку?

Ответ №4:

Спасибо Марку и Кришоджу за вашу поддержку. К сожалению, это не решило проблему; (Я не могу никому здесь дать правильное решение, поскольку мои данные, по-видимому, были повреждены еще до вызова функции загрузки Excel.

Я решил проблему, заставив моего клиента использовать CSV. это было очень незначительное изменение в коде (он же. 1 строка, PHPExcel == потрясающе!) и теперь я получаю все в виде строки (и, таким образом, это работает!)

Еще раз спасибо за всю помощь.

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

1. Здесь мы решаем проблему, чтобы помочь другим, потому что библиотека никому не принадлежит, фактически библиотека сделала открытый исходный код Спасителем