DomDocument inserting CSS from file in style element - php

I am building a system where the requirement says no links to CSS are allowed. They do allow to place all CSS content within the style element.
I am using DOMDocument to build the XML/XHTML.
The CSS stylesheets are around 320 lines so I would pefer to construct them in separate CSS files and solve the insertion of the CSS content in the DomDocument build.
Question:
What is the best way of inserting an external CSS file content
and get it in place between the DOMDocument built style element?
Index.php
<?php
$xml = new DomDocument('1.0', 'UTF-8');
$xml->formatOutput = true;
$html = $xml->createElement('html');
$xml->appendChild($html);
$head = $xml->createElement('head');
$html->appendChild($head);
//
$style = $xml->createElement(
'style',
'css-content....' // The CSS content from external file should be inserted here.
);
$style->setAttribute('type', 'text/css');
$head->appendChild($style);
echo $xml->saveXML();
Main.css
body {
background-color: pink;
}
Wanted result
<?xml version="1.0" encoding="UTF-8"?>
<html>
<head>
<style type="text/css">
body {
background-color: pink;
}
</style>
</head>
</html>

Try something along these lines:
Add
$css = file_get_contents('main.css');
and change $style to:
$style = $xml->createElement('style', $css);
and it should work.

Related

php getimagesize with persian file name

I'm trying to write an Joomla plugin to add width and height tag to each <img> in HTML file.
Some image file names are Persian, and getimagesize faces error.
The code is this:
#$dom->loadHTML('<?xml version="1.0" encoding="UTF-8"?>' . "\n" . '
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<img src="images\banners\س.jpg" style="max-width: 90%;" >
</body>
</html>
');
$x = new DOMXPath($dom);
foreach($x->query("//img") as $node)
{
$imgtag = $node->getAttribute("src");
$imgtag = pathinfo($imgtag);
$imgtag = $imgtag['dirname'].'\\'.$imgtag['basename'];
$imgtag = getimagesize($imgtag);
$node->setAttribute("width",$imgtag[0]);
$node->setAttribute("height",$imgtag[1]);
}
$newHtml = urldecode($dom->saveHtml($dom->documentElement));
And when Persian characters exist in file name, getimagesize shows:
Warning: getimagesize(images\banners\س.jpg): failed to open stream: No such file or directory in C:\wamp64\www\plugin.php
How can I solve this?
Thanks to all,
I couldn't reach to results on WAMP server (local server on Windows),
but when I migrated to Linux server, finally this code worked properly.
$html = $app->getBody();
setlocale(LC_ALL, '');
$dom = new DOMDocument();
#$dom->loadHTML($html);
$x = new DOMXPath($dom);
foreach($x->query("//img") as $node)
{
$imgtag = $node->getAttribute("src");
if(strpos($imgtag,"data:image")===false)
{
$imgtag = getimagesize($imgtag);
$node->setAttribute("width",$imgtag[0]);
$node->setAttribute("height",$imgtag[1]);
}
}
$bodytag = $x->query("//body");
$node = $dom->createElement("script", ' /* java script which may be necessary on client */ ');
$bodytag[0]->appendChild($node);
$html = '<!DOCTYPE html>'."\n" . $dom->saveHtml($dom->documentElement);
Some hints:
the code, shouldn't touch base64 image sources, so I added an condition to the code.
if some script (or whatever, div, p, ....) should be added to body tag, you can use appendChild method.
<!DOCTYPE html> should be added to final DOM object output :)

PHP DOM return as html

I have an xml file slider.xml with html code inside:
<?xml version="1.0" encoding="UTF-8"?>
<content>
<title>Slider</title>
<head>
<script async="async" src='ws-custom/plugins/slider.js'></script>
<script async="defer" src='ws-custom/plugins/functions.js'></script>
</head>
<footer>
<script async="defer" src='ws-custom/plugins/jquery.js'></script>
</footer>
</content>
In PHP I would like to:
1. load it (using simplexml, dom or other better solution) and store in a variable $xml;
2. create an array $head with both $xml->head->children();
3. return the original html code for $head[0] and $head[1].
I have tried using this code:
$xml = simplexml_load_file('slider.xml');
$head = $xml->head->children();
foreach($head as $element){
echo $element->asXML();
}
but it returns self-closing tags:
<script async="async" src="ws-custom/plugins/slider.js"/>
<script async="defer" src="ws-custom/plugins/functions.js"/>
which is not valid html code for W3C http://validator.w3.org/nu/
I would like also to be able to write only async, i.e.
because it's valid html, but with simplexml it's not valid xml.
Thank you very much.
Best regards.
I've edited the script, now it works perfectly.
Note please the row 6:
$element[] = null;
<?php
$xml = new DOMDocument();
$xml = simplexml_load_file('slider.xml');
$head = $xml->head->children();
foreach($head as $element){
$element[] = null;
echo $element->asXML().PHP_EOL;
}
SimpleXML can't output the empty tags properly, you should use DOMDocument instead (LIBXML_NOEMPTYTAG doesn't work in SimpleXML)...
$xml = new DOMDocument('1.0');
$xml->load("slider.xml");
$head = $xml->getElementsByTagName("head");
$headScripts= $head[0]->getElementsByTagName("script");
foreach($headScripts as $element){
echo $xml->saveXML($element, LIBXML_NOEMPTYTAG).PHP_EOL;
}
This code gets a start point (the <head> tag), as you only want the first one it uses [0] and finds the <script> tags inside the start point.
Which with the test source gives...
<script async="async" src="ws-custom/plugins/slider.js"></script>
<script async="defer" src="ws-custom/plugins/functions.js"></script>

CSS is not working for my proxy request

I'm trying to create a proxy request to a different domain from my own and doing some changes on the code before outputting the HTML to be displayed. And all works well except that my CSS file doesn't seem to take effect.
<?php
if (isset($_GET['$url']))
{
$html = file_get_contents($_GET['url']);
$dom = new DOMDocument();
#$dom->loadHTML($html);
$a = array();
foreach ($dom->getElementsByTagName('link') as $href)
{
$a[] = $href->getAttribute('href');
}
echo str_replace($a[0],$url."/".$a[0], $html);
}
?>
The result is an HTML document but without CSS styling. But if I check the source code in my browser it shows that the link to the CSS file is okay and clicking on it takes me to that CSS file, but its not taking effect in styling the output

Set Custom Page Title for HTML2PDF created pdf

I am using HTML2PDF library of PHP to create PDF from HTML. My page url is as below ::
http://domain.com/admin/invoice/invoicedownload
To create pdf using below code ::
ob_start();
$width_in_mm = 240;
$height_in_mm = 250;
$html2pdf = new HTML2PDF('P', array($width_in_mm,$height_in_mm), en, true, 'UTF-8', array(15, 10, 15, 10));
$html2pdf->setDefaultFont('Arial');
$html2pdf->pdf->SetTitle('Invoice Details');
$html2pdf->writeHTML($pdf_template);
$html2pdf->Output($file_name,'I');
die();
This code open pdf view in browser new tab.
Issue I am facing is that that new tab title is set as "Invoice Details - invoicedownload" but I want it as "Invoice Details". Always url's last part is append in title.
Please help me for this.
Thank you in advance.
In order to define your own tab title, you can use the 'embed' html tag.
File n°1 (main):
html, body, embed
{
width: 100%;
height: 100%;
}
body
{
margin: 0;
padding: 0;
}
<!DOCTYPE html>
<html>
<head>
<title>Your title</title>
</head>
<body>
<embed src=/path-to-your-pdf type='application/pdf'/>
</body>
</html>
File n°2 (/path-to-your-pdf):
<?php
$html2pdf = new Html2Pdf('P, 'A4', 'en');
$html2pdf->writeHTML($pdf_template);
$html2pdf->output();
Hope this helps ;)

Extract all the used styles from a CSS file in a HTML document using PHP

I want extract all the used styles from a CSS file in a HTML document.
If there is a HTML like:
<div class="blue"></div>
And a CSS file like:
.blue {
background-color: #2196F3 !important; }
.red {
background-color: #F44336 !important; }
The PHP Code should produce an output as:
.blue {
background-color: #2196F3 !important; }
The purpose is bring to CSS styles to the HTML document to prevent a render-blocking CSS.
I think it's needed a HTML and CSS parser.
Just a rough idea,
supposed my html file is like:
<body class="container">
<div class="row bg-red">
<div class="col-md-12">
</div>
</div>
</body>
Use regex to get string in the class in .html file like:
<.... class="....." >|/>
Substring and split by space
Store it, in multi-dimensional array, (to prepare to store class nesting like: [0] = container, [0][0] = row, [0][0][0] = col-md-12, [0][1] = bg-red)
Read .css file and all <style>
Start read multi-dimensional array, like
Check for array [0] = container, then search css, <style> for .container
Check for array [0][0] = row, then search for .row
Check for array [0] [0][0] = .container .row
Check for array [0][0][0] = col-md-12, then search for .col-md-12
Check for array [0] [0][0] [0][0][0] = .container .row .col-md-12
If found, check it match for all 'dot' in css.
ex. '.container' = match
ex. '.container .row' = match
ex. '#main .container' = match
ex. '.container .row .detail' = not match
ex. '.container > .row' = match
Note: it just a very rough idea, you need to think more to handle the css that require continue such as .container > .row
2021 updated: There are much better tools to perform this task, for example: https://github.com/FullHuman/purgecss
I achieved my exact result, I think this is going to help many people that want to optimize their website as suggested by Google Pagespeed Insights.
Dependencies: https://github.com/paquettg/php-html-parser
https://github.com/sabberworm/PHP-CSS-Parser
use PHPHtmlParser\Dom;
ob_start();
?><!doctype html>
<html>
<head>
.....
</body>
</html><?PHP
$html = ob_get_contents();
ob_end_clean();
$md5 = md5($html);
//add to HTML in style labels the CSS Used and minimized the result
$dom = new Dom;
$dom->load($html);
$style = '';
foreach($css_files as $css_file){
$md5CSS = md5_file($css_file);
$cssContent = file_get_contents($css_file);
$oSettings = Sabberworm\CSS\Settings::create()->withMultibyteSupport(false)/*->beStrict()*/;
$oCssParser = new Sabberworm\CSS\Parser($cssContent, $oSettings);
$cssParsed = $oCssParser->parse();
$memcached->set($md5CSS, $cssParsed);
}
foreach ($cssParsed->getContents() as $oItem) {
if ($oItem instanceof Sabberworm\CSS\CSSList\KeyFrame)
continue;
if ($oItem instanceof Sabberworm\CSS\RuleSet\AtRuleSet)
continue;
if($oItem instanceof Sabberworm\CSS\RuleSet\DeclarationBlock){
$oBlock = $oItem;
$selectors = array();
foreach($oBlock->getSelectors() as $oSelector)
$selectors[] = $oSelector->getSelector();
if(count($dom->find(implode(",",$selectors))) > 0)
$style .= $oBlock->render(Sabberworm\CSS\OutputFormat::createCompact());
}
if ($oItem instanceof Sabberworm\CSS\CSSList\AtRuleBlockList) {
foreach($oItem->getContents() as $oBlock) {
$selectors = array();
foreach($oBlock->getSelectors() as $oSelector)
$selectors[] = $oSelector->getSelector();
if(count($dom->find(implode(",",$selectors))) > 0){
$style .= $oItem->render(Sabberworm\CSS\OutputFormat::createCompact());
break;
}
}
}
}
}
$styleLabel = '<style type="text/css">'.$style.'</style>';
$html = str_replace("</head>", $styleLabel."\n</head>",$html);

Categories