PHP variables in/out a function - php

I want to write data in a csv.
For that I call a function to fill it.
I don't know how to call the variable outside the function (without global) so i open the file in it, but i need to close it outside, and i can't have my $fileOpen variable:
function doMyCode($args)
{
if (!isset($firstLoop)){
$fileOpen = fopen('customers.csv', 'w');
$firstLoop = true;
}
[...]
fputcsv($fileOpen, $rowData, ";");
}
fclose($fileOpen);
So, how can i do that? With good manners, i don't want to put one looper's counter (like $i)
UPDATE
The call to the function is in Magento, it's like the array_map(), but in this form i don't know how to send another parameter or return anything:
Mage::getSingleton('core/resource_iterator')->walk(
$theList->getSelect()->limit(10),
array('exportClient')
);
This is the reason I have this doubt

The best way would be to handle the file opening and closeing outside
function doMyCode($args, $fileOpen ){
fputcsv($fileOpen, $args, ";");
}
$fileOpen = fopen('customers.csv', 'w');
foreach( $lines as $line ){
doMyCode($line , $fileOpen );
}
fclose($fileOpen);
I would not open the file inside the function and close it elsewhere, either open / close it inside that function or open / close it outside, otherwise it just gets too messy, is it open? is it closed? who knows....

Related

PHP: how to check if a given file has been included() inside a function

I have a PHP file that can be include'd() in various places inside another page. I want to know whether it has been included inside a function. How can I do this? Thanks.
There's a function called debug_backtrace() that will return the current call stack as an array. It feels like a somewhat ugly solution but it'll probably work for most cases:
$allowedFunctions = array('include', 'include_once', 'require', 'require_once');
foreach (debug_backtrace() as $call) {
// ignore calls to include/require
if (isset($call['function']) && !in_array($call['function'], $allowedFunctions)) {
echo 'File has not been included in the top scope.';
exit;
}
}
You can set a variable in the included file and check for that variable in your functions:
include.php:
$included = true;
anotherfile.php:
function whatever() {
global $included;
if (isset($included)) {
// It has been included.
}
}
whatever();
You can check if the file is in the array returned by get_included_files(). (Note that list elements are full pathnames.) To see if inclusion occurred during a particular function call, check get_included_files before and after the function call.

Why my variable is undefined inside the function

It gives me this error Notice: Undefined variable: newfile and of course it also gives me fwrite() expects parameter 1 to be resource, null given cause of the first error. What I doing wrong?
$file = fopen("mycsv.csv", 'r');
$newfile = fopen("myjson.txt", 'w');
function write($text, $tab) {
$tabs = "";
for ($index = 0; $index < $tab; $index++) {
$tabs .= "\t";
}
fwrite($newfile, $text."\n".$tabs); //error here
}
Have a read about variable scope in the manual
$file and $newfile are global, therfore $newfile cannot be accessed locally in your function. Either move it into the function, pass it in as a parameter or as a last resort declare it as global in the function
You need to make $newfile global to be able to use it inside a function's scope:
function write($text, $tab) {
global $newfile;
// ... the rest
}
Any variable used inside a function is by default limited to the local function scope.
See: http://php.net/manual/en/language.variables.scope.php
You can do what you want if you make $newfile a global variable or pass it in as another function argument.
Function is out of scope. You could send the opened document direct to the function, that would allow it to be used within scope of the function.
function write($newfile,$text,$tab){
//the rest of your code
}
$returned = write($newfile,$text,$tab);

How to store values globally, permantly?

I want to store some counter and want to increment as desired.
This counters are not related to any client, so i cant use session or cookies.
I tried $GLOBALS but, its not what i want.
I want something like, let say i have 3 php files, each will do some counter manuplation.
init.php
$_GLOBAL_VARIABLE['cntr1'] = 0;
file1.php
$_GLOBAL_VARIABLE['cntr1'] = $_GLOBAL_VARIABLE['cntr1'] + 7;
file2.php
$_GLOBAL_VARIABLE['cntr1'] = $_GLOBAL_VARIABLE['cntr1'] + ($_GLOBAL_VARIABLE['cntr1'] * 0.90);
file3.php
echo $_GLOBAL_VARIABLE['cntr1'];
All three files (except init.php) will called randomly without ant relation and init will called once.
I dont want to try database transaction coz counter manuplation is very frequent, and file i/o is one and the same. I am looking for some way to store my data on server till the time its up and running, somewhat like global class and variables in c#.
If you want the store globally accessible value in the server without the use of database, cookie or session then memcache could be a solution for you. Its a daemon which allows you to store data and use it across different connection requests. If you have frequent visits you will have to somehow handle concurrency within you application.
I think this will work
global $cntr1;
If not then you can make one .inc.php and include this file to all pages.
This will resolve your issue.
im sure this is NOT what you wanted, but i've used fileread/filewrite to store my globals in a file on the drive, which can be read from, written to with updated values etc. This allows for you to set MANY global variables as int's, I've modified my globals code to work as a iterator, counting up or counting down by what ever value you pass.
its a simple quick class i made to handle the request :
<?php
class my_global{
protected $name;
protected $value;
static protected $path = './globals/';
public function __construct()
{
if(!is_dir(self::$path))
mkdir(self::$path);
}
public function change($name, $value)
{
$current = $this->get($name);
$this->set($name,$current+$value);
return $current+$value;
}
protected function set($name, $value)
{
$this->name = $name;
$this->value = $value;
$this->write();
}
protected function get($name)
{
if(file_exists(self::$path.$name))
{
$myFile = self::$path.$name;
$fh = fopen($myFile, 'r');
$value = fread($fh, filesize($myFile));
fclose($fh);
}
else
$value = 0;
$this->name = $name;
$this->value = $value;
return $value;
}
protected function write(){
$myFile = self::$path.$this->name;
$fh = fopen($myFile, 'w') or die("can't open file");
fwrite($fh, $this->value);
fclose($fh);
}
}
$my_global = new my_global();
?>
You can then just call the $my_global->change() method to increase or decrease the counter
<?php
echo $my_global->change('new_global',5).'<br>';
echo $my_global->change('anotherglobal',-2).'<br>';
echo $my_global->change('forme',7).'<br>';
?>
this is more food for thought than anything, but could be used tweaked to work as you need it.

PHP Counter Using OOP

I'm new to OOP terminology, I am trying to create a class that make a hit counter.
I try the code below but it create just a counter.txt page with inside value 1. I dont know why its not incrementing.
class LOGFILE {
public function READ($FileName) {
$handle = fopen($FileName, 'r');
$fread = file_get_contents($FileName);
return $fread;
fclose($handle);
}
public function WRITE($FileName, $FileData) {
$handle = fopen($FileName, 'w');
$FileData = $fread +1;
fwrite($handle, $FileData);
fclose($handle);
}
}
$logfile = new LOGFILE();
$logfile -> WRITE("counter.txt",$FileData);
echo $logfile -> READ("counter.txt");
The reason is that $fread is local variable for both READ and WRITE methods. You need to make it private global variable for your class:
class LOGFILE {
private $fread;
public function READ($FileName) {
$this->fread = file_get_contents($FileName);
return $this->fread;
}
public function WRITE($FileName) {
$this->READ($FileName);
$handle = fopen($FileName, 'w');
$FileData = $this->fread +1;
fwrite($handle, $FileData);
fclose($handle);
}
}
$logfile = new LOGFILE();
$logfile -> WRITE("counter.txt");
echo $logfile -> READ("counter.txt");
Note: I have removed fopen and fclose because file_get_contents does not need it. In write you can use file_put_contents. Removed not used variable $FileData too. It's always a good practice to create variables methods and classes when they are needed.
Also take a look at best practices how to name your classes, variables, methods and so on. Here's best guide, IMO.
Let's start going over the corrected code and see what was missing:
<?php
class LOGFILE {
public function READ($FileName) {
$handle = fopen($FileName, 'r');
$fread = fgets($handle, 8192);
fclose($handle);
return $fread;
}
public function WRITE($FileName, $FileData) {
$counter = $this->READ($FileName);
$handle = fopen($FileName, 'w');
fwrite($handle, $FileData + $counter);
fclose($handle);
}
}
$logfile = new LOGFILE();
$FileData = 1;
$logfile -> WRITE("counter.txt",$FileData);
echo $logfile -> READ("counter.txt")."\n";
$logfile -> WRITE("counter.txt",$FileData);
echo $logfile -> READ("counter.txt")."\n";
?>
use of fgets instead of file_get_contents in READ (you can choose to use file_get_contents but I rather stay consistent with the other function that uses fopen)
use of READ inside function WRITE (the principal of code-reuse)
open of file with write permissions in WRITE: 'w'
init $FileData = 1;
no need to hold a private member: $fread
most important: do not write statements after return (like you did in READ) - statements that are written after return will not be executed!
This solution was tested successfully.
OOP must be used where it's needed. You need a simple thing so, no need of OOP.
<?php
function addValue($file='counter.txt', $amount=1) {
if( false == is_file($file) ) {
return false;
}
$initial = file_get_contents($file);
return #file_put_contents($initial+$amount);
}
addValue();
?>
Test your OOP knowledge on something complex, like a shopping cart or some other concept.
EDIT // so, if you need a simple example that looks complex, here you go :)
<?php
class log {
public $file = '';
private $amount = 0;
public function __construct( $file ) {
$this->file = $file;
$this->amount = 1;
}
public function makeAdd() {
$initial = file_get_contents($this->file);
return #file_put_contents($this->file, $initial + $this->amount);
}
function __call($f, $args) {
switch( $f ) {
case 'add':
if(isset($args[0]) && !empty($args[0])) {
$this->amount = (int)$args[0];
}
if( $this->amount == 0 ) {
throw new Exception('Not a valid amount.');
}
return $this->makeAdd();
break;
}
}
}
try {
// create log
$L = new log('count.txt');
// this will add 2
var_dump($L->add(2));
// this will also add 2
var_dump($L->add());
// until you rewrite the amount
var_dump($L->add(1));
// final result -> 5
} catch(Exception $e) {
die($e->getMessage());
}
?>
Good luck!
Use UpperCamelCase for class names. LogFile, not LOGFILE. When you have a variable and the most interesting thing about it is that it's expected to hold a reference to something that is_a LogFile you should name it logFile.
Use lowerCamelCase for functions. read and write, not READ and WRITE
No spaces around the arrow operator
Code after a return statement in a method can never be reached, so delete it.
read() does not use the handle returned by fopen, so don't call fopen
the temp variable $freed doesn't help us understand the code, so we can lose it
read is a slightly unconventional name. If we rename the function to getCount it will be more obvious what it does.
You said you wanted to make a hit counter. So rename the class from LogFile to HitCounter, and the variable to hitCounter
the $FileData parameter to write doesn't get used because the variable is re-assigned inside the function. We can lose it.
The write method is supposed to add one to the number in the file. Write doesn't really express that. Rename it to increment.
Use a blank line between functions. The procedural code at the end should generally be in a separate file, but here we can just add a couple of extra lines. Delete the blanks between the last three lines of code.
Don't repeat yourself - we shouldn't have to mention 'counter.txt' more than once. OOP is all about combining data structures and behaviour into classes, so make a class private variable to hold the filename, and pass it via a constructor
$fread doesn't exist in the scope of increment, so we can't use it. This won't work. Replace it with a call to to getCount()
Swap the first two lines of increment, so we're not doing two concurent accesses to the same file, although we might be running inside a server that's running our script twice and still doing two concurrent accesses.
Rename the variable $FileData to $count, since that's what it is.
Replace the fopen,fwrite,fclose sequence with file_put_contents, since that does the same thing and is more succinct.
We need tag, since our php code continues to the end of the file.
That leaves us with:
<?php
class HitCounter {
private $fileName;
public function __construct($fileName){
$this->fileName = $fileName;
}
public function getCount() {
return file_get_contents($this->fileName);
}
public function increment() {
$count = $this->getCount() + 1;
file_put_contents($this->fileName, $count);
}
}
$hitCounter = new HitCounter("counter.txt");
$hitCounter->increment();
echo $hitCounter->getCount();
You can create a static counter and increment it each time (instead of create file)
<?php
class CountClass {
public static $counter = 0;
function __construct() {
self::$counter++;
}
}
new CountClass();
new CountClass();
echo CountClass::$counter;
?>

Flag for just create an empty file if not exists?

Which flag should i use for create a file if not exists? Please not that i'll close the point right after fopen() because the "hard part" (decoding the encrypted content) is carried by load() function (decoding logic is not shown):
Class MyClass
{
protected $filename, $data;
public function __construct($filename)
{
$this->filename = $filename;
// Create if not exists
if(!file_exists($this->filename))
{
$fp = fopen($this->filename, '');
fclose($fp);
}
$this->load();
}
public function load()
{
$data = file_get_contents($this->filename);
$this->data = $data === false ? array() : $data;
}
}
wb is about all you'd need. Open a file for writing, truncate any file which already exists, set the file pointer to the start of this new file, and enable binary mode (which prevents PHP from translating line-ending characters on certain platforms like Windows).
'a+', here manual. Ensure that permissions for the dir is ok.

Categories