Add CSS to DomPDF

I've got this code to export some data into a pdf. And I would like to add css from an external css file (which is not mentionned in the html used)

I've got this code to export some data into a pdf. And I would like to add css from an external css file (which is not mentionned in the html used)

/*********************************** Export PDF ****************************************************/
if($request->query->get('exportPDF')!= null){
    // Configure Dompdf according to your needs
    $pdfOptions = new Options();
    $pdfOptions->set('defaultFont', 'Arial');
    // Instantiate Dompdf with our options
    $dompdf = new Dompdf($pdfOptions);
    // Retrieve the HTML generated in our twig file
    $html = $this->renderView('dashboard/user_table.html.twig', [
        'users' => $users
    ]);
    // Load HTML to Dompdf
    $dompdf->loadHtml($html);
    // (Optional) Setup the paper size and orientation 'portrait' or 'portrait'
    $dompdf->setPaper('A3', 'landscape');
    // Render the HTML as PDF
    $dompdf->render();
    // Output the generated PDF to Browser (force download)
    $dompdf->stream("exportUsers.pdf", [
        "Attachment" => true
    ]);
}

The user_table.html is only a file with a <table>

who has some class from a css file loaded in an other template. That means for DomPDF the file who contains the css is unkown and, as a result I have a table with no css in my pdf. I've tried to add the stylesheet in my html directly but the import isn't working like that neither. But I don't want to add it in the html anyway, the css is loaded is a more hight level template.

How to add external files (like bootstrap etc etc) from this structure ? I do not know if this is even possible. Thanks for the help ;)

Nginx Fastcgi Reverse Proxy Cache for PHP (Symfony)

Nginx Fastcgi Reverse Proxy Cache for PHP (Symfony)

Nginx Fastcgi Reverse Proxy Cache for PHP (Symfony) - If you ever faced the case that your PHP app is not performing for the incoming traffic, Nginx can help you.

Originally published by Stefan Pöltl at medium.com

Actually there is a easy caching fix for PHP backends to reduce the load and to serve responses faster that are requested multiple times with the same parameters.

Current application state

In my case I had to fix a legacy API route that generated a JSON based response which took around 400ms. The app is using Memcached to cache serialized objects, but still the response time for an API should be much faster. The code itself was kind of legacy and a fast shot to speed up the application was requested.

Solution

The application lives behind a load balancer and runs on mulitple nodes with the following components:

  • PHP-FPM as PHP Process Manager
  • NGINX as webserver

The simplest solution that came to my mind was to cache the API responses, triggered by a POST request, even if the RFC for HTTP says its not recommended:

Responses to this method are not cacheable, unless the response includes appropriate Cache-Control or Expires header fields. However,the 303 (See Other) response can be used to direct the user agent to retrieve a cacheable resource.
Implementation

The best thing is, you don’t need to touch the application at all, you can just change your nginx configuration file and that’s it. I will show a configuration file you can easily mount into a NGINX Docker container and run it in front of a PHP-FPM container.

docker-compose.yml:
version: '2'
services:
  web:
    image: nginx:latest
    ports:
      - "8080:80"
    volumes:
      - ./:/opt/code
      - ./vhost:/etc/nginx/conf.d/default.conf
    depends_on:
      - fpm
  fpm:
    image: php:7.3-fpm
    volumes:
      - ./:/opt/code
Nginx vhost config:
fastcgi_ignore_headers Cache-Control Expires Set-Cookie;
fastcgi_cache_path /var/cache/nginx levels=1:2 keys_zone=fpmcache:100m max_size=3g inactive=60m use_temp_path=off;
fastcgi_cache_key "$request_uri|$request_body";
fastcgi_cache_methods POST;

server {
server_tokens off;
listen 80 default_server;
server_name server_name _;

access_log   /dev/stdout;
error_log    /dev/stderr;

root /opt/code;

location / {
    try_files $uri /index.php$is_args$args;
}

set $disable_cache 1;
if ($request_uri ~ "^/api") {set $disable_cache 0;}

location ~ [^/]\.php(/|$) {
    fastcgi_cache_bypass $disable_cache;
    fastcgi_no_cache $disable_cache;

    fastcgi_cache fpmcache;
    fastcgi_cache_valid 200 20m;
    fastcgi_cache_min_uses 1;
    fastcgi_cache_lock on;
    add_header X-Cache $upstream_cache_status;

    fastcgi_pass fpm:9000;
    fastcgi_split_path_info ^(.+\.php)(/.*)$;
    fastcgi_read_timeout 35;
    include fastcgi_params;
    fastcgi_param DOCUMENT_ROOT $realpath_root;
    fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
}

}

index.php:

<?php

echo date('Y-m-d H:i:s');

If you spin up the containers with docker-compose up and run the following curl statement multiple times, you should see the same response output for 20 minutes, as configured in the NGINX vhost config.

curl -X POST localhost:8080/api

Cached response output for curl request

As you can see for the /api POST request, we always get the same time exposed from the cache after the first PHP script call was saved on disk in the NGINX container. For all other calls you get the current time forwarded from the backend without caching:

Non cached response output

How did we configure NGINX?
fastcgi_ignore_headers Cache-Control Expires Set-Cookie;

This line is necessary, because Frameworks like Symfony set the Cache-Control: no-cache header by default and the configured caching will be ignored.

fastcgi_cache_path /var/cache/nginx levels=1:2 keys_zone=fpmcache:100m max_size=3g inactive=60m use_temp_path=off;

Here the arguments configure the path to store the cached backend results and set the directory structure/depth. This means the cache folder structure looks like this: /var/cache/nginx/5/dc for the key: 4275fe6d0b92cebe0f8d1461c5fe2dc5

So the directory structure is build like: Last char from the key/next two chars/key

The reason for this is, that nginx has less cache files per folder instead of storing all files in one directory, to speed up the lookup by key.

The file content of the key named file is:

KEY: /api|
VX-Powered-By: PHP/7.3.6
Content-type: text/html; charset=UTF-8

2019–06–13 20:46:28

In general NGINX stores the keys in memory(RAM) with 100MB in our case and keeps a 3GB storage on disk for the cache files. If a key was not fetched for 60 minutes the file gets removed. Further we disable the first write of the generated cached result into a temp folder, for performance reasons.

Next step is to decide which values are used to compute the cache key and which HTTP methods are valid to enable the caching:

fastcgi_cache_key "$request_uri|$request_body";
fastcgi_cache_methods POST;

In the next step, we set a variable that enables the caching only for the /api route and use it in the php location block:

set $disable_cache 1;
if ($request_uri ~ "^/api") {set $disable_cache 0;}
location ~ [^/].php(/|$) {
fastcgi_cache_bypass $disable_cache;
fastcgi_no_cache $disable_cache;
}

Finally we configure which defined cache is used and which HTTP return codes get cached for how long(fastcgi_cache_valid). The fastcgi_min_uses setting caches the result from the backend after the first request was processed. The fastcgi_cache_lock option just lets the first request hitting the backend server, all the others are going to wait until the result is in the cache and fetch it from there. This prevents load on the backend. To debug the current caching status we add the X-Cache header, which says MISS, HIT or EXPIRED.

fastcgi_cache fpmcache;
fastcgi_cache_valid 200 20m;
fastcgi_cache_min_uses 1;
fastcgi_cache_lock on;
add_header X-Cache $upstream_cache_status;

At the end don’t forget to test your hosts configuration with nginx -t and serve your users/clients with a fast API.

Originally published by Stefan Pöltl at medium.com

====================================================================

Thanks for reading :heart: If you liked this post, share it with all of your programming buddies! Follow me on Facebook | Twitter

Learn More

☞ PHP for Beginners - Become a PHP Master - CMS Project

☞ Learn Object Oriented PHP By Building a Complete Website

☞ MEVP Stack Vue JS 2 Course: MySQL + Express.js + Vue.js +PHP

☞ Object Oriented PHP & MVC

☞ PHP OOP: Object Oriented Programming for beginners + Project

☞ Learn PHP Fundamentals From Scratch

☞ The Complete PHP MySQL Professional Course with 5 Projects

☞ The Complete JavaScript Course 2019: Build Real Projects!

Best PHP Frameworks (2019)

In this article, we will be discussing the best PHP Frameworks along with their pros and cons in great depth so that one might get a clear understanding of which one to chose. Our comprehensive research would include some Latest PHP Frameworks.







Basic Introduction of All Frameworks:
In this article, we would be discussing Best PHP Frameworks and before that, we would be having a glimpse of some basic information of all of these PHP Frameworks. One thing common about all of the PHP Frameworks we would be discussing here is that all are Open Source PHP Frameworks. Have a look at some basic facts about these PHP Frameworks:


FrameworkLaravelSymfonyZendCodeIgniterCakePHP
Date of First Commit9-Jun-20114-Jan-201028-Apr-200925-Aug-200616-May-2005
Official Websitehttps://laravel.com/https://symfony.com/https://framework.zend.com/https://codeigniter.com/https://cakephp.org/
Github URLhttps://github.com/laravel/laravelhttps://github.com/symfony/symfonyhttps://github.com/zendframework/zendframeworkhttps://github.com/bcit-ci/CodeIgniterhttps://github.com/cakephp/cakephp
Current Version5.84.233.1.103.7
LicenseMIT licenseMIT licenseNew BSD licenseMIT licenseMIT license

Google Trends [2019]:

As can be seen clearly in the above Google Trends, Laravel is surely racing ahead in the list of best PHP Frameworks in 2019 while Codeigniter is also giving some tough competition here. Also, there is an interesting aspect that Symfony and CakePHP are gaining some traction in the list of top PHP Frameworks.

Suggested Read: Redis vs MySQL Benchmarks


Stack Overflow Trends [2019]:
Stack Overflow: https://tinyurl.com/y23cqb8b

Again, as per the Stack Overflow trends, Laravel is way ahead in the list of Top PHP Frameworks in 2019. Also, Laravel started gaining some serious traction from the 2014-2015 period and since then it is a leading PHP Framework. One interesting point one can note here is that since 2013, Laravel started gaining popularity and other Frameworks saw either downfall or negligible growth.



Github Stars Since First Commit [2019]:
In this world of OpenSource technologies, Github stars since the first commit is the sure shot way of checking the popularity streak of a particular technology and PHP Frameworks are of no exception. So, when discussing the Top PHP Frameworks, one can not ignore the importance of Github Stars. So, here is the list of PHP Frameworks along with their individual data in regard to their Github Stars. 

FrameworkDate of First CommitTotal No of Github Stars
(At the time of writing)
LaravelThursday, 9 June 201152166
SymfonyMonday, 4 January 201020683
ZendTuesday, 28 April 20095698
CodeIgniterFriday, 25 August 200617251
CakePHPMonday, 16 May 20057845

As can be clearly seen from the above table, Laravel Framework, in terms of Github Stars is way ahead in the list of best PHP Frameworks in 2019 while Symfony and CodeIgniter are having the second and third position. One can see here is that Laravel is the youngest of all the above-mentioned frameworks and still has managed to get far more Github stars.

Comparison based on other Parameters:
FrameworkLaravelSymfonyZendCodeIgniterCakePHP
Twitter Followers98.6K34.3K47.8K23K17.4K
Downloads (From Packagist)62.1M+41M+4.9M+0.47M+4.0M+
PHP Version Required5.6.45.6.05.65.3.75.6
Speed(Rest API)5.5 ms2.2 ms (Fastest)3.9 msUnknown5.8 ms (Slowest)

These are some other helpful parameters and benchmarks which completes our comparison of Top 10 Best PHP Frameworks for Web Developers in 2019.

Disclaimer: All the above parameters/comparisons/benchmarks are true at the time of writing this blog post, exact numbers may vary depending on the instant and point in time you are reading this blog/post.

Recommended Articles:
If your learning appetite is still left, you are suggested to read below articles: