Статистика

Участников проекта 105
Опубликовано статей 78
Отчет по карме. Топ 20

Новости блога

1 29.11.2013  Сегодня самым активным участникам newblog'а был выплачен доход с sape.
7 02.11.2012  Ура! Свешилось, нашему сайту дали тИЦ 10. Спасибо всем кто принимает участие в развитии нашего блога.
8 21.08.2012  Интеграция с sape.ru. Теперь каждый автор статей на newblog автоматически зарабатывает на рекламе.
Все новости

Топ 5 категорий

Программирование 46
Операционные системы 9
Базы данных 4
Туризм 2
Заметки 2

Последние 5 заметок (90)

gullyar - Закладки gullyar
gullyar - Ваша первая закладка
osadchaya - Закладки osadchaya
Ira0231188 - Закладки Ira0231188
Ira0231188 - Закладки Ira0231188

Ссылки

www.freedev.asia

php Excel2010 и выше. Как работать с .xlsx форматом напрямую из php.

02.06.2012 11:40 | Просмотров: 2743 | Доход: 96.49 руб. | Комментариев: 7
[Программирование] 
Рейтинг: 5/1

Появилась задача отредактировать значения в одном столбце в .xlsx файле с помощью php в Linux. Соответственно любое взаимодействие через COM отпадает. Отличная библиотека PHPexcel работающая под любой ОС к сожалению не умеет работать с Excel2010, если указывать Excel2007 то сложный файл можно испортить. xlsx файл созданный в Excel2010 представляет собой обычный Zip архив содержащий директории и xml файлы:
 

[Content_Types].xml _rels/ docProps/ xl/
 worksheets/sheetN.xml



Это означает что можно распаковать, отредактировать файлы и заново упаковать при этом не повредив файл. Передо мной стояла задача редактирование ячеек всего в одном столбце, поэтому замарачиваться с готовыми парсерами xml небыло смысла. Задав заведомо уникальное значение в ячейку и grep'нув  я быстро определил какой мне необходимо будет редактировать. Структура ячейки оказалось весьма простой <c r="C6" s="90"><v>5</v></c> где r - координаты, s - формат ячейки, v - значение ячейки. Представляю вашему вниманию пару простых функций на cakephp для работы с .xlsx файлом.

	/**
	 * Распаковка .xlsx файла
	 * 
	 * @param $path Путь до директории
	 * @param $file Название файла
	 * @return Boolean Результат
	 */
	function _excel_unzip($path,$file){
		if(!file_exists($path."/".$file)){
			$this->error('01','Не найден файл: '.$path.'/'.$file);
			return false;
		}
		`cd $path/ && unzip $file`;
		return true;
	}

	/**
	 * Упаковка в .xlsx файл
	 * 
	 * @param $path Путь до директории
	 * @param $file Название файла
	 * @return Boolean Результат
	 */
	function _excel_zip($path,$file){ 
		`rm $path/$file`;
		`cd $path/ && zip -r $file \[Content_Types\].xml _rels/ docProps/ xl/`;
		`cd $path && rm -rf \[Content_Types\].xml _rels/ docProps/ xl/`;
		if(!file_exists($path."/".$file)){
			$this->error('02','Не удалось создать xlsx файл, не найдены компоненты');
			return false;
		}
		return true;
	}

	/**
	 * Редактирование ячейки
	 * 
	 * @param $path Путь до директории
	 * @param $page Номер страницы
	 * @param $coord Координаты ячейки
	 * @param $type Формат ячейки
	 * @param $value Значение ячейки
	 * @return Boolean Результат
	 */
	function _excel_edit($path,$page,$coord,$type,$value){ 
		$filename=$path."/xl/worksheets/sheet".$page.".xml";
		$fp = fopen($filename, "r");
		$contents = fread($fp, filesize($filename));
		fclose($fp);
		$start=strpos($contents,'<c r="'.$coord.'"');
		$end=strpos($contents,'<c r="',$start+1);
		$lft=substr($contents,0,$start);
		$rght=substr($contents,$end,strlen($contents)-$end);
		$insert='<c r="'.$coord.'" '.$type.'><v>'.$value.'</v></c>';
		$contents=$lft.$insert.$rght;
		$fp = fopen($filename, 'w');
		if(!fwrite($fp,$contents)){
	   	$this->error('03','Ошибка редактирования страницы');
	   	return false;
		}
		fclose($fp);
		return true;
	}

	/**
	 * Просмотр ячейки
	 * 
	 * @param $path Путь до директории
	 * @param $page Номер страницы
	 * @param $coord Координаты ячейки
	 * @return String Ячейка
	 */
	function _excel_view($path,$page,$coord){
		 $filename=$path."/xl/worksheets/sheet".$page.".xml";
		 $handle = fopen($filename, "r");
		 $contents = fread($handle, filesize($filename));
		 fclose($handle);
		 $start=strpos($contents,'<c r="'.$coord.'"');
		 $end=strpos($contents,'<c r="',$start+1);
		 return substr($contents, $start,$end-$start);
	}

Пример:

	function main(){
		 Configure::write('debug', 1);

		 $path="/home/gm/labtest";
		 $file='1.xlsx';
		 
		 if($this->_excel_unzip($path,$file)){
			 $this->out($this->_excel_view($path,7,'C6'));
			 $this->_excel_edit($path,7,'C6','s="90"',6);
			 $this->out($this->_excel_view($path,7,'C6'));
			 $this->_excel_zip($path,$file);
		 }
        }

Результат:

<c r="C6" s="90"><v>5</v></c>
<c r="C6" s="90"><v>6</v></c>


© GM
| Комментировать статью |
  • Аноним 0 (23.07.2012 11:00)
    прикольно! помогло, спасибо!
    | Ответить |
    • Аноним 0 (11.06.2016 19:59)
      Это только для числовых значений.... Ибо все строки находятся в отдельном файле и их нужно сопоставлять!
      | Ответить |
  • Tiger +458 (22.08.2012 13:15)
    Это касается только формата xlsx?
    | Ответить |
  • Tiger +458 (22.08.2012 13:16)
    На xls и ods будет работать?
    | Ответить |
    • GM +2587 (22.08.2012 14:35)
      На сколько я знаю у xls были еще не xml, но с xlsx работает на ура :)
      | Ответить |
  • Аноним 0 (04.01.2013 16:11)
    Думаю стоило уточнить что приведенный пример - для cakephp. Более того - для shell. С соответствующими инструкциями по использованию - не все же на кейке пишут.
    | Ответить |
    • GM +2587 (05.01.2013 17:38)
      Согласен, обновил статью, уточнив про cakephp.
      По поводу shell, я в статье указал что наработки для Linux. Команды "cd" и "rm" будут работать из коробки в любом дистрибутиве. Для установки zip в классических deb дистрибутивах: apt-get install zip, в rpm - yum install zip.
      | Ответить |