How do I compress HTML in laravel 5 - php

In Laravel 4.0, I use the code below to compress the HTML laravel response outputs to browser, however it doesn't work in laravel 5.
App::after(function($request, $response)
{
if($response instanceof Illuminate\Http\Response)
{
$buffer = $response->getContent();
if(strpos($buffer,'<pre>') !== false)
{
$replace = array(
'/<!--[^\[](.*?)[^\]]-->/s' => '',
"/<\?php/" => '<?php ',
"/\r/" => '',
"/>\n</" => '><',
"/>\s+\n</" => '><',
"/>\n\s+</" => '><',
);
}
else
{
$replace = array(
'/<!--[^\[](.*?)[^\]]-->/s' => '',
"/<\?php/" => '<?php ',
"/\n([\S])/" => '$1',
"/\r/" => '',
"/\n/" => '',
"/\t/" => '',
"/ +/" => ' ',
);
}
$buffer = preg_replace(array_keys($replace), array_values($replace), $buffer);
$response->setContent($buffer);
}
});
Please how do i make this work in Laravel 5.
OR
Please provide a better way of compressing HTML in laravel 5 if any.
Thanks in advance.
NB: I don't wish to use any laravel package for compressing html, just need a simple code that does the work without killing performance.

Complete code is this (with custom GZip enabled) :
<?php
namespace App\Http\Middleware;
use Closure;
class OptimizeMiddleware
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$response = $next($request);
$buffer = $response->getContent();
if(strpos($buffer,'<pre>') !== false)
{
$replace = array(
'/<!--[^\[](.*?)[^\]]-->/s' => '',
"/<\?php/" => '<?php ',
"/\r/" => '',
"/>\n</" => '><',
"/>\s+\n</" => '><',
"/>\n\s+</" => '><',
);
}
else
{
$replace = array(
'/<!--[^\[](.*?)[^\]]-->/s' => '',
"/<\?php/" => '<?php ',
"/\n([\S])/" => '$1',
"/\r/" => '',
"/\n/" => '',
"/\t/" => '',
"/ +/" => ' ',
);
}
$buffer = preg_replace(array_keys($replace), array_values($replace), $buffer);
$response->setContent($buffer);
ini_set('zlib.output_compression', 'On'); // If you like to enable GZip, too!
return $response;
}
}
Please check your browser network inspector for Content-Length header before/after implement this code.
enjoy it ... :).. .

It is not very good solution to minify html in middleware as you can spend a lot of CPU time on it and it runs on every request.
Instead it is better to use htmlmin package ( https://github.com/HTMLMin/Laravel-HTMLMin ):
composer require htmlmin/htmlmin
php artisan vendor:publish
Minifying HTML on blade template level and caching it in storage should be much more effective.

The recommended way to do this in Larvel 5 is to rewrite your function as middleware. As stated in the docs:
..this middleware would perform its task after the request is handled by the application:
<?php namespace App\Http\Middleware;
class AfterMiddleware implements Middleware {
public function handle($request, Closure $next)
{
$response = $next($request);
// Perform action
return $response;
}
}

I have created a webpack plugin to solve same purpose.MinifyHtmlWebpackPlugin
Install the plugin with npm:
$ npm install minify-html-webpack-plugin --save-dev
For Laravel Mix Users
Paste below snippets into mix.js file.
const MinifyHtmlWebpackPlugin = require('minify-html-webpack-plugin');
const mix = require('laravel-mix');
mix.webpackConfig({
plugins: [
new MinifyHtmlWebpackPlugin({
src: './storage/framework/views',
ignoreFileNameRegex: /\.(gitignore)$/,
rules: {
collapseWhitespace: true,
removeAttributeQuotes: true,
removeComments: true,
minifyJS: true,
}
})
]
});
It will minify all view files during the Webpack build.

This is almost a copy of Vahid's answer but it fixes two problems.
1) It checks if a response is a BinaryFileResponse as any attempt to modify this type of response will throw an Exception.
2) It retained newline characters as the complete elimination of newlines will lead to bad Javascript code on lines with single-line comment.
For example, the code below
var a; //This is a variable
var b; //This will be commented out
Will become
var a; //This is a variable var b; //This will be commented out
Note: At the time of this answer I couldn't get my hands on a good regex to match single line comments without complications or rather, ignore newlines on only lines with a single-line comment, so I'm hoping for a better fix.
Here's the modified version.
<?php
namespace App\Http\Middleware;
use Closure;
class OptimizeMiddleware {
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$response = $next($request);
if ($response instanceof \Symfony\Component\HttpFoundation\BinaryFileResponse) {
return $response;
} else {
$buffer = $response->getContent();
if (strpos($buffer, '<pre>') !== false) {
$replace = array(
'/<!--[^\[](.*?)[^\]]-->/s' => '',
"/<\?php/" => '<?php ',
"/\r/" => '',
"/>\n</" => '><',
"/>\s+\n</" => '><',
"/>\n\s+</" => '><',
);
} else {
$replace = array(
'/<!--[^\[](.*?)[^\]]-->/s' => '',
"/<\?php/" => '<?php ',
"/\n([\S])/" => '$1',
"/\r/" => '',
"/\n+/" => "\n",
"/\t/" => '',
"/ +/" => ' ',
);
}
$buffer = preg_replace(array_keys($replace), array_values($replace), $buffer);
$response->setContent($buffer);
ini_set('zlib.output_compression', 'On'); //enable GZip, too!
return $response;
}
}
}
Edit
Compressing output for every request using the middleware truly is really a bad idea, I recommend you check out this solution by Jokerius

Just in case you are rendering the view manually:
echo view('example.site')->render(function($view, $content) {
return preg_replace(
['/\>[^\S ]+/s', '/[^\S ]+\</s', '/(\s)+/s'],
['>', '<', '\\1'],
$content
); }
);

This package is much better option in my opinion renatomarinho/laravel-page-speed

I did it with very simple code.
Example: welcome.blade.php
Add the following code to the beginning of the page
<?php ob_start('compress_page');?>
Add the following code to the end of the page:
<?php
ob_end_flush();
function compress_page($buffer) {
$search = array("/>[[:space:]]+/", "/[[:space:]]+</");
$replace = array(">","<");
return preg_replace($search, $replace, $buffer);
}?>
Full page code example:
<?php ob_start('compress_page');?>
<!doctype html>
<html lang="{{ app()->getLocale() }}">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Laravel</title>
<!-- Fonts -->
<link href="https://fonts.googleapis.com/css?family=Raleway:100,600" rel="stylesheet" type="text/css">
<!-- Styles -->
<style>
html, body {
background-color: #fff;
color: #636b6f;
font-family: 'Raleway', sans-serif;
font-weight: 100;
height: 100vh;
margin: 0;
}
.full-height {
height: 100vh;
}
.flex-center {
align-items: center;
display: flex;
justify-content: center;
}
.position-ref {
position: relative;
}
.top-right {
position: absolute;
right: 10px;
top: 18px;
}
.content {
text-align: center;
}
.title {
font-size: 84px;
}
.links > a {
color: #636b6f;
padding: 0 25px;
font-size: 12px;
font-weight: 600;
letter-spacing: .1rem;
text-decoration: none;
text-transform: uppercase;
}
.m-b-md {
margin-bottom: 30px;
}
</style>
</head>
<body>
<div class="flex-center position-ref full-height">
#if (Route::has('login'))
<div class="top-right links">
#auth
Home
#else
Login
Register
#endauth
</div>
#endif
<div class="content">
<div class="title m-b-md">
Laravel
</div>
<div class="links">
Documentation
Laracasts
News
Forge
GitHub
</div>
</div>
</div>
</body>
</html>
<?php
ob_end_flush();
function compress_page($buffer) {
$search = array("/>[[:space:]]+/", "/[[:space:]]+</");
$replace = array(">","<");
return preg_replace($search, $replace, $buffer);
}?>

this is best way.. we don't need to use laravel packeges .Thanks..
<?php
namespace App\Http\Middleware;
use Closure;
class OptimizeMiddleware
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$response = $next($request);
$buffer = $response->getContent();
if(strpos($buffer,'<pre>') !== false)
{
$replace = array(
'/<!--[^\[](.*?)[^\]]-->/s' => '',
"/<\?php/" => '<?php ',
"/\r/" => '',
"/>\n</" => '><',
"/>\s+\n</" => '><',
"/>\n\s+</" => '><',
);
}
else
{
$replace = array(
'/<!--[^\[](.*?)[^\]]-->/s' => '',
"/<\?php/" => '<?php ',
"/\n([\S])/" => '$1',
"/\r/" => '',
"/\n/" => '',
"/\t/" => '',
"/ +/" => ' ',
);
}
$buffer = preg_replace(array_keys($replace), array_values($replace), $buffer);
$response->setContent($buffer);
ini_set('zlib.output_compression', 'On'); // If you like to enable GZip, too!
return $response;
}
}

For easy compression, I build my own laravel module. This module will compress all the final html output before sending to the client (browser).
You can also target multiple environment at a time using .env file.
More details on how to install and configure will be found here

Related

How do disable TCPDF version shown in the browser after PDF generation

When i generate the final PDF the version is being displayed.
Is there any way to hide this information ?
I looked into the package documentation but i could not find anything.
This is information I do not want to share.
I checked if there are any functions but I can't find any.
Here is my code that i use to generate the pdf
$pdf = new \TCPDF('L', PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
$pdf->setPrintHeader(false);
$pdf->setPrintFooter(false);
$pdfParams = $this->handlePageParamsByCoverSize($coverSize);
$fontSize = $this->calculateFontSizeByCoverSize($coverSize);
$scissorsIconPath = $this->fileLocator->locate('scissors.png');
$pdf->SetFont(
'helvetica',
'',
$fontSize
);
$pdf->AddPage('L', $pdfParams['format'], true, true);
$pdf->Image(
$coverPath,
$pdfParams['cover']['x'],
$pdfParams['cover']['y'],
$pdfParams['cover']['w'],
$pdfParams['cover']['h'],
'',
'',
'',
false,
300,
'',
false,
false,
0
);
$pdf->Image(
$scissorsIconPath,
$pdfParams['scissorsIcon']['x'],
$pdfParams['scissorsIcon']['y'],
$pdfParams['scissorsIcon']['w'],
$pdfParams['scissorsIcon']['h'],
'',
'',
'',
false,
300,
'',
false,
false,
0
);
$filePath = '/covers/' .$coverName . '.pdf';
$absFileName = $rootPath . $filePath;
try {
$pdf->Output($absFileName, 'F');
} catch (\Exception $e) {
//Move on
}
if (file_exists($absFileName)) {
$result = [
'absPath' => $absFileName,
'path' => $filePath,
];
} else {
$result = ['path' => 'error'];
}
return $result;
I am using the following package
"tecnickcom/tcpdf": "^6.4"
EDIT: Add code and more informations
TCPDF seems to have to methods that might help you:
$tcpdf->SetCreator('My PDF-Generator tool');
$tcpdf->SetAuthor('Your name');
I haven't tried it by myself. I just had a look at the examples of the TCPDF documentation.
Well, if you use a free lib it's quite normal that you can't change that. It would be the same case with other products.
But if you search with a tool such as ripgrep in the source code, you'll see that this string is defined in include/tcpdf_static.php at line 127 and is called by tcpdf.php at two places:
rg "getTCPDFProducer"
Output:
include\tcpdf_static.php
127: public static function getTCPDFProducer() {
tcpdf.php
9554: $out .= ' /Producer '.$this->_textstring(TCPDF_STATIC::getTCPDFProducer(), $oid);
9649: $xmp .= "\t\t\t".'<pdf:Producer>'.TCPDF_STATIC::_escapeXML(TCPDF_STATIC::getTCPDFProducer()).'</pdf:Producer>'."\n";
So if you really have to hide that, you should find a way to override that method, eventually apply a home-made patch or alter the generated file during or after generation.

Codeigniter email library sending blank emails or html source code

I've never had issues sending emails before through CodeIgniter, but all of a sudden it's an issue on my latest project.
I'm using this mail server tool to send mail on my local-host, which has never given me any issues before, and then the CodeIgniter email library.
I can get one of 2 results: either the email sends, but all the raw HTML source code is displayed, or the email sends and has a subject line, but the entire body is blank.
This is my email_helper.php
<?php defined('BASEPATH') OR exit('No direct script access allowed');
function send_email($to, $subject, $template)
{
$ci = &get_instance();
$ci->load->library('email');
$config = array(
'mailtype' => 'html',
'newline' => '\r\n',
'crlf' => '\r\n'
);
//If I comment out this line, it sends raw HTML, otherwise it sends a blank body.
$ci->email->initialize($config);
$ci->email->from($ci->config->item('from_email_address'), $ci->config->item('from_email_name'));
$ci->email->reply_to($ci->config->item('from_email_address'), $ci->config->item('from_email_name'));
$ci->email->to($to);
$ci->email->subject($subject);
$ci->email->message($ci->load->view('email/' . $template . '_html', $data, TRUE));
$ci->email->send();
}
this is my test_html.php
<!DOCTYPE html>
<html>
<head><title>Test</title></head>
<body>
<div style="max-width: 800px; margin: 0; padding: 30px 0;">
TEST!
</div>
</body>
</html>
And then I'm calling the email helper from my controller with this:
$this->load->helper('email_helper');
send_email($this->input->post('email'), 'Test Subject', 'test');
Hope this will help you :
You r missing $data there in your load view section and also try with $ci->load->library('email', $config); instead of $ci->email->initialize($config);
send_email should be like this :
function send_email($to, $subject, $template)
{
$ci = & get_instance();
$config = array(
'mailtype' => 'html',
'charset' => 'iso-8859-1',
'newline' => '\r\n',
'crlf' => '\r\n'
);
$data = '';
$body = $ci->load->view('email/' . $template . '_html', $data, TRUE);
echo $body; die;
$ci->load->library('email', $config);
$ci->email->set_mailtype("html");
$ci->email->from($ci->config->item('from_email_address'), $ci->config->item('from_email_name'));
$ci->email->reply_to($ci->config->item('from_email_address'), $ci->config->item('from_email_name'));
if ($to)
{
$ci->email->to($to);
$ci->email->subject($subject);
$ci->email->message($body);
if ($ci->email->send())
{
return TRUE;
}
else
{
echo $ci->email->print_debugger();die;
}
}
}
For more : https://www.codeigniter.com/user_guide/libraries/email.html

Wkhtmltopdf conversion

My html to pdf conversion using wkhtmlpdf working fine without the <style> tag
but when I include the style tag it's not working that means not generating the pdf some one help me to solve this issue or let me know how to include my style.css in this format.
The way I handle this is as follows--
<?php
// create some HTML content
$html = '<!DOCTYPE html><html><head>
<style>
body {
margin: 0;
padding: 0;
}
...
</style></head><body>
<!-- Your body content -->
</body></html>';
$options = array(
"no-outline",
"binary" => "/usr/local/bin/wkhtmltopdf",
"margin-top" => ".25in",
"margin-right" => ".25in",
"margin-bottom" => ".55in",
"margin-left" => ".25in",
"zoom" => 1
);
$footer = '<!DOCTYPE html><html><head></head><body>...</body></html>';
$page_options = array('footer-html' => $footer);
$pdf->addPage($html, $page_options);
$pdf->saveAs('MY_PDF_NAME.pdf');
Hope this helps!
Best,
-Rush

Unable to Parse ampersand in PHP string

I am trying to parse the ampersand value in a PHP string. It keeps returning blank values after I run my code and I am sure it is because of the 'ampersand' value in my variable ($area). I tried htmlspecialchars, html_entity_decode but to no avail. Please see code below:
<?php
/** Create HTTP POST */
$accomm = 'ACCOMM';
$state = '';
$city = 'Ballan';
$area = 'Daylesford & Macedon Ranges';
$page = '10';
$seek = '<parameters>
<row><param>SUBURB_OR_CITY</param><value>'. $city .'</value></row>
<row><param>AREA</param><value>'. $area .'</value></row>
</parameters>';
$postdata = http_build_query(
array(
'DistributorKey' => '******',
'CommandName' => 'QueryProducts',
'CommandParameters' => $seek)
);
$opts = array(
'http' => array(
'method' => 'POST',
'header' => 'Content-type: application/x-www-form-urlencoded',
'content' => $postdata)
);
/** Get string output of XML (In URL instance) */
$context = stream_context_create($opts);
$result = file_get_contents('http://national.atdw.com.au/soap/AustralianTourismWebService.asmx/CommandHandler?', false, $context);
?>
Pls how do I fix this
Thanks
XML is not HTML, and vice-versa. You cannot have a bare & in an XML document since it is a special character in XML documents. If you're just defining a static string like this your can replace it with & and move on with your day.
If you need to encode arbitrary strings that may or may not contain & or another XML special char, then you'll need functions like:
function xmlentity_encode($input) {
$match = array('/&/', '/</', '/>/', '/\'/', '/"/');
$replace = array('&', '>', '<', '&apos;', '"');
return preg_replace($match, $replace, $input);
}
function xmlentity_decode($input) {
$match = array('/&/', '/>/', '/</', '/&apos;/', '/"/');
$replace = array('&', '<', '>', '\'', '"');
return preg_replace($match, $replace, $input);
}
echo xmlentity_encode("This is testing & 'stuff\" n <junk>.") . "\n";
echo xmlentity_decode("This is testing & &apos;stuff" n >junk<.");
Output:
This is testing & &apos;stuff" n >junk<.
This is testing & 'stuff" n <junk>.
I'm fairly sure that PHP's XML libs do this for you transparently, [and also respecting the character set] but if you're manually constructing your own XML document then you have to ensure that you're aware of things like this.

Formatting tables generated with PHP/PEAR Structures_DataGrid & HTML_Table

I've been working through some examples in a book using pear for the first time... so far it seems pretty cool, but I'm having a small problem where I need to tweak the formatting of one particular column of the table generated from Structures_DataGrid & HTML_Table - specifically I need it to not wrap the text in a cell at the hyphen - which I think I could do using 'nowrap' and html/css - but so far I'm not seeing how to pass that sort of formatting to just one column in the table...
Any suggestions?
Added source code below:
<?php
// Include the DB access credentials
require 'dbcred.php';
// Include the PEAR Structures_DataGrid class
require 'Structures/DataGrid.php';
// instantiate grid for 10 records per page
$datagrid = new Structures_DataGrid(10);
// Define our Datasource options, in this case PDO MySQL
$options = array('dsn' => "mysql://$user:$password#$db_host/$db_name");
// Define the Query
$sql = "SELECT * FROM contact_info";
// Bind the Query to our Datagrid
$bind = $datagrid->bind($sql, $options);
// Test for Errors
if (PEAR::isError($bind))
{
/*error_log('DataGrid Error: '. $bind->getMessage());
$gridsource = 'Foo';*/
echo $bind -> getMessage();
}
else
{
// Define our Column labels, using a 'column' => 'Label' format
$columns = array(
'title' => 'Title',
'first_name' => 'First Name',
'mid_init' => 'Mid. Init.',
'last_name' => 'Last Name',
'suffix' => 'Suffix',
'street_address' => 'Street Address',
'city' => 'City',
'state_prov' => 'State/Province',
'post_code' => 'Postal Code',
'phone_pri' => 'Phone (Pri)',
'phone_alt' => 'Phone (Alt)',
'email' => 'E-Mail',
);
$datagrid->generateColumns($columns);
// Some more options, for our renderer
$renderer_options = array(
'sortIconASC' => '⇑',
'sortIconDESC' => '⇓',
'headerAttributes' => array('bgcolor' => '#E3E3E3'),
'evenRowAttributes' => array('bgcolor' => '#A6A6A6'),
);
$datagrid->setRendererOptions($renderer_options);
// Add some final attributes to our table
$renderer = $datagrid->getRenderer();
$renderer->setTableAttribute('cellspacing', 0);
$renderer->setTableAttribute('cellpadding', 5);
$renderer->setTableAttribute('border', 1);
// Render the table, be sure to check for errors
$gridbody = $datagrid->getOutput();
if (PEAR::isError($gridbody))
{
error_log('DataGrid render error: ' . $gridbody->getMessage());
$gridbody = '';
}
// Finally, render the pager, again checking for errors
$gridpager = $datagrid->getOutput(DATAGRID_RENDER_PAGER);
if (PEAR::isError($gridpager))
{
error_log('DataGrid render error: ' . $gridpager->getMessage());
$gridpager = '';
}
$gridsource = $gridbody . $gridpager;
}
?>
<!DOCTYPE html public "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>PEAR::Structures_DataGrid</title>
<meta http-equiv="Content-type"
content="text/html; charset=iso-8859-1" />
<style type="text/css">
body {
font-family: Tahoma, Arial, Helvetica, sans-serif;
font-size: 11px;
}
h1 {
font-size: 1.2em;
color: navy
}
th {
white-space: no-wrap;
}
</style>
</head>
<body>
<h1>PEAR::Structures_DataGrid</h1>
<?php echo $gridsource ?>
</body>
</html>
Don't know what pear is but:
You can format columns like this in html:
<table>
<col style="background: green;" />
<col />
<tr>
<td>First TD of first TR</td>
<td>Second TD of first TR</td>
</tr>
<tr>
<td>First TD of second TR</td>
<td>Second TD of second TR</td>
</tr>
</table>
That makes the background of the first column green.

Categories