Local PhantomJS PDF Generation

I noticed that Invoice Ninja now supports local PDF generation with PhantomJS, but the link in email settings to point to the installation guide just goes to the overall install guide.

What’s the procedure for making the app use PhantomJS instead of PhantomJSCloud?

Thanks!

You need to add the following line to your .env file

PHANTOMJS_BIN_PATH=/path/to/phantomjs

More info here: http://docs.invoiceninja.com/en/latest/configure.html#phantomjs

That did the trick. Thanks!

Was searching for the solution. Thanks Hillel.

Hi.

I have Windows server.

I downloaded phantomjs-2.1.1-windows.zip
I extracted PhantomJS to c:\PhantomJs\bin\phantomjs.exe
I added the line to .env: PHANTOMJS_BIN_PATH=c:\PhantomJs\bin\
In Email settings I checked: Attach Invoice (Using local PhantomJS)

Still I get email without an attached PDF.

What am I doing wrong?

Thank you

Br,
Dali

Please check storage/logs/laravel-error.log for details.

Thank oyu for reply Hillel.

I extracted PhantomJS to c:\PhantomJs\bin\phantomjs.exe

It will fail no matter what I set as path:

PHANTOMJS_BIN_PATH=c:\PhantomJs\bin
PHANTOMJS_BIN_PATH=c:\PhantomJs\bin
PHANTOMJS_BIN_PATH=\PhantomJs\bin
PHANTOMJS_BIN_PATH=\PhantomJs\bin
PHANTOMJS_BIN_PATH=PhantomJs\bin
PHANTOMJS_BIN_PATH=PhantomJs\bin
PHANTOMJS_BIN_PATH=c:/PhantomJs/bin/
PHANTOMJS_BIN_PATH=c:/PhantomJs/bin
PHANTOMJS_BIN_PATH=/PhantomJs/bin/
PHANTOMJS_BIN_PATH=/PhantomJs/bin
PHANTOMJS_BIN_PATH=PhantomJs/bin/
PHANTOMJS_BIN_PATH=PhantomJs/bin

[2017-03-08 11:13:44] production.ERROR: PhantomJS - Failed to create pdf: File does not exist or is not executable: /PhantomJs/phantomjs.exe {“context”:“PHP”,“user_id”:1,“account_id”:1,“user_name”:“Dali Sternisa”,“method”:“PUT”,“url”:“http://invoice.dbstudio.si/invoices/237",“user_agent”:"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36”,“ip”:“93.103.102.10”,“count”:16} []

Thank you!

Br,
Dali

Try this…

PHANTOMJS_BIN_PATH=C:\PhantomJs\bin\phantomjs.exe

As per: https://github.com/jonnnnyw/php-phantomjs/issues/123#issuecomment-249964831

Thank you for reply.

Yes it did solve the LOG error, but I still does not attach the PDF in email sent to the client… No Log entries.

Br,
Dali

Can you check if setting APP_DEBUG to true fixes it.

Also, try adding \Log::info($response->getContent()); here to see the response from the server.

https://github.com/invoiceninja/invoiceninja/blob/master/app/Libraries/CurlUtils.php#L60

The response should appear in storage/logs/laravel-info.log

Yes, with APP_DEBUG=true it works great. The moment I set it to false it stop attaching the PDF.

I can not have APP_DEBUG=true turned on the clients portal.

Any solution?

Thank you

Br,
Dali

Try adding isLazy and setTimeout as seen here https://github.com/jonnnnyw/php-phantomjs/issues/85#issuecomment-226611806 in CurlUtils::phantom()

Thank you

I was checking the link but still don’t know where exactly to put those lines.

Thank you

Br,
Dali

$client = Client::getInstance(); $client->isLazy(); $client->getEngine()->setPath($path);
    $request = $client->getMessageFactory()->createRequest($url, $method);
    $request->setTimeout(5000);        
    $response = $client->getMessageFactory()->createResponse();

Ahh, it’s the CurlUtils.php file. That was I missing :slight_smile:

It works now. However it takes about 10 sec to send the email. It feels like the system hangs for a while, as there is no PDF generating note pr a progress bar, but that’s not a big problem.

By the way what will happen when I update Invoice Ninja. Will I need to modify CurlUtils.php again?

Thank you
Br,
Dali

One way to speed it up is to enable queues:

http://docs.invoiceninja.com/en/latest/configure.html#email-queues

We’ll look into fixing this in our next release.

Thank you Hillel!!!

QUEUE_DRIVER=database speeds up, but mail doesn’t get send. No log errors.

QUEUE_DRIVER=redis

[2017-03-08 19:47:36] production.ERROR: exception ‘Predis\Connection\ConnectionException’ with message ‘No connection could be made because the target machine actively refused it. [tcp://127.0.0.1:6379]’ in C:\www\globevoices.com\payments\vendor\predis\predis\src\Connection\AbstractConnection.php:155 Stack trace: #0 C:\www\globevoices.com\payments\vendor\predis\predis\src\Connection\StreamConnection.php(128): Predis\Connection\AbstractConnection->onConnectionError(‘No connection c…’, 10061) #1 C:\www\globevoices.com\payments\vendor\predis\predis\src\Connection\StreamConnection.php(178): Predis\Connection\StreamConnection->createStreamSocket(Object(Predis\Connection\Parameters), ‘tcp://127.0.0.1…’, 4) #2 C:\www\globevoices.com\payments\vendor\predis\predis\src\Connection\StreamConnection.php(100): Predis\Connection\StreamConnection->tcpStreamInitializer(Object(Predis\Connection\Parameters)) #3 C:\www\globevoices.com\payments\vendor\predis\predis\src\Connection\AbstractConnection.php(81): Predis\Connection\StreamConnection->createResource() #4 C:\www\globevoices.com\payments\vendor\predis\predis\src\Connection\StreamConnection.php(258): Predis\Connection\AbstractConnection->connect() #5 C:\www\globevoices.com\payments\vendor\predis\predis\src\Connection\AbstractConnection.php(180): Predis\Connection\StreamConnection->connect() #6 C:\www\globevoices.com\payments\vendor\predis\predis\src\Connection\StreamConnection.php(288): Predis\Connection\AbstractConnection->getResource() #7 C:\www\globevoices.com\payments\vendor\predis\predis\src\Connection\StreamConnection.php(394): Predis\Connection\StreamConnection->write(’*3\r\n$5\r\nRPUSH\r\n…’) #8 C:\www\globevoices.com\payments\vendor\predis\predis\src\Connection\AbstractConnection.php(110): Predis\Connection\StreamConnection->writeRequest(Object(Predis\Command\ListPushTail)) #9 C:\www\globevoices.com\payments\vendor\predis\predis\src\Client.php(331): Predis\Connection\AbstractConnection->executeCommand(Object(Predis\Command\ListPushTail)) #10 C:\www\globevoices.com\payments\vendor\predis\predis\src\Client.php(315): Predis\Client->executeCommand(Object(Predis\Command\ListPushTail)) #11 C:\www\globevoices.com\payments\vendor\laravel\framework\src\Illuminate\Queue\RedisQueue.php(79): Predis\Client->__call(‘rpush’, Array) #12 C:\www\globevoices.com\payments\vendor\laravel\framework\src\Illuminate\Queue\RedisQueue.php(79): Predis\Client->rpush(‘queues:default’, ‘{“job”:"Illumin…’) #13 C:\www\globevoices.com\payments\vendor\laravel\framework\src\Illuminate\Queue\RedisQueue.php(66): Illuminate\Queue\RedisQueue->pushRaw(’{“job”:"Illumin…’, NULL) #14 C:\www\globevoices.com\payments\bootstrap\cache\compiled.php(9963): Illuminate\Queue\RedisQueue->push(Object(App\Jobs\SendInvoiceEmail)) #15 C:\www\globevoices.com\payments\bootstrap\cache\compiled.php(9949): Illuminate\Bus\Dispatcher->pushCommandToQueue(Object(Illuminate\Queue\RedisQueue), Object(App\Jobs\SendInvoiceEmail)) #16 C:\www\globevoices.com\payments\bootstrap\cache\compiled.php(9924): Illuminate\Bus\Dispatcher->dispatchToQueue(Object(App\Jobs\SendInvoiceEmail)) #17 C:\www\globevoices.com\payments\bootstrap\cache\compiled.php(5726): Illuminate\Bus\Dispatcher->dispatch(Object(App\Jobs\SendInvoiceEmail)) #18 C:\www\globevoices.com\payments\app\Http\Controllers\InvoiceController.php(404): App\Http\Controllers\BaseController->dispatch(Object(App\Jobs\SendInvoiceEmail)) #19 C:\www\globevoices.com\payments\app\Http\Controllers\InvoiceController.php(376): App\Http\Controllers\InvoiceController->emailInvoice(Object(App\Models\Invoice)) #20 [internal function]: App\Http\Controllers\InvoiceController->update(Object(App\Http\Requests\UpdateInvoiceRequest), ‘237’) #21 C:\www\globevoices.com\payments\bootstrap\cache\compiled.php(9482): call_user_func_array(Array, Array) #22 C:\www\globevoices.com\payments\bootstrap\cache\compiled.php(9544): Illuminate\Routing\Controller->callAction(‘update’, Array) #23 C:\www\globevoices.com\payments\bootstrap\cache\compiled.php(9524): Illuminate\Routing\ControllerDispatcher->call(Object(App\Http\Controllers\InvoiceController), Object(Illuminate\Routing\Route), ‘update’) #24 [internal function]: Illuminate\Routing\ControllerDispatcher->Illuminate\Routing{closure}(Object(Illuminate\Http\Request)) #25 C:\www\globevoices.com\payments\vendor\laravel\framework\src\Illuminate\Routing\Pipeline.php(52): call_user_func(Object(Closure), Object(Illuminate\Http\Request)) #26 [internal function]: Illuminate\Routing\Pipeline->Illuminate\Routing{closure}(Object(Illuminate\Http\Request)) #27 C:\www\globevoices.com\payments\bootstrap\cache\compiled.php(10006): call_user_func(Object(Closure), Object(Illuminate\Http\Request)) #28 C:\www\globevoices.com\payments\bootstrap\cache\compiled.php(9525): Illuminate\Pipeline\Pipeline->then(Object(Closure)) #29 C:\www\globevoices.com\payments\bootstrap\cache\compiled.php(9512): Illuminate\Routing\ControllerDispatcher->callWithinStack(Object(App\Http\Controllers\InvoiceController), Object(Illuminate\Routing\Route), Object(Illuminate\Http\Request), ‘update’) #30 C:\www\globevoices.com\payments\bootstrap\cache\compiled.php(8582): Illuminate\Routing\ControllerDispatcher->dispatch(Object(Illuminate\Routing\Route), Object(Illuminate\Http\Request), ‘App\Http\Contro…’, ‘update’) #31 C:\www\globevoices.com\payments\bootstrap\cache\compiled.php(8569): Illuminate\Routing\Route->runController(Object(Illuminate\Http\Request)) #32 C:\www\globevoices.com\payments\bootstrap\cache\compiled.php(8283): Illuminate\Routing\Route->run(Object(Illuminate\Http\Request)) #33 [internal function]: Illuminate\Routing\Router->Illuminate\Routing{closure}(Object(Illuminate\Http\Request)) #34 C:\www\globevoices.com\payments\vendor\laravel\framework\src\Illuminate\Routing\Pipeline.php(52): call_user_func(Object(Closure), Object(Illuminate\Http\Request)) #35 C:\www\globevoices.com\payments\app\Http\Middleware\Authenticate.php(101): Illuminate\Routing\Pipeline->Illuminate\Routing{closure}(Object(Illuminate\Http\Request)) #36 [internal function]: App\Http\Middleware\Authenticate->handle(Object(Illuminate\Http\Request), Object(Closure), ‘user’) #37 C:\www\globevoices.com\payments\bootstrap\cache\compiled.php(10021): call_user_func_array(Array, Array) #38 [internal function]: Illuminate\Pipeline\Pipeline->Illuminate\Pipeline{closure}(Object(Illuminate\Http\Request)) #39 C:\www\globevoices.com\payments\vendor\laravel\framework\src\Illuminate\Routing\Pipeline.php(32): call_user_func(Object(Closure), Object(Illuminate\Http\Request)) #40 [internal function]: Illuminate\Routing\Pipeline->Illuminate\Routing{closure}(Object(Illuminate\Http\Request)) #41 C:\www\globevoices.com\payments\bootstrap\cache\compiled.php(10006): call_user_func(Object(Closure), Object(Illuminate\Http\Request)) #42 C:\www\globevoices.com\payments\bootstrap\cache\compiled.php(8284): Illuminate\Pipeline\Pipeline->then(Object(Closure)) #43 C:\www\globevoices.com\payments\bootstrap\cache\compiled.php(8275): Illuminate\Routing\Router->runRouteWithinStack(Object(Illuminate\Routing\Route), Object(Illuminate\Http\Request)) #44 C:\www\globevoices.com\payments\bootstrap\cache\compiled.php(8265): Illuminate\Routing\Router->dispatchToRoute(Object(Illuminate\Http\Request)) #45 C:\www\globevoices.com\payments\bootstrap\cache\compiled.php(2419): Illuminate\Routing\Router->dispatch(Object(Illuminate\Http\Request)) #46 [internal function]: Illuminate\Foundation\Http\Kernel->Illuminate\Foundation\Http{closure}(Object(Illuminate\Http\Request)) #47 C:\www\globevoices.com\payments\vendor\laravel\framework\src\Illuminate\Routing\Pipeline.php(52): call_user_func(Object(Closure), Object(Illuminate\Http\Request)) #48 C:\www\globevoices.com\payments\app\Http\Middleware\StartupCheck.php(201): Illuminate\Routing\Pipeline->Illuminate\Routing{closure}(Object(Illuminate\Http\Request)) #49 [internal function]: App\Http\Middleware\StartupCheck->handle(Object(Illuminate\Http\Request), Object(Closure)) #50 C:\www\globevoices.com\payments\bootstrap\cache\compiled.php(10021): call_user_func_array(Array, Array) #51 [internal function]: Illuminate\Pipeline\Pipeline->Illuminate\Pipeline{closure}(Object(Illuminate\Http\Request)) #52 C:\www\globevoices.com\payments\vendor\laravel\framework\src\Illuminate\Routing\Pipeline.php(32): call_user_func(Object(Closure), Object(Illuminate\Http\Request)) #53 C:\www\globevoices.com\payments\app\Http\Middleware\QueryLogging.php(32): Illuminate\Routing\Pipeline->Illuminate\Routing{closure}(Object(Illuminate\Http\Request)) #54 [internal function]: App\Http\Middleware\QueryLogging->handle(Object(Illuminate\Http\Request), Object(Closure)) #55 C:\www\globevoices.com\payments\bootstrap\cache\compiled.php(10021): call_user_func_array(Array, Array) #56 [internal function]: Illuminate\Pipeline\Pipeline->Illuminate\Pipeline{closure}(Object(Illuminate\Http\Request)) #57 C:\www\globevoices.com\payments\vendor\laravel\framework\src\Illuminate\Routing\Pipeline.php(32): call_user_func(Object(Closure), Object(Illuminate\Http\Request)) #58 C:\www\globevoices.com\payments\app\Http\Middleware\DuplicateSubmissionCheck.php(39): Illuminate\Routing\Pipeline->Illuminate\Routing{closure}(Object(Illuminate\Http\Request)) #59 [internal function]: App\Http\Middleware\DuplicateSubmissionCheck->handle(Object(Illuminate\Http\Request), Object(Closure)) #60 C:\www\globevoices.com\payments\bootstrap\cache\compiled.php(10021): call_user_func_array(Array, Array) #61 [internal function]: Illuminate\Pipeline\Pipeline->Illuminate\Pipeline{closure}(Object(Illuminate\Http\Request)) #62 C:\www\globevoices.com\payments\vendor\laravel\framework\src\Illuminate\Routing\Pipeline.php(32): call_user_func(Object(Closure), Object(Illuminate\Http\Request)) #63 C:\www\globevoices.com\payments\bootstrap\cache\compiled.php(3225): Illuminate\Routing\Pipeline->Illuminate\Routing{closure}(Object(Illuminate\Http\Request)) #64 C:\www\globevoices.com\payments\app\Http\Middleware\VerifyCsrfToken.php(44): Illuminate\Foundation\Http\Middleware\VerifyCsrfToken->handle(Object(Illuminate\Http\Request), Object(Closure)) #65 [internal function]: App\Http\Middleware\VerifyCsrfToken->handle(Object(Illuminate\Http\Request), Object(Closure)) #66 C:\www\globevoices.com\payments\bootstrap\cache\compiled.php(10021): call_user_func_array(Array, Array) #67 [internal function]: Illuminate\Pipeline\Pipeline->Illuminate\Pipeline{closure}(Object(Illuminate\Http\Request)) #68 C:\www\globevoices.com\payments\vendor\laravel\framework\src\Illuminate\Routing\Pipeline.php(32): call_user_func(Object(Closure), Object(Illuminate\Http\Request)) #69 C:\www\globevoices.com\payments\bootstrap\cache\compiled.php(13532): Illuminate\Routing\Pipeline->Illuminate\Routing{closure}(Object(Illuminate\Http\Request)) #70 [internal function]: Illuminate\View\Middleware\ShareErrorsFromSession->handle(Object(Illuminate\Http\Request), Object(Closure)) #71 C:\www\globevoices.com\payments\bootstrap\cache\compiled.php(10021): call_user_func_array(Array, Array) #72 [internal function]: Illuminate\Pipeline\Pipeline->Illuminate\Pipeline{closure}(Object(Illuminate\Http\Request)) #73 C:\www\globevoices.com\payments\vendor\laravel\framework\src\Illuminate\Routing\Pipeline.php(32): call_user_func(Object(Closure), Object(Illuminate\Http\Request)) #74 C:\www\globevoices.com\payments\bootstrap\cache\compiled.php(12022): Illuminate\Routing\Pipeline->Illuminate\Routing{closure}(Object(Illuminate\Http\Request)) #75 [internal function]: Illuminate\Session\Middleware\StartSession->handle(Object(Illuminate\Http\Request), Object(Closure)) #76 C:\www\globevoices.com\payments\bootstrap\cache\compiled.php(10021): call_user_func_array(Array, Array) #77 [internal function]: Illuminate\Pipeline\Pipeline->Illuminate\Pipeline{closure}(Object(Illuminate\Http\Request)) #78 C:\www\globevoices.com\payments\vendor\laravel\framework\src\Illuminate\Routing\Pipeline.php(32): call_user_func(Object(Closure), Object(Illuminate\Http\Request)) #79 C:\www\globevoices.com\payments\bootstrap\cache\compiled.php(13271): Illuminate\Routing\Pipeline->Illuminate\Routing{closure}(Object(Illuminate\Http\Request)) #80 [internal function]: Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse->handle(Object(Illuminate\Http\Request), Object(Closure)) #81 C:\www\globevoices.com\payments\bootstrap\cache\compiled.php(10021): call_user_func_array(Array, Array) #82 [internal function]: Illuminate\Pipeline\Pipeline->Illuminate\Pipeline{closure}(Object(Illuminate\Http\Request)) #83 C:\www\globevoices.com\payments\vendor\laravel\framework\src\Illuminate\Routing\Pipeline.php(32): call_user_func(Object(Closure), Object(Illuminate\Http\Request)) #84 C:\www\globevoices.com\payments\bootstrap\cache\compiled.php(13208): Illuminate\Routing\Pipeline->Illuminate\Routing{closure}(Object(Illuminate\Http\Request)) #85 [internal function]: Illuminate\Cookie\Middleware\EncryptCookies->handle(Object(Illuminate\Http\Request), Object(Closure)) #86 C:\www\globevoices.com\payments\bootstrap\cache\compiled.php(10021): call_user_func_array(Array, Array) #87 [internal function]: Illuminate\Pipeline\Pipeline->Illuminate\Pipeline{closure}(Object(Illuminate\Http\Request)) #88 C:\www\globevoices.com\payments\vendor\laravel\framework\src\Illuminate\Routing\Pipeline.php(32): call_user_func(Object(Closure), Object(Illuminate\Http\Request)) #89 C:\www\globevoices.com\payments\bootstrap\cache\compiled.php(3286): Illuminate\Routing\Pipeline->Illuminate\Routing{closure}(Object(Illuminate\Http\Request)) #90 [internal function]: Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode->handle(Object(Illuminate\Http\Request), Object(Closure)) #91 C:\www\globevoices.com\payments\bootstrap\cache\compiled.php(10021): call_user_func_array(Array, Array) #92 [internal function]: Illuminate\Pipeline\Pipeline->Illuminate\Pipeline{closure}(Object(Illuminate\Http\Request)) #93 C:\www\globevoices.com\payments\vendor\laravel\framework\src\Illuminate\Routing\Pipeline.php(32): call_user_func(Object(Closure), Object(Illuminate\Http\Request)) #94 [internal function]: Illuminate\Routing\Pipeline->Illuminate\Routing{closure}(Object(Illuminate\Http\Request)) #95 C:\www\globevoices.com\payments\bootstrap\cache\compiled.php(10006): call_user_func(Object(Closure), Object(Illuminate\Http\Request)) #96 C:\www\globevoices.com\payments\bootstrap\cache\compiled.php(2366): Illuminate\Pipeline\Pipeline->then(Object(Closure)) #97 C:\www\globevoices.com\payments\bootstrap\cache\compiled.php(2350): Illuminate\Foundation\Http\Kernel->sendRequestThroughRouter(Object(Illuminate\Http\Request)) #98 C:\www\globevoices.com\payments\public\index.php(52): Illuminate\Foundation\Http\Kernel->handle(Object(Illuminate\Http\Request)) #99 {main} [] []

Using redis would require setting up/configuring the redis server, database is easier to use.

You need to run php artisan queue:listen or php artisan queue:work --daemon to send the emails in the queue.

https://laravel.com/docs/5.2/queues#running-the-queue-listener

Dali - I’m curious as to how you installed Invoice Ninja on windows - this would be great - I don’t supposed you could possibly outline your installation steps?

Well, I just followed the instructions on website. Installation is not OS depended. It works beautifully on Windows 10 pro.

You just need few things on server

Apache or IIS
Mysql
Php
Mcrypt

and a bit of webadmin skills.
http://docs.invoiceninja.com/en/latest/install.html

I hope it helps

Br,
Dali