I'm creating a web app where I want to include JavaScript files with all file sources in an array, but I can't do that.
Header.php
<head>
<?php
$import_scripts = array(
'file01.js',
'file02.js'
);
foreach ($import_scripts as $script) {
echo '<script src="' . $script . '"></script>';
}
?>
</head>
<body>
Index.php
<?php
include('header.php');
array_push($import_scripts,'file03.js')
?>
But this only includes file01.js and file02.js, JavaScript files.
Your issue is that you've already echo'ed the scripts in headers.php by the time you push the new value into the array in index.php. So you need to add to extra scripts before you include headers.php. Here's one way to do it (using the null coalescing operator to prevent errors when $extra_scripts is not set):
header.php
<?php
$import_scripts = array_merge(array(
'file01.js',
'file02.js'
), $extra_scripts ?? []);
?>
<!DOCTYPE html>
<html>
<head>
<!-- Scripts Section -->
<?php
foreach ($import_scripts as $script) {
echo '<script src="' . $script . '"></script>' . PHP_EOL;
}
?><title>Demo</title>
</head>
<body>
<p>Blog</p>
index.php
<?php
$extra_scripts = ['file03.js'];
include 'header.php';
?>
Output (demo on 3v4l.org)
<!DOCTYPE html>
<html>
<head>
<!-- Scripts Section -->
<script src="file01.js"></script>
<script src="file02.js"></script>
<script src="file03.js"></script>
<title>Demo</title>
</head>
<body>
<p>Blog</p>
header.php
<?php
function scripts()
{
return [
'file01.js',
'file02.js'
];
}
function render($scripts)
{
foreach ($scripts as $script) {
echo '<script src="' . $script . '"></script>';
}
}
?>
<head>
index.php:
<?php
include 'header.php';
$extra_scripts = scripts();
$extra_scripts[] = 'script3.js';
render($extra_scripts);
?>
</head>
<body>
PHP is processed top down so it will currently be adding file03.js to the array after the foreach has been run.
This means you have two options:
Run the scripts after the header (Not reccomended)
Like Nick suggested, in index.php, specify additional scripts before the header is called
Other answers have answered why (you output content before adding the item to the array).
The best solution is to do all your processing before your output. Also helps with error trapping, error reporting, debugging, access control, redirect control, handling posts... as well as changes like this.
Solution 1: Use a template engine.
This may be more complex than you need, and/or add bloat. I use Twig, have used Smarty (but their site is now filled with Casino ads, so that's a concern), or others built into frameworks. Google "PHP Template engine" for examples.
Solution 2: Create yourself a quick class that does the output. Here's a rough, (untested - you will need to debug it and expand it) example.
class Page
{
private string $title = 'PageTitle';
private array $importScripts = [];
private string $bodyContent = '';
public setTitle(string $title): void
{
$this->title = $title;
}
public addImportScript(string $importScript): void
{
$this->importScripts[] = $importScript;
}
public addContent(string $htmlSafeBodyContent): void
{
$this->bodyContent .= $bodyContent;
}
public out(): void
{
echo '<!DOCTYPE html>
<html>
<head>
<!-- Scripts Section -->
';
foreach ($this->importScripts as $script) {
echo '<script src="' . htmlspecialchars($script) . '"></script>' . PHP_EOL;
}
echo '
<!-- End Scripts Section -->
<title>' . htmlspecialchars($this->title) . '</title>
</head>
<body> . $this->bodyContent . '
</body>
</html>';
exit();
}
}
// Usage
$page = new page();
$page->setTitle('My Page Title'); // Optional
$page->addImportScript('script1');
$page->addImportScript('script2');
$page->addContent('<h1>Welcome</h1>');
// Do your processing here
$page->addContent('<div>Here are the results</div>');
$page->addImportScript('script3');
// Output
$page->out();
I'd create a new php file, say functions.php and add the following code into it.
<?php
// script common for all pages.
$pageScripts = [
'common_1.js',
'common_2.js',
];
function addScripts(array $scripts = []) {
global $pageScripts;
if (!empty ($scripts)) { // if there are new scripts to be added, add it to the array.
$pageScripts = array_merge($pageScripts, $scripts);
}
return;
}
function jsScripts() {
global $pageScripts;
$scriptPath = './scripts/'; // assume all scripts are saved in the `scripts` directory.
foreach ($pageScripts as $script) {
// to make sure correct path is used
if (stripos($script, $scriptPath) !== 0) {
$script = $scriptPath . ltrim($script, '/');
}
echo '<script src="' . $script .'" type="text/javascript">' . PHP_EOL;
}
return;
}
Then change your header.php as
<?php
include_once './functions.php';
// REST of your `header.php`
// insert your script files where you needed.
jsScripts();
// REST of your `header.php`
Now, you can use this in different pages like
E.g. page_1.php
<?php
include_once './functions.php';
addScripts([
'page_1_custom.js',
'page_1_custom_2.js',
]);
// include the header
include_once('./header.php');
page_2.php
<?php
include_once './functions.php';
addScripts([
'./scripts/page_2_custom.js',
'./scripts/page_2_custom_2.js',
]);
// include the header
include_once('./header.php');
You are adding 'file03.js' to $import_scripts after including 'header.php', so echoing scripts it have been done yet. That's why 'file03.js' is not invoked.
So, you need to add 'file03.js' to $import_scripts before echoing scripts, this means before include 'header.php'.
A nice way is to move $import_scripts definition to index.php, and add 'file03.js' before including 'header.php'.
But it seems that you want to invoke certain JS scripts always, and add some more in some pages. In this case, a good idea is to define $import_scripts in a PHP file we can call init.php.
This solution will be as shown:
header.php
<head>
<?php
foreach ($import_scripts as $script) {
echo '<script src="' . $script . '"></script>';
}
?>
</head>
<body>
init.php
<?php
$import_scripts = array(
'file01.js',
'file02.js'
);
index.php
<?php
require 'init.php';
array_push($import_scripts,'file03.js');
include 'header.php';
header.php
<?php
echo "<head>";
$importScripts = ['file01.js','file02.js'];
foreach ($importScripts as $script) {
echo '<script src="' . $script . '"></script>';
}
echo "</head>";
echo "<body>";
index.php
<?php
include 'header.php';
array_push($importScripts, 'file03.js');
print_r($importScripts);
Output
Array ( [0] => file01.js [1] => file02.js [2] => file03.js )
Related
I am trying to include file in string replace but in output i am getting string not the final output.
analytic.php
<?php echo "<title> Hello world </title>"; ?>
head.php
<?php include "analytic.php"; ?>
index.php
string = " <head> </head>";
$headin = file_get_contents('head.php');
$head = str_replace("<head>", "<head>". $headin, $head);
echo $head;
Output i am getting :
<head><?php include "analytic.php"; ?> </head>
Output i need :
<head><title> Hello world </title> </head>
Note : Please do not recommend using analytic.php directly in index.php because head.php have some important code and it has to be merged analytic.php with head.php and then index.php
To get the desired output :
function getEvaluatedContent($include_files) {
$content = file_get_contents($include_files);
ob_start();
eval("?>$content");
$evaluatedContent = ob_get_contents();
ob_end_clean();
return $evaluatedContent;
}
$headin = getEvaluatedContent('head.php');
string = " <head> </head>";
$head = str_replace("<head>", "<head>". $headin, $head);
echo $head;
Output will be output string not file string :
<head><title> Hello world </title> </head>
I think your approach is pretty basic (you try to hardcore modify - programmerly edit - the template script, right?) but anyway:
$file = file('absolut/path/to/file.php');
foreach ($file as $line => $code) {
if (str_contains($code, '<head>')) {
$file[$line] = str_replace('<head>', '<head>' . $headin, $code);
break;
}
}
file_put_contents('absolut/path/to/file.php', $file);
I am using these codes so that I can pass the file needed or other attribute through variables but it is not working properly. I don't know what the problem is because the code looks pretty fine to me. Index page does not show any content from header's page.
helper.php
<?php
function render($template, $data = array())
{
$path = $template . ' .$php ';
if(file_exists($path))
{
extract($data);
require($path);
}
}
header.php
<?php require_once('helper.php') ?>
<!doctype html>
<head>
<title><?php echo htmlspecialchars($title); ?></title>
</head>
<body>
Index.php
<?php
require_once('helper.php');
render('header', array('title' => 'Index'));
?>
This is wrong:
$path = $template . ' .$php ';
You are adding spaces and a $ sign to your path:
$path = $template . '.php';
I believe you must want this line
$path = $template . ' .$php ';
to actually be this:
$path = $template . '.php';
Run into a bit of a sticky situation which I can't seem to wrap my finger around. Basically what I am trying to achieve is having the ability to inject different Javascript files on different page.
Some simple, random example:
Page 1: import jquery.js
Page 2: import mootools.js
So what I have done is, I've created a function called addScript() like so:
function addScript($file) {
$script = '';
$script .= '<script src="'. REL_PATH . '/path/to/file/' . $file . '">';
$script .= '</script>';
return $script;
}
so if I call addScript('jquery.min'); it, outputs correctly.
What I now want to do is replace the closing </head> tag with the output from the above function. If I do the following then it works fine:
ob_start();
require_once("models/header.php");
$contents = ob_get_contents();
ob_end_clean();
echo str_replace('</head>', addScript('jquery.js') . '</head>', $contents);
However I would like this to be a little more dynamic as there may be multiple script that I need to inject on each page like so:
addScript('script.js');
addScript('script2.js');
addScript('script3.js');
I then thought of creating a getHead() function with a foreach loop inside and returning str_replace there instead but this did not work.
Can anyone guide my in the direction to dynamically inject as many script as required and output the last bit of the head?
Why not do something like this:
class Assets {
private static $css = array();
private static $js = array();
static function add_style($path) {
self::$css[] = $path;
}
static function add_script($path) {
self::$js[] = $path;
}
static function get_styles() {
$output = '';
foreach(self::$css as $path) {
$ouput .= '<link rel="stylesheet" href="'. $path .'" />' . "\n";
}
return $ouput;
}
static function get_scripts() {
$output = '';
foreach(self::$js as $path) {
$ouput .= '<script type="text/javascript" src="'. $path .'"></script>' . "\n";
}
return $ouput;
}
}
Then anywhere in your project:
Assets::add_style('path/to/style.css');
Assets::add_script('path/to/jquery.js');
And in header.php:
<head>
<!-- other header stuff -->
<?php echo Assets::get_styles(); ?>
<?php echo Assets::get_scripts(); ?>
</head>
Is much more convenient, and you can can extend the class to do more fancy stuff.
Disclaimer: there is much debate about using static vars, as they look like globals. I agree, but this is quick-and-dirty and works no matter what kind of framework you use. You can also make the variables oldschool instance vars, but then you'll have to pass the assets object to the header.php as well.
What's wrong with the following??
echo str_replace('</head>',
addScript('jquery.js').
addScript('jquer1.js').
addScript('jquer2.js').
addScript('jquer3.js').
'</head>', $contents);
How about you put the ob_start(); in header.php. Then your function is:
function addScript($file) {
$script = '<script src="'. REL_PATH . '/path/to/file/' . $file . '"></script>';
echo str_replace('</head>', addScript('jquery.js') . '</head>', ob_get_clean());
}
Then:
addScript('script.js');
This method keeps the output buffer going and you can manipulate it later in the script whenever you want. just as you do with the addScript().
My menu system all comes from the index file. A simplified example:
#index.php
...
<div id="container">
include($inc_file) //index.php?site=news will show news.php
</div>
...
My question is: how can I only include some js-files and css-files when they are needed. For example, I have a file with a slider. I would like only to include the js/css-files related to the slider when visiting that page.
I know that I can make if/else clauses, but I find that a bit ineffective. Is it possible to place a session containing an array with all the files that should be included on the frontpage?
Here is what I would use:
<?php
$path_parts = pathinfo(__FILE__);
$filename = $path_parts['filename'];
if ($filename === "somepage") {
?>
<script src=""></script>
<link ...>
<?php } ?>
I would just have a preset array for each page with an array of css/js files it would need to include.
eg.
settings.php
<?php
$pages = array();
$pages['index'] = array(
"css" => array("main.css","index.css"),
"js" => array("jquery.min.js","someotherjs.js")
);
$pages["about"] = array(
...
);
index.php
<?php
include('settings.php');
?>
...
<head>
<?php
foreach($pages['index']['css'] as $css)
echo "<link rel='stylesheet' type='text/css' href='$css'>";
?>
...
<?php
foreach($pages['index']['js'] as $js)
echo "<script src='$js'></script>";
</body>
</head>
This may not be the answer you were expecting but did you know that the browser does not download css or js files that have not changed since the last time they were downloaded. They are cached on the client PC and only refreshed if the copy on the server has changed.
Theerfore you may not need to be so selective about what you load on each page as it probably wont cause a fresh download of a css or js file.
Prepare an object where you can add style or js files as you need, here a little example.
class head {
private styles = array();
private scripts = array();
public function __construct() {}
// add script in page
public function add_script(filepath){
array_push($this->scripts, filepath);
}
// add style in page
public function add_style(filepath){
array_push($this->styles, filepath);
}
// get html <link> for styles
public function get_styles(){
$html = '';
$len = count($this->styles);
for($i=0; $i < $len; $i++){
$html .='<link rel="stylesheet" type="text/css" href="'.$this->styles[$i].'">';
}
return $html;
}
// get html <script> for scripts
public function get_scripts(){
$html = '';
$len = count($this->scripts);
for($i=0; $i < $len; $i++){
$html .='<script type="text/javascript" src="'.$this->scripts[$i].'"></script>';
}
return $html;
}
}
// destruct ...
in your controller :
require('/class/head.php');
$head = new head();
$head->add_style('/css/myStyle.css');
$head->add_script('/js/myScript.js');
in head
<?php echo $head->get_styles(); ?>
<?php echo $head->get_scripts(); ?>
I am using PHP and CodeIgniter. In every view file, I include the header.php, seen below:
<head>
<link rel="...">
<script type="text/javascript">...</script>
</head>
Notice that the head tag is closed in this file. Now I want to add a <script> tag in another file without modifying header.php. C# has ContentPlaceHolder that can be used to indicate where tags can be added within head tag. Is there any equivalent in php? If not, How can I achieve this?
You can easily add other scripts in your header by adding a single variable in your controller like this:
Controller:
$data['myScript'] = '<link rel="..."><script type="text/javascript">...</script>';
$this->load->view('myView',$data);
Then in your header.php add:
<head>
<link rel="...">
<script type="text/javascript">...</script>
<?php if (isset($myScript)) echo $myScript; ?>
</head>
This makes a very customizeable template for each view because you can add the scripts only in the views you need them.
Here's what I usually do with any CodeIgniter project...
I extend the HTML helper (application/helpers/MY_html_helper.php) to include a js() function:
function js($js)
{
$js_base_path = '';
// If you have multiple JS files, pass an array
if(is_array($js))
{
foreach($js as $script_src)
{
if(strpos($script_src, 'http://') === false && strpos($script_src, 'https://') === false)
{
$js_base_path = base_url() . 'js/';
}
echo '<script src="' . $js_base_path . $script_src . '"></script>';
}
}
// Otherwise, a string will do
else
{
if(strpos($js, 'http://') === false && strpos($js, 'https://') === false)
{
$js_base_path = base_url() . 'js/';
}
echo '<script src="' . $js_base_path . $js . '"></script>';
}
}
In my controller, I'll include my footer (header, in your case) with a js parameter:
$this->load->view('_footer', array('js'=>'jquery.cycle.lite.js'));
My _footer view runs the js() function like this:
<?php
if(isset($js))
{
$this->load->helper('html');
js($js);
}
?>
This has worked great for me, feel free to customize it to your needs.
Phil Sturgeon's template library has some handy functionalities for this:
http://philsturgeon.co.uk/demos/codeigniter-template/user_guide/library.html#prepend_metadata