i was wondering if this setup would work. i have to crank out a batch of PDF from a bunch of variables i'm pushing into the $_SESSION via a form (duh...). the idea is to pass the template file to the dompdf engine and have the template populate from the $_SESSION then out to PDF. it seems to me that when the $template gets loaded it should do that, yes?
here's the basic code:
<?php
function renderToPDF($theTemplate = "template.php") // this is just to show the value
{
require_once("dompdf/dompdf_config.inc.php");
$content = file_get_contents($theTemplate);
if ($content !== false)
{
$dompdf = new DOMPDF();
$dompdf->load_html($content);
$dompdf->render();
$dompdf->stream("kapow_ItWorks.pdf");
}
}
?>
and this is the template.php file (basically... you don't want all 16 pages...)
<html>
<meta>
<head>
<link href="thisPage.css" type="text/css" rel="stylesheet">
</head>
<body>
<h1><?php echo $_SESSION['someTitle'] ?></h1>
<h2>wouldn't it be nice, <?php echo $_SESSION['someName'] ?></h2>
</body>
</html>
so my thinking is that the template.php will pull the variables right out of the $_SESSION array without any intervention, looking like this:
BIG TITLE
wouldn't it be nice, HandsomeLulu?
i guess the nut of the question is: Do $_SESSION variables get evaluated when PHP files are loaded, but not rendered?
WR!
file_get_contents does not evaluate the PHP file, it simply gets its contents (the file as it is in the hard drive).
To do what you want, you need to use output buffering and include.
ob_start(); // Start Output beffering
include $theTemplate; // include the file and evaluate it : all the code outside of <?php ?> is like doing an `echo`
$content = ob_get_clean(); // retrieve what was outputted and close the OB
for some reason, the code ON the page that calls the function ALSO gets dumped into the file. this was placed before the header. i understand now why: i wasn't referencing an external page, i was importing and external page. don't know why that didn't click.
anyway. as soon as i got rid of the page's extra stuff, it worked just fine. in retrospect, what dompdf needed to state was quite simply that NO HTML of ANY kind (echo, print, &c.) can be on the page that calls the function. at least that what it appears to require at this level of my knowledge.
for those who, like me, are floundering in a misma of 'everything but the answer', here's the bare bones code that did the job:
buildPDF.php:
<?php
session_start();
$_SESSION['someTitle'] = "BIG FAT TITLE";
$_SESSION['someName'] = "HandomeLu";
$theTemplate = 'template.php';
function renderToPDF($templateFile)
{
require_once("_dox/dompdf/dompdf_config.inc.php");
ob_start();
include $templateFile;
$contents = ob_get_clean();
if ($contents !== false)
{
$dompdf = new DOMPDF();
$dompdf->load_html($contents);
$dompdf->render();
$dompdf->stream("kapow_ItWorks.pdf");
}
}
renderToPDF($theTemplate);
?>
and this is the template.php:
<!DOCTYPE HTML>
<html>
<meta>
<head>
<meta charset="utf-8">
<link href="thisPage.css" type="text/css" rel="stylesheet">
</head>
<body>
<h1><?php echo $_SESSION['someTitle'] ?></h1>
<p>wouldn't it be nice, <?php echo $_SESSION['someName'] ?></p>
</body>
</html>
also note that the external CSS file reads in just fine. so you can still keep the structure and style separate. also, the $_SESSION variables can be set anywhere, obviously, i just set them here to keep testing easy.
hope this is useful for those getting started with this GREAT class. if you're looking to get up and running cranking out PDF files, this kicks so much butt, it should have a trigger and a grip on it. :)
thanks to everyone who commented. you got me in the place i needed to be. :)
this site ROCKS.
WR!
Related
I am using R Shiny to develop a web page and also include my own R code.
I am using p5.js(https://p5js.org/) to display a game in the web page.
As in the official web page says I have an HTML and the p5 javascript code together with the javascript library. If I run the HTML, that is, clicking right and pressing chrome to display I get the started example (https://p5js.org/get-started/) with no incidence.
Here it is the HTML code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<!--<meta name="viewport" content="width=device-width, initial-scale=1">-->
<script language="javascript" type="text/javascript" src="libraries/p5.js"> </script>
<script language="javascript" type="text/javascript" src="sketch.js"></script>
<!-- this line removes any default padding and style. you might only need one of these values set. -->
<style> body {padding: 0; margin: 0;} </style>
</head>
<body>
</body>
</html>
When I do the same in Shiny, running the code from R-Studio I do not get anything from it. I have stored the javascript files in the www folder as it is supposed to be and I currently know that my HTML called the javascript since I set an alert in the p5 javascript file, but outside the setup and draw methods. The problem is that, even though the alert is loaded, seems like the setup and draw methods are not called and, obviously, as a consequence, they do not load the canvas. I know that they are not called because I have a called to an alert in the setup method that works running the HTML file directly but not if I run the same file from R-Studio.
Here it is the p5 javascript code:
alert("GOOD1");
function setup() {
alert("GOOD2");
createCanvas(640, 480);
}
function draw() {
if (mouseIsPressed) {fill(0);}
else {fill(255);}
ellipse(mouseX, mouseY, 80, 80);
}
I load the HTML page in Shiny using the next line of code
... ,tabItem(tabName = "tabProcessing", htmlOutput("processingMasterThesis") ...
Attach to the tag "processingMasterThesis" I have the corresponding URL to the HTML file in the server.R, as it is supposed to be so the problem is not here.
Why may be the cause of this? It works if I call the HTML file directly to be load in the browser but not if I do it from R-Studio, why?
I have solved the problem. The p5 java script code will be:
// =====================
// "app/sketch.js"
// =====================
var myCanvas;
function setup() {
var idCanvas = 'divCanvas';
myCanvas = createCanvas(300, 300);
myCanvas.parent(idCanvas);
}
function draw() {
if (mouseIsPressed) {
fill(0);
} else {
fill(255);
}
ellipse(mouseX, mouseY, 80, 80);
}
The library you need to run the example can be found at https://p5js.org/
In this javascript file I have created an id that reference a html div element so that is the place where I will set my canvas. Once this is done, the rest of the javascript code will code perfectly. The point is to reference that the parent of the canvas is that div as you can see in the code.
After this you just have to create either in shiny or pure html code something like this:
# THE UI (File ui.R)
library(shiny)
library(shinydashboard)
library(rmarkdown)
shinyUI(
fluidRow(
# THE UI
tags$html(
tags$body(
singleton(tags$head(tags$script(src = "master_thesis/app/libraries/p5.js")))
,singleton(tags$head(tags$script(src = "master_thesis/app/sketch.js")))
,singleton(tags$div(id = 'divCanvas', style = 'width:auto; height:auto'))
))
)
)
The code that I show below is in shiny. The first "head" line include the library p5.js and the second "head" line just say "hey this is my p5 script file" and "divCanvas will be the div that I will print on".
You may have issues with the references to the javascript file. I think is worthy to note that you must create a www folder in your root shiny application. In this folder, you must put your javascript files. For example, as you can see in my code the two javascript files that I am using follow the next path:
ShinyApplication/www/app/libraries/p5.js
ShinyApplication/www/app/sketch.js
Hope this can help!
I have been searching for this all over, but can not find an answer or example.
Can a Ractive template be used to construct head elements that are consistant across pages, and can that be loaded from a separate file?
For example: all html, head, and title tag info is loaded via a referencable template from an external file into an index page.
+html+
+head+
+title+
+/title+
+/head+
And if so, how do you do it? As I try to wrap my head around it, jquery and ractive.js would need to load. Is there a different/better solution?
It is possible. But it's not practical and it raises other issues.
Here's a basic implementation that shows how <head> can be templated but without concentrating on putting the template in an external file. This works for me in Chrome and IE.
<html>
<head id="output"></head>
<script id="template" type="text/html">
<title>{{ title }}</title>
</script>
<script type="text/javascript" src="ractive.min.js"></script>
<script type="text/javascript">
var ractive = new Ractive({
template: "#template",
el: "#output",
data: {
title: "This is the title"
}
});
</script>
<body>
...
</body>
</html>
You'll run into problems with this approach because the head elements won't be loaded until after the page has loaded and Ractive kicks in. This may cause the following problems:
Search engines might not be able to read the page title and meta tags
Any javascript you need to load into <head> may not work (I tried some simple examples and was able to get the javascript to run but it failed to reference any elements in the body. Maybe it's a context issue and maybe Ractive has support to overcome this but this is an area I'm unfamiliar with.)
If you require valid HTML, this probably won't work for you because script tags can't be direct children of <html>, and <head> is supposed to have <title> as a direct child.
You're better off using a server-side solution to template <head>.
I am using gulp-file-include to build my html pages using some partials & templates. By using context variables, I can customize each meta headers. However, don't know how I could include a line only if a context variable exists, as the "##else" statement doesn't seem to exist.
My parent HTML looks like:
##include ('_header.html', {
"title":"my page",
"description": "description",
"canonical":"http://www.sourcefromquote.com" })
<body>
A wonderful Page
##include ('_footer.html")
</body></html>
I was thinking to use a _header.html close to something like that :
<html>
<head>
<title>##title</title>
<meta name="description" content="##description">
##if (canonical) { <link rel="canonical" href="##canonical" /> }
</head>
If the "canonical" variable is not set in the the parent HTML, it throws an error (canonical is not defined).
I guess I could include the full tag in a variable and forget about the ##if, but that would not be as clean as expected !
Any ideas ?
Thank you in advance.
In the head, you enter:
##if (context.canonical) {<link rel="canonical" href="##canonical" />}
In the file that includes the header you enter:
##include('_head.html', {
"canonical" : "https://www.website.com/canonical-link.html"
})
I am attempting to create a template using Smarty for php. I would like the template to be reusable so I inheriting it and substituting values using blocks. This works fine except when I need to access these block values in sub-templates. I am calling these sub-templates using smarty's {include} function.
Example:
Template-Parent (template.tpl):
<html>
<head>
{include file=sub_template.tpl}
</head>
<body>
{block name=title}No Title Provided{/block}
</body>
</html>
Sub-Template (sub_template.tpl)
<title>{block name=title}No Title Provided{/block}</title>
Template-Child (template_child.tpl)
{extends file="template.tpl"}
{block name=title}My Website!{/block}
When I view the site, the output is:
<html>
<head>
<title>No Title Provided</title>
</head>
<body>
My Website!
</body>
</html>
After doing some reaserch I did see a note on smarty's website about enclosing {include} functions in dummy {block} tags but have had varied levels of success getting this to work.
Note:
If you have a subtemplate which is included with {include} and it
contains {block} areas it works only if the {include} itself is
called from within a surrounding {block}. In the final parent
template you may need a dummy {block} for it.(http://www.smarty.net/docs/en/advanced.features.template.inheritance.tpl)
Due to this, I have tried:
<html>
<head>
{block name=dummy}{include file=sub_template.tpl}{/block}
</head>
<body>
{block name=title}No Title Provided{/block}
</body>
</html>
This seems to work until I make any change to sub-template. As soon as a change to the sub-template is made, it once again stops responding to the block values set in the child.
Have I misunderstood what the notice was referring to about placing the {include} in dummy block tags or is this a bug with smarty? I am not currently using caching but my other thought was that maybe this is a sub-template caching problem.
Any insight would be greatly appreciated, thanks!
It is true that these templates are compiled and cached into the templates directory. This is why clearing the templates directory temporarily fixed the issue. The template caching is different than the explicit caching that smarty also supports. I have found that the template caching can be overridden with:
$smarty->compile_check = true;
$smarty->force_compile = true;
This allows changes to the template to be made with out needing to delete the cache after change while in development.
The rules would be:
Delete all lines except the last line which contains: link and href=
Replace the contents of whatever is after: href= and before: .css with: hello-world
Must maintain no quotes, single quotes or double quotes around the file name
A few examples:
This is a source file with quotes:
<link rel="stylesheet" href="css/reset.css">
<link rel="stylesheet" href="css/master.css">
This is the new source file:
<link rel="stylesheet" href="hello-world.css">
This is a source file without quotes:
<link rel=stylesheet href=css/reset.css>
<link rel=stylesheet href=css/master.css>
This is the new source file:
<link rel=stylesheet href=hello-world.css>
It does not need to maintain the path of the file name. It however cannot use <> brackets or spaces to determine what needs to be edited because the template language which is writing that line might not use brackets or spaces. The only thing that would remain consistent is href=[filename].css.
My bash/sed/regex skills are awful but those tools seem like they will probably get the job done in a decent way? How would I go about doing this?
EDIT
To clarify, the end result would leave everything above and below the lines that contain link and href= alone. Imagine that the source file was an html file or any other template file like so:
<html>
<head>
<title>Hello</title>
<link rel="stylesheet" href="css/reset.css">
<link rel="stylesheet" href="css/master.css">
</head>
<body><p>...</p></body>
</html>
It would be changed to:
<html>
<head>
<title>Hello</title>
<link rel="stylesheet" href="css/hello-world.css">
</head>
<body><p>...</p></body>
</html>
The path of the CSS files might be anything too.
../foo/bar.css
http://www.hello.com/static/css/hi.css
/yep.css
ok.css
The new file's path would be supplied as an argument of the bash script so the regex should remove the path.
Following a discussion in chat, one solution using PHP as a command line script would look like this -
#! /usr/bin/php
<?php
$options = getopt("f:r:");
$inputFile = $options['f'];
$replacement = $options['r'];
// read entire contents of input file
$inputFileContents = file_get_contents($inputFile);
// setup the regex and execute the search
$pattern = '/.*link.*href=["|\']?(.*[\\\|\/]?.*)\.css["|\']?.*/';
preg_match_all($pattern, $inputFileContents, $matches);
// remove last occurance of regex
// these are the lines we'll want to hang onto
$matchedLines = $matches[0];
array_pop($matchedLines);
// isolate the last css file name
$matchedFileName = array_pop($matches[1]);
// first substitution replaces all lines with <link> with
// an empty string (deletes them)
$inputFileContents = str_replace($matchedLines,'',$inputFileContents);
// second substitution replaces the matched file name
// with the desired string
$inputFileContents = str_replace($matchedFileName,$replacement,$inputFileContents);
//*/
// save to new file for debugging
$outputFileName = "output.html";
$outputFile = fopen($outputFileName,'w+');
fwrite($outputFile,$inputFileContents);
fclose($outputFile);
/*/
// save changes to original file
$origFile = fopen($inputFile,'w+');
fwrite($origFile,$inputFileContents);
fclose($origFile);
//*/
exit();
?>
You would execute this script from the command line like so -
$ php thisScript.php -f "input.html" -r "hello-world"
-f is the input file that we are parsing.
-r is the replacement string for the css file name (in this example "hello-world").
Answer specifically, for this case:
If you include same css file twice, it does not create any harm as far as seen by the user.
So you may just replace both css/reset.css AND css/master.css by css/hello-world.css.
There may be better ways, but I found this a quick way. It will work specifically for this case & not if you want to replace <script> or other tags.
Try including the first part of the file before the css and then include the rest of the file below the css, and in the middle, echo the correct css lines