LINUX.ORG.RU

Муки творчества

 , , , ,


2

1

Всем привет!

Наваял/напастил,наговнякал вот такой примерный php-скрипт конвертора docx —> pdf.

Пока правда его не отлаживал, сразу, конечно, ничего не заработает :-)

А сюда пришел за «гнилыми помидорами» от сообщества: поругайте, подскажите, что можно сделать лучше.

Какие есть явные косяки, кроме php?

★★★★★
Ответ на: комментарий от EXL

Так бы сразу и сказал :-)

Я подумал, ты знаешь супер-пупер генератор, скрытый от глаз непосвящённых.

Twissel ★★★★★
() автор топика

Таки да, сменю генератор pdf с tcpdf на wkhtmltopdf, чтоб было меньше возни со шрифтами

Twissel ★★★★★
() автор топика
Ответ на: комментарий от Twissel

Хотя, по-моему, хрен редьки не слаще, посмотрел я на примеры ее использования и расхотелось мне.

Тянуть к пыху целый браузер на Webkit в придачу :-)

Twissel ★★★★★
() автор топика

Есть еще вот такая фигня для конвертации docx2tex.

Внутри тоже сидит Saxon XSLT 2.0 процессор, такие дела...

Twissel ★★★★★
() автор топика
Ответ на: комментарий от Twissel

Хотя текст на немецком обрабатывается нормально.

Похоже, что проблемы только с восточной экзотикой и с кириллицей :-)

Twissel ★★★★★
() автор топика
<?php
ini_set('dispay_errors', 1);
require('tcpdf/tcpdf.php');

function Convertion($proc, $xmlFile, $xslFile, $output_page, $doc_name, $tmp_dir)
{
                $zip = new ZipArchive();
                if ($zip->open($doc_name, ZipArchive::CREATE) === TRUE)
                {
                                $zip->extractTo($tmp_dir);
                                $zip->close();
                }
                $saxonProc = new Saxon\SaxonProcessor();
                $proc      = $saxonProc->newXsltProcessor();
                $proc->setSourceFromFile($xmlFile);
                $proc->compileFromFile($xslFile);
                touch($output_page);
                $proc->setOutputFile($output_page);
                $proc->transformToFile();
                $proc->clearParameters();
                $proc->clearProperties();
}

function ProducePDF($pdf_name, $html_page)
{
                // create new PDF document
                $pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
                
                // set document information
                $pdf->SetCreator(PDF_CREATOR);
                $pdf->SetAuthor('Tony');
                $pdf->SetTitle('A document');
                $pdf->SetSubject('Information');
                $pdf->SetKeywords('TCPDF, PDF');
                
                // set default header data
                $pdf->SetHeaderData('', PDF_HEADER_LOGO_WIDTH, '', '');
                
                // set header and footer fonts
                $pdf->setHeaderFont(Array(
                                PDF_FONT_NAME_MAIN,
                                '',
                                PDF_FONT_SIZE_MAIN
                ));
                $pdf->setFooterFont(Array(
                                PDF_FONT_NAME_DATA,
                                '',
                                PDF_FONT_SIZE_DATA
                ));
                
                // set default monospaced font
                $pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED);
                
                // set margins
                $pdf->SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT);
                $pdf->SetHeaderMargin(PDF_MARGIN_HEADER);
                $pdf->SetFooterMargin(PDF_MARGIN_FOOTER);
                
                // set auto page breaks
                $pdf->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM);
                
                // set image scale factor
                $pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);
                
                // set some language-dependent strings (optional)
                if (file_exists(dirname(__FILE__) . '/lang/eng.php'))
                {
                                require_once(dirname(__FILE__) . '/lang/eng.php');
                                $pdf->setLanguageArray($l);
                }
                // ---------------------------------------------------------
                
                // set font
                $pdf->SetFont('helvetica', '', 12);
                
                // add a page
                $pdf->AddPage();
                
                
                $html = file_get_contents($html_page);
                // output the HTML content
                $pdf->writeHTML($html, true, false, true, false, '');
                
                // reset pointer to the last page
                $pdf->lastPage();
                
                // ---------------------------------------------------------
                
                //Close and output PDF document
                $pdf->Output($pdf_name, 'FI');
                
                
}

function recursiveRemoveDirectory($pathName)
{
                foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($pathName, FilesystemIterator::SKIP_DOTS), RecursiveIteratorIterator::CHILD_FIRST) as $path)
                {
                                $path->isDir() && !$path->isLink() ? rmdir($path->getPathname()) : unlink($path->getPathname());
                }
                chmod($pathName, 0777);
                rmdir($pathName);
}
$doc_name    = "commands_deu.docx";
$result_name = "result.pdf";
//$FILES['userfile']['name'];
$tmp_dir     = substr(str_shuffle(MD5(microtime())), 0, 10);
mkdir($tmp_dir);
$output_page   = $tmp_dir . "/output.html";
$download_path = $tmp_dir . '_' . $result_name;
$xmlFile       = $tmp_dir . "/word/document.xml";
$xslTable      = "xsl/docx2html.xsl";
Convertion($proc, $xmlFile, $xslTable, $output_page, $doc_name, $tmp_dir);
$html = file_get_contents($output_page);
$html = preg_replace('#<script(.*?)>(.*?)</script>#is', '', $html);
file_put_contents($output_page, $html);
ProducePDF($download_path, $output_page);
recursiveRemoveDirectory($tmp_dir);

Вроде подправил отступы :-)

Единственное, что меня нынче радует это то, что мой велосипед создаёт pdf примерно в 3 раза быстрее,

чем docx2tex -p и не тянет столько зависимостей как последний.

Twissel ★★★★★
() автор топика
Последнее исправление: Twissel (всего исправлений: 1)
Ответ на: комментарий от Twissel

Convert indentation to spaces не учили? Безтолковые комменты так и не пропали, мусор с пропусками строк так же остался, предопределённые переменные хоть бы в констатны вынес или передавал бы в аргументы запуска.

kachan ★★
()
Ответ на: комментарий от kachan

Convert indentation to spaces

Отступы табами да, 4 пробела на таб, вроде так.

С остальным согласен, еще «причешу».

Twissel ★★★★★
() автор топика
Ответ на: комментарий от kachan
<?php
ini_set('dispay_errors', 1);
require('tcpdf/tcpdf.php');
function Convertion($proc, $xmlFile, $xslFile, $output_page, $doc_name, $tmp_dir)
{
    $zip = new ZipArchive();
    if ($zip->open($doc_name, ZipArchive::CREATE) === TRUE)
    {
        $zip->extractTo($tmp_dir);
        $zip->close();
    }
    $saxonProc = new Saxon\SaxonProcessor();
    $proc      = $saxonProc->newXsltProcessor();
    $proc->setSourceFromFile($xmlFile);
    $proc->compileFromFile($xslFile);
    touch($output_page);
    $proc->setOutputFile($output_page);
    $proc->transformToFile();
    $proc->clearParameters();
    $proc->clearProperties();
}
function ProducePDF($pdf_name, $html_page)
{
    $pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
    $pdf->SetCreator(PDF_CREATOR);
    $pdf->SetAuthor('Tony');
    $pdf->SetTitle('A document');
    $pdf->SetSubject('Information');
    $pdf->SetKeywords('TCPDF, PDF');
    $pdf->SetHeaderData('', PDF_HEADER_LOGO_WIDTH, '', '');
    $pdf->setHeaderFont(Array(
        PDF_FONT_NAME_MAIN,
        '',
        PDF_FONT_SIZE_MAIN
    ));
    $pdf->setFooterFont(Array(
        PDF_FONT_NAME_DATA,
        '',
        PDF_FONT_SIZE_DATA
    ));
    $pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED);
    $pdf->SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT);
    $pdf->SetHeaderMargin(PDF_MARGIN_HEADER);
    $pdf->SetFooterMargin(PDF_MARGIN_FOOTER);
    $pdf->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM);
    $pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);
    if (file_exists(dirname(__FILE__) . '/lang/eng.php'))
    {
        require_once(dirname(__FILE__) . '/lang/eng.php');
        $pdf->setLanguageArray($l);
    }
    $pdf->SetFont('helvetica', '', 12);
    $pdf->AddPage();
    $html = file_get_contents($html_page);
    $pdf->writeHTML($html, true, false, true, false, '');
    $pdf->lastPage();
    $pdf->Output($pdf_name, 'FI');
}
function recursiveRemoveDirectory($pathName)
{
    foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($pathName, FilesystemIterator::SKIP_DOTS), RecursiveIteratorIterator::CHILD_FIRST) as $path)
    {
        $path->isDir() && !$path->isLink() ? rmdir($path->getPathname()) : unlink($path->getPathname());
    }
    chmod($pathName, 0777);
    rmdir($pathName);
}
$uploads_dir = "uploads";
$tmp_name    = $_FILES["userfile"]["tmp_name"];
$name        = $_FILES["userfile"]["name"];
move_uploaded_file($tmp_name, "$uploads_dir/$name");
$doc_name    = "$uploads_dir/$name";
$result_name = "result.pdf";
$tmp_dir     = substr(str_shuffle(MD5(microtime())), 0, 10);
mkdir($tmp_dir);
$output_page   = $tmp_dir . "/output.html";
$download_path = $tmp_dir . '_' . $result_name;
$xmlFile       = $tmp_dir . "/word/document.xml";
$xslTable      = "xsl/docx2html.xsl";
Convertion($proc, $xmlFile, $xslTable, $output_page, $doc_name, $tmp_dir);
$html = file_get_contents($output_page);
$html = preg_replace('#<script(.*?)>(.*?)</script>#is', '', $html);
file_put_contents($output_page, $html);
ProducePDF($download_path, $output_page);
recursiveRemoveDirectory($tmp_dir);

Остались предопределённые переменные, вроде как.

Twissel ★★★★★
() автор топика
Ответ на: комментарий от Twissel

что сразу бросается в глаза


  • array() заменяем на []
  • dirname(__FILE__) заменяем на __DIR__
  • Сначала создаем каталог, а потом перед удалением chmod($pathName, 0777). А можно сразу задать права при создании mkdir($tmp_dir, 0777), но опять же обрати внимание на umask
  • Да и вообще если все файлы ты создаешь здесь, а потом удаляешь, значит список файлов есть, то можно и не бегать рекурсивно по каталогу, а сразу удалить существующий список файлов.
  • Включи себе error_reporting(E_ALL | E_STRICT); чтобы видеть нужные ошибки
  • Пропуски строк зря все убил, они нужны для отделения логического функционала. У тебя в начальных примерах было их в избытке, но не все же удалять))
kiotoze ★★★★
()
Последнее исправление: kiotoze (всего исправлений: 1)
Ответ на: комментарий от kiotoze

OK, спасибо, что не забыл :-)

Как и следовало ожидать, заказчик допилил проект, наняв другого фрилансера и меня об этом не предупредил, ну да пофиг — приведу в порядок, выложу к себе на GitHub.

Пущай валяется, мож потом в ООП стиле перепишу...

Twissel ★★★★★
() автор топика
Последнее исправление: Twissel (всего исправлений: 1)
Ответ на: комментарий от kiotoze

mkdir($tmp_dir, 0777)

В документации, емнип, пишут, что это дефолтное значение прав доступа при создании каталога, но у меня почему-то оказалось не так.

Пришлось извращаться :-/

Twissel ★★★★★
() автор топика
Последнее исправление: Twissel (всего исправлений: 1)
Ответ на: комментарий от Twissel

Note that you probably want to specify the mode as an octal number, which means it should have a leading zero. The mode is also modified by the current umask, which you can change using umask().

ну и на оффтопике не работает

kiotoze ★★★★
()
Ответ на: комментарий от Kilte

Уже кидали, эту ссыль, спасибо)

Тут самым интригующим моментом было то, что тот XSLT 2.0 процессор таки заработал и мало того, кто-то уже специально за меня написал таблицы преобразования WordML в HTML.

О красоте и правильности кода пока мало заботился, результат, как говорится на лицо :-)

Twissel ★★★★★
() автор топика
Последнее исправление: Twissel (всего исправлений: 1)
Ответ на: комментарий от kiotoze

Ставил я ведущий «восьмеричный» ноль.

Нифига права не ставились.

Локалхост, PHP 5.6.22, Ubuntu 16.04

Twissel ★★★★★
() автор топика

Хотя, справедливости ради, должен сказать, что с правильным враппером wkhtmltopdf работает шустрее tcpdf

Twissel ★★★★★
() автор топика
Последнее исправление: Twissel (всего исправлений: 1)
Ответ на: комментарий от kiotoze

Надо было установить бит setgid для каталога /var/www/html, тогда можно обойтись без chmod

Неплохо было бы это в документации к пыху откомментить. Как думаешь?

Twissel ★★★★★
() автор топика
Ответ на: комментарий от Twissel

arch

➜  ~  php -v
PHP 7.0.7 (cli) (built: May 25 2016 18:40:26) ( NTS )
Copyright (c) 1997-2016 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2016 Zend Technologies
    with Xdebug v2.4.0, Copyright (c) 2002-2016, by Derick Rethans

kiotoze ★★★★
()
Ответ на: комментарий от kiotoze

Ясно, спасибо.

Я проверял на php 5.6.22, но подозреваю, что это фокусы AppArmor'а в Убунте 16.04.

По правде, сейчас лень разбираться работает и ладно.

Twissel ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.