Write into csv in php (class php) - php

I'm using php class to write data to CSV. Link to class: http://www.jongales.com/blog/2009/09/24/php-class-to-write-csv-files/
Class code:
<?php
/**
* Simple class to properly output CSV data to clients. PHP 5 has a built
* in method to do the same for writing to files (fputcsv()), but many times
* going right to the client is beneficial.
*
* #author Jon Gales
*/
class CSV_Writer {
public $data = array();
public $deliminator;
/**
* Loads data and optionally a deliminator. Data is assumed to be an array
* of associative arrays.
*
* #param array $data
* #param string $deliminator
*/
function __construct($data, $deliminator = ",")
{
if (!is_array($data))
{
throw new Exception('CSV_Writer only accepts data as arrays');
}
$this->data = $data;
$this->deliminator = $deliminator;
}
private function wrap_with_quotes($data)
{
$data = preg_replace('/"(.+)"/', '""$1""', $data);
return sprintf('"%s"', $data);
}
/**
* Echos the escaped CSV file with chosen delimeter
*
* #return void
*/
public function output()
{
foreach ($this->data as $row)
{
$quoted_data = array_map(array('CSV_Writer', 'wrap_with_quotes'), $row);
echo sprintf("%s\n", implode($this->deliminator, $quoted_data));
}
}
/**
* Sets proper Content-Type header and attachment for the CSV outpu
*
* #param string $name
* #return void
*/
public function headers($name)
{
header('Content-Type: application/csv');
header("Content-disposition: attachment; filename={$name}.csv");
}
}
?>
and php code:
if($_GET['action']=="csv") {
$data = array(array("one","two","three"), array(4,5,6));
$csv = new CSV_Writer($data);
$csv->headers('test');
$csv->output();
}
The problem is the resulting file. I have a CSV file instead of the array is only the HTML content page. Why is this happening?
The content of the CSV file:
<!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>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>title</title>
<link href="../css/style.css" rel="stylesheet" type="text/css" media="screen" />
<script type="text/javascript" src="jscripts/tiny_mce/tiny_mce.js"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript" src="jscripts/picnet.table.filter.min.js"></script>
<link href="style.css" rel="stylesheet" type="text/css" media="screen" />
<script type="text/javascript">
...
Thx for help.

You have two issues:
You're reinventing the wheel, as PHP already has fputcsv. Don't do that!
From what I can see, you didn't stop executing the script, so PHP is going to go ahead and render the rest of the HTML document. I can't tell exactly why you're not seeing the HTML preceded by CSV info, but maybe the output cache is being flushed somehow. The fix for this is to add an exit(); line at the end of that block:
if($_GET['action']=="csv") {
$data = array(array("one","two","three"), array(4,5,6));
$csv = new CSV_Writer($data);
$csv->headers('test');
$csv->output();
exit();
}

Related

Load html/php template function

I just go to the point.
Nvm need to add more text to much code..
Trying to load a Template with php inside it but php prints in html instead.
Init.php
class Init {
public static $ROOT = '';
public static $TEMPLATE = '';
public static $SERVICE = '';
public static function start() {
// Init Paths
Init::$ROOT = str_replace("\\", "/", __DIR__);
Init::$TEMPLATE = Init::$ROOT . "/Template/";
Init::$SERVICE = Init::$ROOT . "/Service/";
// Init Template.php class
require_once(Init::$SERVICE . "Template.php");
// Load template Top.php
$top = new Template(Init::$TEMPLATE . "Layout/Top.php");
echo $top->load(); // Show Top.php
}
}
Top.php
<!DOCTYPE html>
<html>
<?
// Load template Head.php
$head = new Template(Init::$TEMPLATE . "Layout/Head.php");
$head->set("TITLE", "Dashboard"); //Set [#TITLE] to Dashboard
$head->load(); // Show Head.php
?>
</html>
Head.php
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>[#TITLE] | cwEye</title> <!-- [#TITLE] will be Dashboard-->
<?
echo "Hello"; // ERROR -> This will print <? echo"Hello"; ?> in my page
?>
</head>
Template.php
<?
class Template {
protected $file;
protected $values = array();
private static $templateFile = null;
public function __construct($file) {
$this->file = $file;
}
public function set($key, $value) {
$this->values[$key] = $value;
}
// This code works but it will not load php inside
public function load() {
if (!file_exists($this->file)) return "Error loading template file ($this->file).";
ob_start();
include_once($this->file);
$data = ob_get_clean();
foreach ($this->values as $key => $value) {
echo str_replace("[#$key]", $value, $data);
}
if(count($this->values) == 0) echo $data;
}
}
?>
Ive played with allot of functions to make it but it does not work...
It just prints the php in html.
Tried with
ob_start();
include_once(FILE);
$data = ob_get_clean();
Don't use short tags like <? or <?=, use <?php instead. You probably have your short_open_tag set to false in php.ini. If you are using PHP 7 then you should know short tags were removed completely and wont work anymore.
In head.php use the full tag. Change
to
<?php echo "hello"; ?>

Extract code from PHP function and insert in earlier function

Is it possible to call a function in PHP that contains code meant for the head of a document that can be inserted into the head.
eg.
<head>
<title>PHP Test</title>
<?php extra_data();?>
</head>
<body>
<?php new_function();?>
</body>
So when new_function() is called it outputs some code but also contains so extra info for the head such as a stylesheet that can be added to the extra_data() function in the head at the top.
Since its all being executed on the server anyway is this possible?
You can define extra_data() like so:
function extra_data(){
$new_function_data = new_function();
switch($new_function_data['extra']){
case 1:
echo '<link href="extra1.css" rel="stylesheet" type="text/css">';
break;
case 2:
echo '<link href="extra2.css" rel="stylesheet" type="text/css">';
break;
}
}
You can define new_function() like so:
function new_function(){
//Add logic to determine what data should be returned
$data['normal'] = 'Normal data to output';
$data['extra'] = 'Extra data for extra_data()';
return $data;
}
and change your php to
<?php $new_function_data = new_function(); echo $new_function_data['normal']; ?>

Passing variables between php pages

I'm new to the Kohana Framework. I have a problem - How can I pass the variable $title from Layout.php to Head.php?
In controller:
<?php defined('SYSPATH') or die('No direct script access.');
class Controller_Admin_Quanly extends Controller_Template {
public $template='admin/layout';
function _showWithTemplate($subview,$title)
{
$admin_path = 'admin/';
$this->template->head = View::Factory(''.$admin_path.'head');
$this->template->subview = View::Factory(''.$admin_path.''.$subview.'');
$this->template->title = $title;
}
public function action_index()
{
$this->_showWithTemplate('subview/home','Trang quản trị hệ thống');
}
}
In view Layout.php:
<!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>
<?php echo $head?>
</head>
<body>
</body>
</html>
In view Head.php:
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title><?=$title?></title>
<base href="<?=URL::base()?>">
<link rel="stylesheet" type="text/css" href="style.css" />
<script type="text/javascript" src="javascript/jquery.min.js"></script>
<script type="text/javascript" src="javascript/ddaccordion.js"></script>
You could do something like this:
$admin_path = 'admin/';
$this->template->head = View::Factory(''.$admin_path.'head');
$this->template->head->title = $title;
$this->template->subview = View::Factory(''.$admin_path.''.$subview.'');
$this->template->title = $title;
Note the $this->template->head->title = $title; you need to pass it along manually to the head view.
You can use set() or bind(). See example:
$view = View::factory('user/roadtrip')
->set('places', array('Rome', 'Paris', 'London', 'New York', 'Tokyo'));
->bind('user', $this->user);
Ref: http://kohanaframework.org/3.3/guide/kohana/mvc/views
What you are looking for is set_global
http://docs.kohanaphp.com/core/view#set_global
It will allow you to set a variable for all your views to be able to use. You won't be passing it per say but it will still do what you want.
Example fix
function _showWithTemplate($subview,$title)
{
$admin_path = 'admin/';
$this->template->head = View::Factory(''.$admin_path.'head');
$this->template->subview = View::Factory(''.$admin_path.''.$subview.'');
$this->template->set_global('title', $title);
}

using custom template engine how do I replace content with php

So, I have a template engine I made and I want to replace {pageBody} with contents from a PHP file, when I do it using the template engine it does not execute the PHP, rather it displays it in view source option.
TEMPLATE.PHP
<?php
class TemplateLibrary {
public $output;
public $file;
public $values = array();
public function __construct($file) {
$this->file = $file;
$this->file .= '.tpl';
$this->output = file_get_contents('templates/'.$this->file);
}
public function replace($key, $value)
{
$this->values[$key] = $value;
}
public function output() {
foreach($this->values as $key => $value)
{
$ttr = "{$key}";
$this->output = str_replace($ttr, $value, $this->output);
}
return $this->output;
}
}
index.tpl
<!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>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>{page_title}</title>
{page_style}
</head>
<body>
{page_header}
{page_body}
{page_footer}
</body>
</html>
HTML replace works fine, but PHP does not. Any ideas?
You are rather scattered with your files and the list is incomplete. I've listed all the files you've provided so far below.
#Jonathon above is correct, that you will need to use output buffering to capture the output of the PHP file and include() the file (so it gets executed) instead of using file_get_contents() (which does not execute the file).
[edit] I re-created all these files in my local environment and confirmed that #Jonathon's suggestion worked perfectly. I've updated dev/replacements.php to include the suggested code.
Additionally, I added two more functions to your TemplateLibrary class : replaceFile($key, $filename) that does the file_get_contents($filename) so that you don't have to repeat it so often, and replacePhp($key, $filename) that performs an include() while capturing the output, so you can encapsulate the complexities of including a PHP file.
Good Luck!
main.php
<?php
require_once 'dev/dev.class.php';
require_once 'dev/templatelibrary.php';
$dev = new dev('netnoobz-billing');
$dev->loadLib('JS', 'js', 'jquery');
// template library and required files
$template = new TemplateLibrary('index');
require_once 'dev/replacements.php';
echo $template->output();
dev/templatelibrary.php
<?php
class TemplateLibrary {
public $output;
public $file;
public $values = array();
public function __construct($file) {
$this->file = $file;
$this->file .= '.tpl';
$this->output = file_get_contents('templates/'.$this->file);
}
public function replace($key, $value)
{
$this->values[$key] = $value;
}
public function replaceFile($key, $filename)
{
$this->values[$key] = file_get_contents($filename);
}
public function replacePhp($key, $filename)
{
ob_start();
include($filename);
$data = ob_get_clean();
$this->values[$key] = $data;
}
public function output() {
foreach($this->values as $key => $value)
{
$ttr = "{$key}";
$this->output = str_replace($ttr, $value, $this->output);
}
return $this->output;
}
}
index.tpl
<!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>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>{page_title}</title>
{page_style}
</head>
<body>
{page_header}
{page_body}
{page_footer}
</body>
</html>
replacements.php
<?php
$configStyleSheet = '<style type="text/css">'
. file_get_contents('styles/default/main.css')
. '</style>';
$pageHeader = file_get_contents('templates/header.tpl');
$pageFooter = file_get_contents('templates/footer.tpl');
#$pageBody = file_get_contents('loaders/pageBody.php');
ob_start();
include('loaders/pageBody.php');
$pageBody = ob_get_clean();
$template->replace('{page_style}' , $configStyleSheet);
$template->replace('{page_title}' , 'NetBilling');
$template->replace('{page_header}', $pageHeader);
$template->replace('{page_footer}', $pageFooter);
$template->replace('{page_body}' , $pageBody);
loaders/pageBody.php
<?php echo 'test'; ?>
[edit] added loaders/pageBody.php from OP's comment.
[edit] Updated dev/replacements.php to capture output buffer and use include on .php
You're using file_get_contents in your pastebin code but you should be using your template processor or PHP's include() instead. If you do $template->replace('{page_header}', $pageHeader), $pageHeader is just the source of the tpl and your template processor does not know that so it will just replace the tag with that source. Fix:
$pageHeader = new TemplateLibrary('header');
// ...
$template->replace('{page_header}', $pageHeader->output());
For the PHP files, you should call include() on the file, wrapped in output buffering, so you can pass the output of the PHP execution as the template variable, instead of the PHP source itself:
ob_start();
include('loaders/pageBody.php');
$pageBody = ob_get_clean();
/// ...
$template->replace('{page_body}', $pageBody);

MVC Blog - How to include a header\ footer\ other.php file

Following this tutorial http://johnsquibb.com/tutorials/mvc-framework-in-1-hour-part-one Im trying to write my first MVC Blog.
I understood how it works, router.php Calls the suitable page controller. This controller calls the model, Then calls the View page with the returned value.
My question is, What if I want to add to the same news.php page a header\footer. Normally I would write "include("header.php"). But now when using MVC, how could I implement that?
These are my files:
router.php:
<?php
/**
* This controller routes all incoming requests to the appropriate controller
*/
//Automatically includes files containing classes that are called
//fetch the passed request
$pageURL = $_SERVER["SERVER_NAME"].$_SERVER["REQUEST_URI"];
$path_parts = pathinfo($pageURL);
$page_name = $path_parts['filename'];
$parsed = explode('?' , $page_name);
//the page is the first element
$page = array_shift($parsed);
// If there is any variables, GET them.
if(!empty($parsed))
{
$parsed = explode('&' , $parsed[0]);
$getVars = array();
foreach ($parsed as $argument)
{
//explode GET vars along '=' symbol to separate variable, values
list($variable , $value) = explode('=' , $argument);
$getVars[$variable] = urldecode($value);
}
}
//compute the path to the suitable file
$target ='controllers/' . $page . '_controller.php';
//get target controller
if (file_exists($target))
{
include_once($target);
//modify page to fit naming convention
$class = ucfirst($page) . '_Controller';
//instantiate the appropriate class
if (class_exists($class))
{
$controller = new $class;
}
else
{
//did we name our class correctly?
die('class does not exist!');
}
}
else
{
//can't find the file in 'controllers'!
die('page does not exist!');
}
//once we have the controller instantiated, execute the default function
//pass any GET varaibles to the main method
$controller->main($getVars);
// AutoLoad
function __autoload($className)
{
// Parse out filename where class should be located
// This supports names like 'Example_Model' as well as 'Example_Two_Model'
list($suffix, $filename) = preg_split('/_/', strrev($className), 2);
$filename = strrev($filename);
$suffix = strrev($suffix);
//select the folder where class should be located based on suffix
switch (strtolower($suffix))
{
case 'model':
$folder = '/models/';
$filename = ($className);
break;
case 'library':
$folder = '/libraries/';
break;
case 'driver':
$folder = '/libraries/drivers/';
break;
}
//compose file name
$file = SERVER_ROOT . $folder . strtolower($filename) . '.php';
//fetch file
if (file_exists($file))
{
//get file
include_once($file);
}
else
{
//file does not exist!
die("File '$filename' containing class '$className' not found in
'$folder'.");
}
}
?>
post_controller.php
<?php
/**
* This file handles the retrieval and serving of posts posts
*/
class Posts_Controller
{
/**
* This template variable will hold the 'view' portion of our MVC for this
* controller
*/
public $template = 'posts';
/**
* This is the default function that will be called by router.php
*
* #param array $getVars the GET variables posted to index.php
*/
public function main(array $getVars)
{
//$b_controller =new Bottom_Bar_Controller;
//$b_controller->main($getVars);
$postsModel = new Posts_Model;
//get an post
$post = $postsModel->get_post($getVars['id']);
//create a new view and pass it our template
$header = new View_Model('header_template');
$bottom_bar = new View_Model('bottom_bar');
$view = new View_Model($this->template);
//assign post data to view
$view->assign('header', $header->render(FALSE));
$view->assign('bottom', $bottom_bar->render(FALSE));
$view->assign('title' , $post['title']);
$view->assign('content' , $post['content']);
$view->assign('date' , $post['date']);
$view->assign('by' , $post['added_by']);
$view->render();
}
}
posts_model.php
<?php
/**
* The Posts Model does the back-end heavy lifting for the Posts Controller
*/
class Posts_Model
{
/**
* Holds instance of database connection
*/
private $db;
public function __construct()
{
$this->db = new MysqlImproved_Driver;
}
/**
* Fetches article based on supplied name
*
* #param string $author
*
* #return array $article
*/
public function get_post($id)
{
//connect to database
$this->db->connect();
//sanitize data
$author = $this->db->escape($id);
//prepare query
$this->db->prepare
(
"
SELECT * FROM `posts`
WHERE
`id` = '$id'
LIMIT 1
;
"
);
//execute query
$this->db->query();
$article = $this->db->fetch('array');
return $article;
}
}
?>
view_model.php
<?php
/**
* Handles the view functionality of our MVC framework
*/
class View_Model
{
/**
* Holds variables assigned to template
*/
private $data = array();
/**
* Holds render status of view.
*/
private $render = FALSE;
/**
* Accept a template to load
*/
public function __construct($template)
{
//compose file name
$file = SERVER_ROOT . '/views/' . strtolower($template) . '.php';
if (file_exists($file))
{
/**
* trigger render to include file when this model is destroyed
* if we render it now, we wouldn't be able to assign variables
* to the view!
*/
$this->render = $file;
}
}
/**
* Receives assignments from controller and stores in local data array
*
* #param $variable
* #param $value
*/
public function assign($variable , $value)
{
$this->data[$variable] = $value;
}
/**
* Render the output directly to the page, or optionally, return the
* generated output to caller.
*
* #param $direct_output Set to any non-TRUE value to have the
* output returned rather than displayed directly.
*/
public function render($direct_output = TRUE)
{
// Turn output buffering on, capturing all output
if ($direct_output !== TRUE)
{
ob_start();
}
// Parse data variables into local variables
$data = $this->data;
// Get template
include($this->render);
// Get the contents of the buffer and return it
if ($direct_output !== TRUE)
{
return ob_get_clean();
}
}
public function __destruct()
{
}
}
posts.php
<!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>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link href="../style/style.css" rel="stylesheet" type="text/css" media="screen" />
<title> Posts (View)</title>
</head>
<body>
<div id="main">
<div class="container">
<?=$data['header'];?>
<div id="content">
<div class="content-background">
<h2> <?=$data['title'];?></h2>
<h4> <?=$data['date'];?> </h4>
<p><?=$data['content'];?></p>
</div>
</div>
</div>
</div>
</body>
</html>
Part of the problem is, that your tutorial has a pretty primitive interpretation of MVC-inspired design pattern (you actually cannot implement classical MVC in PHP, but there are patterns, that are based on it).
View is not just a template. Views are supposed to be class instances, which contain all presentation logic and deal with multiple templates. What you actually have there is a layout template which contains posts template.
// class \Application\View\Posts
public function render()
{
$layout = new Template( $this->defaultTemplateDirectory . 'layout.html');
$content = new Template( $this->defaultTemplateDirectory . 'posts.html' );
$layout->assign( 'content' , $content->render() );
return $layout->render();
}
Also, one of the things, that a view instance should do, is requesting information from the model layer.
Few materials that you might find useful:
Model-View-Confusion part 1: Why the model is accessed by the view in MVC
Simple PHP Template Engine
How should a model be structured in MVC?
And if you want to expand you knowledge in OOP, this post contains a list of recommended lectures and books.
There is no good solution in the MVC structure for that. You can find a solution in every framework. In CakePHP for example you can use an AppController, a controller which is always called for every requests. Sort of base controller.
But no, not very nice to do.
Most simple one is to ask the data directly from the view. That sounds weird but it is accepted in the MVC structure. So in your view you call $News->getLatestItems(10); and work with them.
I don't like it but it works.
If you have lots of widgets and blocks MVC alone might just not be the right structure. Then you could take a look at things like: http://techportal.inviqa.com/2010/02/22/scaling-web-applications-with-hmvc/ which is a derivate of MVC.
Another solution which you see more and more: Request it via AJAX calls. So just load them after the page has loaded. That way you also solve the issue since one MVC request then becomes multiple MVC requests.

Categories