Запуск команд по системе от php - PullRequest
0 голосов
/ 24 июня 2011

Я установил wkhtmltopdf , используя

sudo apt-get install wkhtmltopdf

У меня есть скрипт php, который генерирует команду для этого.

Примером того, что он генерирует, является

wkhtmltopdf 'http://stackoverflow.com' "/tmp/Stack Overflow.pdf" --orientation Portrait --page-size A1 --zoom 1

, который при запуске в терминале работает нормально.

Однако при запуске с использованием shell_exec()похоже, это не имеет никакого эффекта.

Обратите внимание, что вызов echo shell_exec('wkhtmltopdf --version -'); выводит информацию о версии, поэтому что-то работает ...

Фактический код:

class pdf
{

    protected $contents_url = null;
    protected $local_html_file = null;
    protected $contents_are_local = false;

    protected $tmp_path = '/tmp/';
    protected $exec_path = '/usr/bin/wkhtmltopdf';
    protected $cmd = null;

    protected $orientation = 'Portrait';
    protected $size = pdf::A4;
    protected $toc = false;
    protected $color = true;
    protected $title = null;
    protected $auth = array('enable' => false, 'user' => null, 'pass' => null);
    protected $headers = array();
    protected $cookies = array();
    protected $post = array();
    protected $replace = array();
    protected $forms = false;
    protected $zoom = 1;
    protected $javascript = true;
    protected $footer = array('center' => null, 'left' => null, 'right' => null, 'font' => null, 'size' => null,
                              'spacing' => null, 'html' => null, 'line' => null);
    protected $heading = array('center' => null, 'left' => null, 'right' => null, 'font' => null, 'size' => null,
                              'spacing' => null, 'html' => null, 'line' => null, 'default' => null);

    //these are the supported paper sizes, although they don't do much, using the const's means that if you use
    //an unsupported size php will throw an error
    const A0 = 'A1';
    const A1 = 'A1';
    const A2 = 'A2';
    const A3 = 'A3';
    const A4 = 'A4';
    const A5 = 'A5';
    const A6 = 'A6';
    const A7 = 'A7';
    const A8 = 'A8';
    const A9 = 'A9';

    const B0 = 'B1';
    const B1 = 'B1';
    const B2 = 'B2';
    const B3 = 'B3';
    const B4 = 'B4';
    const B5 = 'B5';
    const B6 = 'B6';
    const B7 = 'B7';
    const B8 = 'B8';
    const B9 = 'B9';
    const B10 = 'B10';

    const C5E = 'C5E';
    const Comm10E = 'Comm10E';
    const DLE = 'DLE';
    const Executive = 'Executive';
    const Folio = 'Folio';
    const Ledger = 'Ledger';
    const Legal = 'Legal';
    const Letter = 'Letter';
    const Tabloid = 'Tabloid';

    public function __construct($contents = null)
    {

    error_reporting(E_ALL);
ini_set('display_errors', 1);
        if ($contents != null)
            $this->contents($contents);

    }

    public function contents($contents = 'http://example.com')
    {
        if (stripos($contents, 'http://') === 0 || stripos($contents, 'https://') === 0) {
            $this->contents_url = $contents;
            $this->contents_are_local = false;
            return $this;
        }

        if ($this->local_html_file == null)
            $this->local_html_file = $this->tmp_path . rand(0, 1000) . md5(microtime()) . '.html';

        if (!file_put_contents($this->local_html_file, $contents)) {
            trigger_error('Failed to write contents to file');
            return false;
        }

        $this->contents_are_local = true;
        $this->contents_url = $this->local_html_file;

        return $this;
    }

    //set the path to a writeable folder
    public function tmp($path = '/tmp/')
    {
        $this->tmp_path = $path;
        return $this;
    }

    //set the path to the executable
    public function executable($path = 'wkhtmltopdf-i386')
    {
        $this->exec_path = $path;
        return $this;
    }

    //set the orientation of the pdf file
    public function orient($orientation = 'Portrait')
    {
        $this->orientation = ucfirst($orientation);
        return $this;
    }

    //set the size of the page
    public function size($size = pdf::A4)
    {
        $this->size = ucfirst($size);
        return $this;
    }

    //use table of contents?
    public function toc($create_toc = false)
    {
        $this->toc = $create_toc;
        return $this;
    }

    //create color pdf?
    public function color($use_color = true)
    {
        $this->color = $use_color;
        return $this;
    }

    //alias for color, damn americans!
    public function colour($use_colour = true)
    {
        return $this->color($use_colour);
    }

    //set the title. by default this is the document title
    public function title($title = null)
    {
        $this->title = $title;
    }

    //set a custom header for accessing the page
    public function header($key, $value = null)
    {
        if ($value == null)
            unset($this->headers[$key]);
        else
            $this->headers[$key] = $value;
        return $this;
    }

    //set a custom cookie for accessing the page
    public function cookie($key, $value = null)
    {
        if ($value == null)
            unset($this->cookies[$key]);
        else
            $this->cookies[$key] = $value;
        return $this;
    }

    //set a custom post field for accessing the page
    public function post($key, $value = null)
    {
        if ($value == null)
            unset($this->cookies[$key]);
        else
            $this->post[$key] = $value;
        return $this;
    }

    //used to set a custom replace string in the header/footer
    public function replace($what, $with = null)
    {
        if ($with == null)
            unset($this->replace[$what]);
        else
            $this->replace[$what] = $with;
        return $this;
    }

    //do you want to convert html forms to pdf forms?
    public function forms($enable = true)
    {
        $this->forms = $enable;
        return $this;
    }

    public function zoom($level = 1)
    {
        $this->zoom = $level;
    }

    public function javascript($enable = true){
        $this->javascript = $enable;
    }

    //used to request the page with basic http auth
    public function authenticate($username = null, $password = null)
    {
        if ($username == null && $password == null) {
            $this->auth['enable'] == false;
            return $this;
        }

        if (($username == null && $password != null) || ($username != null && $password == null)) {
            trigger_error('Username and Password must be set to use authentication, (call function with no parameters to disabled authentication)');
            return $this;
        }

        $disallowed = array(' ', '/', '\'', '"', '\\');

        foreach ($disallowed as $char) {
            if (stripos($username . $password, $char) !== false) {
                trigger_error('Invalid characters in authentication settings');
                return $this;
            }
        }

        $this->auth['enabled'] = true;
        $this->auth['user'] = $username;
        $this->auth['pass'] = $password;
        return $this;
    }

    //used to set all the footer options    
    public function footer($what = null, $value = null)
    {
        //support for array to be passed
        if(is_array($what)){
            foreach($what as $key => $val)
                $this->footer($key, $val);
            return $this;
        }

        //handler to clear footer
        if($what == null){
            foreach($this->footer as &$val)
                $val = null;
            return $this;
        }


        switch (strtolower($what)) {

            //centered footer text
            case 'center':
                $this->footer['center'] = $value;
                return $this;

            //left aligned footer text
                case 'left':
                $this->footer['left'] = $value;
                return $this;

            //right aligned footer text
            case 'right':
                $this->footer['right'] = $value;
                return $this;

            //footer font name (default Arial)
            case 'font':
            case 'font-name':
                $this->footer['font'] = $value;
                return $this;

            //footer font size
            case 'size':
            case 'font-size':
                $this->footer['size'] = $value;
                return $this;

            //url if you wish an html page to be used as the footer
            case 'html':
                foreach($this->footer as &$val) $val = null;
                $this->footer['html'] = $value;
                return $this;

            //display a line above the footer
            case 'line':
                $this->footer['line'] = $value;
                return $this;

            //spacing between footer and content in mm
            case 'spacing';
                $this->footer['spacing'] = $value;
                return $this;

            default:
                trigger_error('Invalid options passed to footer');
                return $this;
        }
    }

    //documentation same as footer
    public function heading($what = null, $value = null)
    {

        //support for array to be passed
        if(is_array($what)){
            foreach($what as $key => $val)
                $this->heading($key, $val);
            return $this;
        }

        if($what != 'default')
            $this->heading['default'] == null;

        //handler to clear footer
        if($what == null){
            foreach($this->footer as &$val)
                $val = null;
            return $this;
        }


        switch (strtolower($what)) {

            //centered heading text
            case 'center':
                $this->heading['center'] = $value;
                return $this;

            //left aligned heading text
            case 'left':
                $this->heading['left'] = $value;
                return $this;

            //right aligned heading text
            case 'right':
                $this->heading['right'] = $value;
                return $this;

            //heading font name (default Arial)
            case 'font':
            case 'font-name':
                $this->heading['font'] = $value;
                return $this;

            //heading font size
            case 'size':
            case 'font-size':
                $this->heading['size'] = $value;
                return $this;

            //url if you wish an html page to be used as the heading
            case 'html':
                foreach($this->heading as &$val) $val = null;
                $this->heading['html'] = $value;
                return $this;

            //display a line below the heading
            case 'line':
                $this->heading['line'] = $value;
                return $this;

            //spacing between heading and content in mm
            case 'spacing';
                $this->heading['spacing'] = $value;
                return $this;

            //used to enable the default heading
            case 'default':
                foreach($this->heading as &$val) $val = null;
                $this->heading['default'] = $value;
                return $this;

            default:
                trigger_error('Invalid options passed to heading');
                return $this;
        }
    }

    //function to generate pdf, saveFile is used to change where the file is saved to
    //if saveFile is not set, a file will be created in the tmp directory
    public function generate($mode = 'return|clean|remove', $saveFile = null, $use_tmp = false)
    {
        //if (!file_exists($this->exec_path))
        //    trigger_error('Could not load executable');

        $input = escapeshellarg($this->contents_url);

        $output = ($saveFile == null ? $this->tmp_path . rand(0, 1000) . md5(microtime()) . '.pdf' : ($use_tmp
                ? $this->tmp_path : '') . $saveFile . '.pdf');
        $filename = end(explode('/', $output));

        if (!$this->execute($input, $output)) {
            trigger_error('Failed to create pdf');
            return false;
        }

        $pdf = file_get_contents($output);

        $actions = explode('|', str_replace(' ', '', $mode));

        //-------------------------
        //VALID ACTION SETS
        //-------------------------
        //using a non-valid action
        //set will cause un-intended
        //consequences
        //-----------------------
        //DOWNLOAD
        //-----------------------
        //RETURN
        //-----------------------
        //SAVE
        //-----------------------
        //EMBED
        //-------------------------
        //REMOVE + DOWNLOAD
        //-------------------------
        //REMOVE + RETURN
        //-----------------------
        //REMOVE + EMBED
        //-------------------------
        //CLEAN + DOWNLOAD
        //-------------------------
        //CLEAN + RETURN
        //-------------------------
        //CLEAN + SAVE
        //-----------------------
        //CLEAN + EMBED
        //-------------------------
        //CLEAN + REMOVE + DOWNLOAD
        //-------------------------
        //CLEAN + REMOVE + RETURN
        //-------------------------
        //CLEAN + REMOVE + EMBED
        //-----------------------


        //CLEAN: remove the html file
        if (in_array('clean', $actions) && $this->local_html_file != null)
            unlink($this->local_html_file);

        //REMOVE: remove the pdf file
        if (in_array('remove', $actions))
            unlink($output);

        //SAVE: don't delete the pdf and return the path to it
        if (in_array('save', $actions))
            return $output;

        //RETURN: return the pdf as a string
        if (in_array('return', $actions))
            return $pdf;

        //DOWNLOAD: generate a download request
        if (in_array('download', $actions)) {
            header('Content-Type: application/pdf');
            header('Content-Length: ' . strlen($pdf));
            header('Content-Disposition: attachment; filename="' . $filename . '"');
            header('Cache-Control: private, max-age=0, must-revalidate');
            header('Pragma: public');
            ini_set('zlib.output_compression', '0');
            die($pdf);
        }

        //EMBED: show the pdf
        if (in_array('embed', $actions)) {
            header('Content-Type: application/pdf');
            header('Content-Length: ' . strlen($pdf));
            header('Content-Disposition: inline; filename="' . $filename . '"');
            header('Cache-Control: private, max-age=0, must-revalidate');
            header('Pragma: public');
            ini_set('zlib.output_compression', '0');
            die($pdf);
        }

        trigger_error('No return type for pdf specified');


    }

    private function execute($input, $output)
    {
        $this->cmd = $this->exec_path;
        $this->cmd .= ' ' . $input;
        $this->cmd .= ' "' . $output.'"';
        $this->cmd .= ' --orientation ' . $this->orientation;
        $this->cmd .= ' --page-size ' . $this->size;
        $this->cmd .= ' --zoom ' . $this->zoom;

        $this->cmd .= ($this->toc ? ' --toc' : '');
        $this->cmd .= ($this->javascript ? '' : ' --disable-javascript');
        $this->cmd .= ($this->color ? '' : ' --grayscale');
        $this->cmd .= ($this->forms ? ' --forms' : '');
        $this->cmd .= ($this->title != null ? ' --title "' . $this->title . '"' : '');

        $this->cmd .= ($this->heading['center']  == null ? '' : ' --header-center "'.$this->heading['center'].'"');
        $this->cmd .= ($this->heading['left']    == null ? '' : ' --header-left "'.$this->heading['left'].'"');
        $this->cmd .= ($this->heading['right']   == null ? '' : ' --header-right "'.$this->heading['right'].'"');
        $this->cmd .= ($this->heading['font']    == null ? '' : ' --header-font-name "'.$this->heading['font'].'"');
        $this->cmd .= ($this->heading['size']    == null ? '' : ' --header-font-size '.$this->heading['size']);
        $this->cmd .= ($this->heading['line']    == null ? '' : ' --header-line');
        $this->cmd .= ($this->heading['spacing'] == null ? '' : ' --header-spacing '.$this->heading['spacing']);
        $this->cmd .= ($this->heading['html']    == null ? '' : ' --header-html '.$this->heading['html']);
        $this->cmd .= ($this->heading['default'] == null ? '' : ' --default-header');

        $this->cmd .= ($this->footer['center']   == null ? '' : ' --footer-center "'.$this->footer['center'].'"');
        $this->cmd .= ($this->footer['left']     == null ? '' : ' --footer-left "'.$this->footer['left'].'"');
        $this->cmd .= ($this->footer['right']    == null ? '' : ' --footer-right "'.$this->footer['right'].'"');
        $this->cmd .= ($this->footer['font']     == null ? '' : ' --footer-font-name "'.$this->footer['font'].'"');
        $this->cmd .= ($this->footer['size']     == null ? '' : ' --footer-font-size '.$this->footer['size']);
        $this->cmd .= ($this->footer['line']     == null ? '' : ' --footer-line');
        $this->cmd .= ($this->footer['spacing']  == null ? '' : ' --footer-spacing '.$this->footer['spacing']);
        $this->cmd .= ($this->footer['html']     == null ? '' : ' --footer-html '.$this->footer['html']);

        if ($this->auth['enable']) {
            $this->cmd .= ' --username ' . $this->auth['user'];
            $this->cmd .= ' --password ' . $this->auth['pass'];
        }

        foreach ($this->headers as $key => $value)
            $this->cmd .= ' --custom-header ' . $key . ' ' . $value;

        foreach ($this->cookies as $key => $value)
            $this->cmd .= ' --cookie ' . $key . ' ' . $value;

        foreach ($this->post as $key => $value)
            $this->cmd .= ' --post ' . $key . ' ' . $value;

        foreach ($this->replace as $key => $value)
            $this->cmd .= ' --replace ' . $key . ' "' . $value.'"';


        //debug flag
        if(isset($_GET['show_convert_cmd']) && $_GET['show_convert_cmd'])
        die($this->cmd);
        //todo: find all possible return values on correct function
        //todo: for now we will just spit out true for everything        
        shell_exec($this->cmd);
                return true;
    }

}

?>

Демонстрационная страница

if (!isset($_GET['example'])) {
    $examples = array(
        'DEFAULT SETTINGS: HTML STRING',
        'DEFAULT SETTINGS: RETURN',
        'DEFAULT SETTINGS: DOWNLOAD',
        'DEFAULT SETTINGS: SAVE',
        'SETTING PAPER SIZE: A0',
        'USING TABLE OF CONTENTS',
        'GRAYSCALE PDF GENERATION',
        'SETTING ORIENTATION: LANDSCAPE',
        'BASIC HTTP AUTHENTICATION',
        'SETTING CUSTOM HTTP HEADERS',
        'SETTING COOKIES',
        'ENABLE FORM CONVERSION',
        'HEADERS AND FOOTERS: ENABLE DEFAULT PDF HEADER',
        'HEADERS AND FOOTERS: SET LEFT CONTENT AND A CUSTOM REPLACEMENT VALUE',
        'HEADERS AND FOOTERS: SET LEFT AND RIGHT CONTENT USING MULTIPLE CALLS',
        'HEADERS AND FOOTERS: SET LEFT AND RIGHT CONTENT USING AN ARRAY',
        'DISABLE JAVASCRIPT',
        'SETTING ZOOM LEVEL'
    );

    foreach ($examples as $id => $example) {
        echo '<a href="?example=' . $id . '">' . $example . '</a><hr />';
    }
    die();
}

require_once('class.php');
$html = '<!doctype html><html><head><title>Lol Title</title><link rel="stylesheet" href="http://doc.trolltech.com/4.6/classic.css"/></head><body><h2>Lols</h2><table class="valuelist"><tr><th>Lol</th><th>Again</th></tr><tr><td>First</td><td>Second</td></tr></table><h2>Form</h2><form><input value="input" /><input type="checkbox" /><input type="checkbox" checked="checked" /><input type="submit" value="Submit" /></form></body></html>';
$html_pdf_name = 'HTML Example';

$url = 'http://stackoverflow.com';
$url_pdf_name = 'Stack Overflow';

switch ($_GET['example']) {
    //--------------------------------------
    //EXAMPLE: DEFAULT SETTINGS: HTML STRING
    //--------------------------------------
    case 0:
        $pdf = new pdf($html);
        $pdf->generate('remove|clean|embed', $html_pdf_name, true);
        break;


    //--------------------------------------
    //EXAMPLE: DEFAULT SETTINGS: RETURN
    //--------------------------------------
    case 1:
        $pdf = new pdf($url);
        $pdf_contents = $pdf->generate('remove|clean|return', $url_pdf_name, true);
        echo $pdf_contents;
        break;

    //--------------------------------------
    //EXAMPLE: DEFAULT SETTINGS: DOWNLOAD
    //--------------------------------------
    case 2:
        $pdf = new pdf($url);
        $pdf->generate('remove|clean|download', $url_pdf_name, true);
        break;

    //--------------------------------------
    //EXAMPLE: DEFAULT SETTINGS: SAVE
    //--------------------------------------
    case 3:
        $pdf = new pdf($url);
        echo $pdf->generate('clean|save', $url_pdf_name, true);
        break;

    //--------------------------------------
    //EXAMPLE: SETTING SIZE: A0
    //--------------------------------------
    case 4:
        $pdf = new pdf($url);
        $pdf->size(pdf::A0)->generate('remove|clean|embed', $url_pdf_name, true);
        break;

    //--------------------------------------
    //EXAMPLE: TABLE OF CONTENTS
    //--------------------------------------
    case 5:
        $pdf = new pdf($url);
        $pdf->toc(true)->generate('remove|clean|embed', $url_pdf_name, true);
        break;

    //--------------------------------------
    //EXAMPLE: GRAYSCALE
    //--------------------------------------
    case 6:
        $pdf = new pdf($url);
        $pdf->color(false)->generate('remove|clean|embed', $url_pdf_name, true);
        break;

    //--------------------------------------
    //EXAMPLE: ORIENTATION: LANDSCAPE
    //--------------------------------------
    case 7:
        $pdf = new pdf($url);
        $pdf->orient('Landscape')->generate('remove|clean|embed', $url_pdf_name, true);
        break;

    //--------------------------------------
    //EXAMPLE: AUTHENTICATION: BASIC HTTP AUTH
    //--------------------------------------
    case 8:
        $pdf = new pdf($url);
        $pdf->authenticate('username', 'password')->generate('remove|clean|embed', $url_pdf_name, true);
        break;

    //--------------------------------------
    //EXAMPLE: HEADERS: SETTING A CUSTOM HEADER
    //--------------------------------------
    case 9:
        $pdf = new pdf($url);
        $pdf->header('key', 'value')->generate('remove|clean|embed', $url_pdf_name, true);
        break;

    //--------------------------------------
    //EXAMPLE: COOKIES: SETTING A CUSTOM COOKIE
    //--------------------------------------
    case 10:
        $pdf = new pdf($url);
        $pdf->cookie('key', 'value')->generate('remove|clean|embed', $url_pdf_name, true);
        break;

    //--------------------------------------
    //EXAMPLE: FORMS: ENABLE FORMS CONVERSION
    //--------------------------------------
    case 11:
        $pdf = new pdf($html);
        $pdf->forms(true)->generate('remove|clean|embed', $html_pdf_name, true);
        break;

    //--------------------------------------
    //EXAMPLE: HEADERS AND FOOTERS: ENABLE DEFAULT HEADER
    //there are a crap load more header and footer settings, look in the code and it should be obvious!
    //--------------------------------------
    case 12:
        $pdf = new pdf($url);
        $pdf->heading('default', true)->generate('remove|clean|embed', $url_pdf_name, true);
        break;

    //--------------------------------------
    //EXAMPLE: HEADERS AND FOOTERS: SET THE LEFT FOOTER CONTENT, AND A CUSTOM REPLACE FOR IT
    //there are a crap load more header and footer settings, look in the code and it should be obvious!
    //--------------------------------------
    case 13:
        $pdf = new pdf($url);
        $pdf->heading('left', 'Page [page] of [topage] by [myuser]')->replace('myuser', 'My Users Name')->generate('remove|clean|embed', $url_pdf_name, true);
        break;

    //--------------------------------------
    //EXAMPLE: HEADERS AND FOOTERS: SET THE LEFT AND RIGHT FOOTER CONTENT, USING MULTIPLE CALLS
    //there are a crap load more header and footer settings, look in the code and it should be obvious!
    //--------------------------------------
    case 14:
        $pdf = new pdf($url);
        $pdf->heading('left', 'Page [page] of [topage]')->heading('right', '[time]')->generate('remove|clean|embed', $url_pdf_name, true);
        break;

    //--------------------------------------
    //EXAMPLE: HEADERS AND FOOTERS: SET THE LEFT AND RIGHT FOOTER CONTENT, USING ARRAY
    //there are a crap load more header and footer settings, look in the code and it should be obvious!
    //--------------------------------------
    case 15:
        $heading = array(
            'left' => 'Page [page] of [topage]',
            'right' => '[time]'
        );
        $pdf = new pdf($url);
        $pdf->heading($heading)->generate('remove|clean|embed', $url_pdf_name, true);
        break;


    //--------------------------------------
    //EXAMPLE: DISABLE JAVASCRIPT
    //--------------------------------------
    case 16:
        $pdf = new pdf($url);
        $pdf->javascript(false)->generate('remove|clean|embed', $url_pdf_name, true);
        break;

    //--------------------------------------
    //EXAMPLE: SETTING ZOOM
    //--------------------------------------
    case 17:
        $pdf = new pdf($url);
        $pdf->zoom(5)->generate('remove|clean|embed', $url_pdf_name, true);
        break;

}

Ответы [ 2 ]

1 голос
/ 24 июня 2011

Это зависит от версии, которая у вас есть, но для запуска некоторых старых версий wkhtmltopdf требуется подключение к X-серверу (т. Е. Вам пришлось запускать его в графической среде, даже если он не создавал никаких окон).

Более поздние версии исправили это, но все еще требуют присутствия X (поэтому, если вы запускаете его на другом компьютере только для сервера, это все еще может быть проблемой).

В качестве первого шага проверьте версию, которую вы получили от apt, и, если она старая, установите новую версию вручную.

1 голос
/ 24 июня 2011

Попробуйте это:

с консоли

whereis wkhtmltopdf

Он сообщит вам абсолютный путь к программе (например, / usr / bin / wkhtmltopdf)
А чем попробовать из PHP

/usr/bin/wkhtmltopdf 'http://stackoverflow.com' "/tmp/Stack Overflow.pdf" --orientation Portrait --page-size A1 --zoom 1

И если это не работает, добавьте это в ваш скрипт

error_reporting(E_ALL);
ini_set('display_errors', 1);

А постите сюда какие ошибки PHP пишут

Я пытаюсь установить и запустить на своем компьютере:

root:/home/azat# aptitude install wkhtmltopdf

root:/home/azat/Desktop# php 1.php
No protocol specified
wkhtmltopdf: cannot connect to X server :0

И от пользователя, у которого есть разрешения и переменные для X-сервера:

azat:~/Desktop$ php 1.php 
Loading page (1/2)
Printing pages (2/2)                                               
Done
...