I am running into a blank page, and although I have told PHP to report all errors I still get nothing which leads me to believe it must be a syntax error. I can't find what it is though.
Here is the script I am working on:
test.php
<?php
ini_set('display_errors', '1');
require('database.php');
print("hello");
$config = new Config("lessons.db","data/");
$db = new Database($config, array('first', 'second', 'third', 'fourth'), true);
print_r($db->dumpToArray());
?>
database.php
<?php
class Config {
private
$_db
$_file,
$_directory,
$_delimiter,
$_columns;
public function __construct(string $file, string $directory = null, string $delimiter = "|") {
$_db = $directory.$file;
$_directory = $directory;
$_delimiter = $delimiter;
}
public function db() {
return $_db;
}
public function delimiter() {
return $_delimiter;
}
}
class Database {
private
$_config,
$_columns,
$_rows,
$_pointer;
public function __construct(Config $config, array $constants = null, boolean $caseInsensitive = false) {
$_config = $config;
is_readable ($_config->db())
or exit ("The database cannot be read");
if(!is_null($constants))
$this->defineColumns($constants, $caseInsensitive);
return;
}
private function connect(string $method) {
if (!($_pointer = #fopen($_config->db(), $method)) or printf("Unable to connect to database");
}
private function disconnect() {
fclose($_pointer);
}
private function defineColumns($constants, $caseInsensitive) {
for (var $i=0;$i<count($constants);$i++)
define($constants[i], $i, $caseInsensitive);
}
public function dumpToArray() {
$arrayDump = explode($_config->delimiter(), file($_config->db(), FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES));
return $arrayDump;
}
public function getRowByValue($column, $value) {
$this->connect('r');
$rowNumber = 0;
while (!feof($_Pointer)) {
$row = explode($_config->delimiter(), fgets($dbPointer, 1024));
if ($row[$column] == $value) {
$this->disconnect();
return $row;
}
$rowNumber++;
}
$this->disconnect();
return false;
}
}
?>
Anyone can see what could be causing it?
I think require(database.php); should be require('database.php');.
Try changing that and see if it helps
Also, you're missing a semicolon on
return $arrayDump
EDIT
Okay, I'm not too sure, but try to remove the casting from the parameters of the functions.
So...
public function __construct(Config $config, array $constants = null, boolean $caseInsensitive = false)
Would be
public function __construct($config, $constants = null, $caseInsensitive = false) {
I don't do much OOC in PHP, but just taking another shot.
At first glance... This won't fly
$db = new Database($config, ["first","second","third","fourth"], true);
Your Database class expects an array
$db = new Database($config, array('first', 'second', 'third', 'fourth'), true);
Anyone can see what could be causing it?
Thats most wrong and inefficient way of looking for errors.
you can stare in your code for ages and even ask other people to do it, yet without any success.
Why not to just read the exact error message?
You were on the right track, but gave up.
As Flukey said in the comments, you have to check error log, which by default is the ame as web-server error log.
Watching the actual errors is the only proper way to correct your code.
Tip
If you have a syntax error and are in a situation where the only way you can change the error_reporting/display_errors settings is in the script itself, you can still make it work.
The trick is to make another script that has no syntax errors, and in that script set your config options, and then include the suspected bad script.
<?php
error_reporting(-1); // show all
ini_set('display_errors', 1);
require 'file_with_parse_error.php';
Still, you should generally be able to change these settings in php.ini or webserver config files. And there's should be an error log available to look at in any case.
Then just request the url for that new script in your web browser.
there are other error reporting levels in php.ini - you might want to look into them.
Since you're unable to look at error logs, try throwing a bunch of print statements in your code and see what line is killing your script. If it's killing in your database.php script, throw some prints in and there.
<?php
ini_set('display_errors', '1');
require('database.php');
print "Test1";
print("hello");
print "Test2";
$config = new Config("lessons.db","data/");
print "Test3";
$db = new Database($config, array('first', 'second', 'third', 'fourth'), true);
print "Test4";
print_r($db->dumpToArray());
?>
Related
I'm setting session in run method of thread class but i don't access to session from out.
And i create file by fopen in run method but the file also doesn't create.
for example, I'm using by the following codes:
session_start();
class Async extends Thread
{
public function run()
{
$fp = fopen('test.txt', 'w');
fwrite($fp, '1');
fclose($fp);
$_SESSION['test'] = 'test';
}
}
foreach ($tests as $test)
{
$workers[$i] = new Async();
$workers[$i]->start();
}
echo $_SESSION['test'];
Update a SESSION or any other variable by multiple threads is not safe !!
What do you want to do is dangerous: you can easily lose data, because your session's update function is not synchronized between different threads
The solution is to update your code like this :
<?php
session_start();
class Async extends Thread
{
private $_session = NULL;
public function __construct($session)
{
$this->_session = $session;
}
public function run()
{
// imagine if N threads want to open the same file with 'write' mode ?
$fp = fopen(Thread::getCurrentThreadId() . '_test.txt', 'w');
fwrite($fp, '1');
fclose($fp);
$this->_session['test'] = 'test';
}
public function getSession()
{
return $this->_session;
}
}
foreach ($tests as $test)
{
$workers[$i] = new Async($_SESSION);
$workers[$i]->start();
// to synchronize thread operations : wait until the launched thread has terminated
$workers[$i]->join();
$_SESSION = $workers[$i]->getSession();
}
echo $_SESSION['test'];
Notes :
While i'm doing some tests i have found an issue when i try to update an array in thread, so i've opened a new question in SO http://stackoverflow.com/q/32476271/4098311
I'm not very sure that `$_SESSION` is visible inside a thread, so i've passed it as an argument to the constructor
There are two possibilities.
1) run() function is not called due to some error.
2) As you said that fopen is not create a file, So it it possible that due to some error file does not create and code execution is stop before $_SESSION['test'] define.
I get a strange PHP error after updating my php version to 5.4
This is my function
protected function create() {
//if (VBRIDGE_DEBUG)
//drupal_set_message(__CLASS__ .'::'.__METHOD__);
$path = $this->vbridge_root_path;
$path_vbridge = $path . '/' . VBridge::VBRIDGE_CLASS_PREFIX;
$subclass = $this->getClass();
foreach ($this->_objclass as $objclass) {
if (!$this->createObj($path, $objclass, $subclass)) {
$this->createObj($path_vbridge, $objclass);
}
}
if (self::getStatus()) {
return false;
}
// Set User Session Qookie
//$this->getUser()->setQookie($this->getQookie());
// Set User Session
$this->getUser()->setSession($this->getSession());
$this->getSession()->setQookie($this->getQookie());
//$this->getUser()->setAuth($this->getAuth());
// Set User Pass
$this->getUser()->setPass($this->getPass());
// Set Auth
$this->setAuthMethods();
$this->setAuthStorages();
//
foreach ($this->getConfig() as $config) {
if ($config['#type'] == '#class') {
//createObj($config['#name'], $config['#type'], $config['#class'], $config['#path'], $appData['#config']);
}
}
return true;
}
This is the line that gives
if ($config['#type'] == '#class') {
I've looked at similar questions but haven't figured out how to fix this. Any assistance would be helpful.
Edit: Yes, I did put wrong code up last night. I was very tired after trying to tangle with this.
The error message you've posted doesn't match the line of code you say it originates from. You should get a different error for that, specifically to do with only using variables by reference.
Your code should be
$accounts = user_load_multiple(array(), array('name' => $login));
$account = array_shift($account);
But Drupal already has a helper method for that, so you might as well use it:
$account = user_load_by_name($login);
I'm doing a project using HTML5 WebSockets, with a PHP server using a websockets library right here at Github.
My project also depends on knowing how many players are online. The library has three abstract methods, connected, closed, and process. In connected and closed, it takes a parameter $user, which is a custom class that has a random alphanumeric string as the variable id.
I have a protected $users = []; at the beginning of my class, inside my class, which extends the WebSocketServer that the library provides. In my connected method, I array_push the $user provided to the $users array. Then, in my closed method, I loop through the $users array, checking if the element in $users has the same $id as the $user provided, and then array_splicing that element away if that is try.
So. Here's my problem. When I run my PvPASCIIServer.php as root, and connect using a test web page, everything works fine. BUT, when I disconnect, it says:
PHP Warning: array_splice() expects parameter 1 to be array, null given in /var/www/PvPASCII/PvPASCIIServer.php on line 24
Shouldn't array() not initialize $users as null? Why would it? I've also tried using the literal format of initializing arrays, [], but even that didn't work. And even wierder, my array_push at the beginning of my connected function did not return an error message. Logically, it should have worked and pushed a $user to the end of the $users array, so even if it was initialized null, it should have not been null after that.
My code, if you need it:
#!/usr/local/bin/php
<?
require_once("websockets.php");
class PvPASCIIServer extends WebSocketServer
{
protected $users = [];
protected function connected($user)
{
$this->send($user, "say Pong!");
array_push($this->users, $user);
echo $user->id;
return true;
}
protected function closed($user)
{
echo "Client " + $user->id + " disconnected from the server.";
for($i = 0; $i < sizeof($this->users); $i++)
{
if($this->users[$i]->id == $user->id)
{
array_splice($users, $i, 1); // <-- Line with the error
}
}
}
protected function process($user, $message)
{
// Yet to be determined.
}
}
$host = "localhost";
$port = 3000;
$server = new PvPASCIIServer($host, $port);
$server->run();
?>
$users needs to be $this->users just like everywhere else in your class:
if($this->users[$i]->id == $user->id)
{
array_splice($this->users, $i, 1); // <-- Line with the error
}
array_splice($users, $i, 1); // <-- Line with the error
Should be:
array_splice($this->users, $i, 1); // <-- Line with the error
Since you want to use the class variable $users and not the function variable $users
EDIT:
What John Conde also says (he was a little faster with typing ;-) )
I'm trying to make an error logging class, I have some functions to set up various output methods like DB, file, return and screen. I want all errors to be stored into an array and when __destruct() is called, I want to stop the client from waiting for data and the log details about errors the user experienced. This way they don't have to report errors to me.
I have 2 modes, a simple GUI to test the functionality and the actual script generates responses in JSON, machine to machine. For GUI the final dump is fine but for JSON it destroys the response. So all error reporting is off and I have to handle any errors that would be dumped on screen myself, hence the $return in function flush_log($return) which make the function return a string if set to true.
After reporting flushing the errors I want to:unset($this->log_arrays)
or empty: $this->log_arrays=Array();, but it is out of scope - I understand why, my function uses a local copy - but how do I reset the array?
[EDIT]:
I tried:
$this->log_arrays = Array();
$this->log_arrays = null;
array popping:
for ($i = 1; count($this->log_arrays); $i++)
{
array_pop($this->log_arrays);
}
But I think none of it can work because within a class function you work with copies of variables, so they're basically out of scope.
[/EDIT]:
This is an already simplified class.. :
<?php
class log_strings extends mysqli
{
private $log_arrays = Array();
public function __construct($output_to_file=false, $output_to_db=true, $fall_back_file=true, $arguments, $ip=null)
{
// Setup mysqli connection, file handle or report error if one or all have failed.
// Also check wich outputs should be used and keep that info for later.
}
public function log($level, $string)
{
$log_arrays[] = Array('level' => $level, 'string' => $string);
}
public function __destruct()
{
$this->flush_log();
}
public function flush_log($return=false)
{
if (!isset($log_arrays) && count($log_arrays) == 0)
{
return true;
}
if ($return)
{
return $this->return_output();
}
else
{
$success = false;
// if enabled, output to db
if ($this->output_to_db)
{
$success = $success || $this->mysqli_output();
}
// if enabled or if db failed and fallback is enabled, output to file
if ($this->output_to_file || ($this->fall_back_file && !$success))
{
$success = $success || $this->file_output();
}
// if neither file or db succeeded, dump on screen
if ($success = false)
{
$this->screen_dump();
}
return true;
}
unset($this->log_arrays); // <= This is what it is all about!
}
private function screen_dump()
{
foreach($this->log_arrays as $array)
{
echo "<strong>{$array['level']}</strong>{$array['string']}<br/>\n";
}
}
private function mysqli_output()
{
// Output to db functionally equal to $this->screen_dump()
}
private function file_output()
{
// Output to file functionally equal to $this->screen_dump()
}
private function return_output()
{
// Return output functionally equal to $this->screen_dump()
}
}
?>
Resetting the array should work
$this->log_arrays = array();
Unset a class property is a very bad idea. Because it may be used in other methods or other classes using a potentionally getter of your class.
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;
?>