Ik ben bezig mijn site over te zetten van PhP 5.6 naar PhP 7.3

Heb al veel gedaan maar loop tegen een probleem aan bij de volgende functie die ik ooit en keer op het internet gevonden heb. Functie is een rating manager (5 star rating). En ik heb geen idee hoe ik dit moet oplossen. Bestaat uit een stuk PhP en ene stuk AJAX (niet overgezet). Probleem zit in het PhP deel. Onderstaande code werk goed op PhP 5.6. Hulp wordt zeer gewaardeerd.

//mysql extention must be loaded
// Abstact class for rating
abstract class Database {
    public $databaseHost = DATABASEHOST;
    public $databaseUser = DATABASEUSERNAME;
    public $databasePassword = DATABASEPASSWORD;
    public $databaseName = DATABASENAME;
    public $connection = null; //  database connection
    protected $recordsSelected = 0;
    protected $recordsUpdated = 0;
    
    
    protected function connect() {
    
        $this->connection = new mysqli($this->databaseHost, $this->databaseUser, $this->databasePassword, $this->databaseName);
        if (!$this->connection) {
            $this->connection = null;
               trigger_error(mysql_error());
        }
//        mysql_select_db($this->databaseName);
    }
    
    protected function querySelect($query) {
        
        if (strlen(trim($query)) < 0 ) {
            trigger_error("Database encountered empty query string in querySelect function", E_USER_ERROR);
            return false;
        }
        
        if ($this->connection === null ) {
            $this->connect();
        }
        $result = $this->query($query, $this->connection) ;
        if (!$result) {
            return array();
        }
        $this->recordsSelected = mysql_num_rows($result);
        return $this->getData($result);
    }
    
    protected function queryExecute($query) {
        
        if (strlen(trim($query)) < 0 ) {
            trigger_error("Database encountered empty query string in queryExecute function", E_ERROR);
        }
        
        if ($this->connection === null ) {
            $this->connect();
        }
        
        $res = mysql_query($query, $this->connection);
        if($res) {
            $this->recordsUpdated = mysql_affected_rows($this->connection);
        }
    }
    
    protected function getData($result) {
        $data = array();
        $i = 0;
        while ($row = mysql_fetch_assoc($result)) {
            foreach ($row as $key => $value) {
                $data[$i][$key] = stripslashes($value);        
            }
            $i++;
        }
        return $data;
    }    
    
}
Tegen welke errors loop je aan?
Ik zie dat je in ieder geval de functies van mysqli moet gebruiken i.p.v. mysql.
- Ariën - op 03/07/2019 14:59:04

Tegen welke errors loop je aan?
Ik zie dat je in ieder geval de functies van mysqli moet gebruiken i.p.v. mysql.


De eerste waar ik tegen aan loop is:
Fatal error: Uncaught Error: Call to undefined method RatingManager::query() in /home/cyctoe01/decyclo.nl/TEST/prog/RatingManager.inc.php:77 Stack trace: #0

En dat is op deze regel: $result = $this->query($query, $this->connection) ;

Mijn probleem is niet zo zeer dat ik niet weet hoe ik de mysqli functies moet gebruiken. Maar hoe ik daar binnen deze functies mee om moet gaan.

Normaal gebruik is regels als:
$mysqli = new mysqli($DBserver, $DBuser_name, $DBpassword, $database);
$sql = "SELECT * from 'table'";
$result = $mysqli->query($sql);
$record = $result->fetch_assoc();
$record['tekst'];

Maar in deze functies wordt gebruik gemaakt van $this->connection
Moet ik overal waar $this->connection staat daar $this['connection'] van maken, net zoals bij attributen van een record?



Als ik alles omzetziet het er zo uit:
	protected function connect() {
	
		$this['connection'] = new mysqli($this['databaseHost'], $this['databaseUser'], $this['databasePassword'], $this['databaseName']);
		if (!$this['connection']) {
			$this['connection'] = null;
   			trigger_error(mysql_error());
		}
//		mysql_select_db($this->databaseName);
	}
	
	protected function querySelect($query) {
		
		if (strlen(trim($query)) < 0 ) {
			trigger_error("Database encountered empty query string in querySelect function", E_USER_ERROR);
			return false;
		}
		
		if ($this['connection'] === null ) {
			$this['connect']();
		}

//		$result = mysql_query($query, $this->connection) or die(mysql_error());
//		$result = $this->query($query, $this->connection) ;
		$result = $this->query($query, $this['connection']) ;
		if (!$result) {
			return array();
		}

//		$this->recordsSelected = mysql_num_rows($result);
		$this['recordsSelected'] = mysqli_num_rows($result);
		return $this->getData($result); 
	}
	
	protected function queryExecute($query) {
		
		if (strlen(trim($query)) < 0 ) {
			trigger_error("Database encountered empty query string in queryExecute function", E_ERROR);
		}
		
		if ($this['connection'] === null ) {
			$this['connect']();
		}
		
		$res = mysql_query($query, $this['connection']);
		if($res) {
			$this['recordsUpdated'] = mysqli_affected_rows($this['connection']);
		}
	}
	
	protected function getData($result) {
		$data = array();
		$i = 0;
		while ($row = mysql_fetch_assoc($result)) {
			foreach ($row as $key => $value) {
				$data[$i][$key] = stripslashes($value);		
			}
			$i++;
		}
		return $data;
	}	
	
}

En dan krjg ik de volgende meldng:
Fatal error: Uncaught Error: Cannot use object of type RatingManager as array in /home/cyctoe01/decyclo.nl/TEST/prog/RatingManager.inc.php:72 Stack trace: #0

En dat is op deze regel: if ($this['connection'] === null ) { In function QuerySelect
Zou je alsjeblieft alle codefragmenten tussen [code]...[/code] blokken kunnen zetten? Dat maakt eea een stuk beter leesbaar.

NB als je alles aan het omschrijven bent naar een object georienteerde smaak dan zul je iets moeten doen van de vorm $this->connection, en niet $this['connection'] ofzo.
Thomas van den Heuvel op 03/07/2019 18:10:04

Zou je alsjeblieft alle codefragmenten tussen [code]...[/code] blokken kunnen zetten? Dat maakt eea een stuk beter leesbaar.

NB als je alles aan het omschrijven bent naar een object georienteerde smaak dan zul je iets moeten doen van de vorm $this->connection, en niet $this['connection'] ofzo.

Heb alles bennen [cpde]gezet.

Mijn site is niet opject georienteerd. Alleen dit stukje heb ik vanaf het net geplukt en dat werkt anders dan de rest van mijn site. In de openingspost staat de originele code die ik graag omgezet wil hebben naar PhP 7 / mysqli.
Je gebruikt nu procedureel (mysqli_xxxx( ..) ) en objectgeorienteerd ($conn->query(...) ) door elkaar heen. Gezien je al met classes werkt, raad ik objectgeorienteerd aan.

Het kan wel gemengd, maar ik raad het af, omdat consistente code veel lekkerder werkt dan een mengelmoes. Verder is het ook makkelijk uit te bouwen met goede foutafhandeling.
Lijn 30 kan object-georienteerd
Lijn 44 is nog een oude query
Lijn 46 kan object-georienteerd
Lijn 53 is ook nog een verouderde functie.

Kijk ook eens op php.net/ en dan daarachter de functienaam, zoals bijv.https://php.net/mysqli_affected_rows, voor uitleg over de functies, en met name de object-georienteerde variant.

Misschien zou voor cruciale bedrijfstoepassingen, de standaard mysql-server geen oplossing zijn, maar Percona MySQL server.
Ik kom er nog niet uit. De 5 sterren worden wel getoond. En als er al op gestemd was dan wordt ook de gemiddelde rating weergegeven.
2 voorbeelden:
https://www.decyclo.nl/TEST/prog/index.php?Entre_Dore_et_Ance&subpageid=Cyclo&editid=8803#form2

https://www.decyclo.nl/TEST/prog/index.php?Marmotte_Granfondo_Alpes&subpageid=Cyclo&editid=6929#form2

Met muis over de sterren geeft goed aan hoeveel sterren ik wil kiezen voor mijn rating.

Maar bij klikken op een ster gebeurd er niets.

Op mijn site die nog op PhP 5.6 staat werkt het wel.
https://www.cyclokalender.nl/V2.0/prog/index.php?&id=&subpageid=cal

Hieronder de inhoud van het hele script dat dit afhandelt.


abstract class Database {
	public $databaseHost = DATABASEHOST;
	public $databaseUser = DATABASEUSERNAME;
	public $databasePassword = DATABASEPASSWORD;
	public $databaseName = DATABASENAME;
//	public $databaseHost = $DBserver;
//	public $databaseUser = $DBuser_name;
//	public $databasePassword = $DBpassword;
//	public $databaseName = $database;
	public $connection = null; //  database connection
	protected $recordsSelected = 0;
	protected $recordsUpdated = 0;
	
	
	protected function connect() {
	
		$this->connection = new mysqli($this->databaseHost, $this->databaseUser, $this->databasePassword, $this->databaseName);
		if (!$this->connection) {
			$this->connection = null;
   			trigger_error(mysqli_error()); 
		}
//		mysql_select_db($this->databaseName);
	}
	
	protected function querySelect($query) {
		
		if (strlen(trim($query)) < 0 ) {
			trigger_error("Database encountered empty query string in querySelect function", E_USER_ERROR);
			return false;
		}
		
		if ($this->connection === null ) {
			$this->connect();
		}
//		$result = $this->query($query) ;
		$result = mysqli_query($this->connection, $query) ;
		if (!$result) {
			return array();
		}

		$this->recordsSelected = mysqli_num_rows($result);
		return $this->getData($result); 
	}
	
	protected function queryExecute($query) {
		
		if (strlen(trim($query)) < 0 ) {
			trigger_error("Database encountered empty query string in queryExecute function", E_ERROR);
		}
		
		if ($this->connection === null ) {
			$this->connect();
		}
		
//		$res = $this->query($query);
		$res = mysqli_query($this->connection, $query) ;
		if($res) {
			$this->recordsUpdated = mysqli_affected_rows($this->connection);
		}
	}
	
	protected function getData($result) {
		$data = array();
		$i = 0;
		while ($row = $result->fetch_assoc()) {
			foreach ($row as $key => $value) {
				$data[$i][$key] = stripslashes($value);		
			}
			$i++;
		}
		return $data;
	}	
	
}



[size=xsmall]Toevoeging op 05/07/2019 21:35:13:[/size]

En het tweede deel



/**
 * Ajax start rating
 *@package AJAXRATING
 *@access public
 *@abstract Database
 *@author Sudhir Chauhan ([email protected], [email protected])
 *@return string
 *@version 1.0.0;
 * TODO:: 
 *	for optimisation we can get all values from rating table in the constructer
 * 	and avoid multiple select queries.
 * 	IP base check: restrict users how have already voted. (cookie or ip address0
 */
class RatingManager extends Database {
	public static $instance = 0;
	
	public function __construct() {
		
	}
	
	public static function getInstance() {
		if (self::$instance == 0 ) {
			self::$instance = new RatingManager();
		}
		return self::$instance;
//		echo " getInstance : </BR></BR>";
	}
	
	/**
	 * Draw stars
	 * TODO: add IP restriction check to avoid person to vote again
	 * COOKIE can also be used for this
	 */
	public function drawStars($id) {
//		echo " drawStars : </BR></BR>";
		
		if (!is_numeric($id)) {
			trigger_error("RatingManager encountered problem in drawStars() parameter. Passed parameter must be numeric.");
			exit;
		}
		
		$query = "SELECT total_votes, total_value, used_ips FROM " .TABLERATING ." WHERE id='".$id."'";
		$result = $this->querySelect($query);
		
		if (is_array($result) && count($result) > 0 ) {
			$totalVotes = $result[0]['total_votes'];	//how many total votes
			$totalValues = $result[0]['total_value'];  //total number of rating added together and stored
			$oldIPs = unserialize($result[0]['used_ips']);
		}
		else {
			$totalVotes = 1;
			$totalValues = 0;
			$oldIPs = Array();		
		}
		
		$currentRating = @number_format($totalValues / $totalVotes, 2) * STARWIDTH ;
		
		// allow single submit for userid
		//$ipAddress = $_SERVER['REMOTE_ADDR'];
		$ipAddress = $_SESSION['USERID'];
//		$ipAddress = $ip;
		
		if (in_array($ipAddress, $oldIPs)) {
			$this->drawPrintedStars($currentRating, $id); 
			return;
		}

$ratingString = '<div id="unit_long'.$id.'">
<ul class="unit-rating">
<li class="current-rating" style="width:'.$currentRating.'px;">Currently '.$currentRating.'; ?>/ TOTALSTARS </li>';
		
			for ($ncount = 1; $ncount <= TOTALSTARS; $ncount++) { 
				$ratingString .= '<li><a href="javascript:void(0);" title="'.$ncount.' out of '.TOTALSTARS.'" class="r'.$ncount.'-unit" onclick="javascript:sndRequest(\''.$ncount.'\','.$id.',\''.$ipAddress.'\')">'.$ncount.'</a></li>';
			}

			$ncount = 0; // resets the count
			
			$ratingString .= '</ul>
							</div>';
			
		echo $ratingString;	
		
	}
	
	/**
	 * update votes for id
	 */
	public function updateVote($numberofVotesSent, $voteForWitchId, $userIPAddress) {
//		echo " updateVote : </BR></BR>";
		$numberOfVotes = $numberofVotesSent;
		$voteForID = $voteForWitchId; 
		$ipAddress = $userIPAddress; 

		$query = "SELECT total_votes, total_value, used_ips FROM " .TABLERATING ." WHERE id='".$voteForID."'";
		$result = $this->querySelect($query);
		
		$sum = 0;
		$oldIPAddress = Array();
		if (is_array($result) && count($result) > 0) {
			$totalVotes = $result[0]['total_votes'];			//how many votes total
			$totalValues = $result[0]['total_value'];  //total number of rating added together and stored
			$oldIPAddress = unserialize($result[0]['used_ips']);
			$sum = $numberOfVotes + $totalValues;		// add together current vote value and the total vote value
		}
		
		if ($sum == 0) {
			$addedVotes = 1; //checking to see if the first vote has been voted
			$sum = $numberOfVotes ;
		}
		else {
			$addedVotes = $totalVotes + 1;//increment the current number of votes
		}

		if (is_array($oldIPAddress)) {
			array_push($oldIPAddress, $ipAddress);//if it is an array i.e. already has entries the push in another value
		}
		else {
			$oldIPAddress = array($ipAddress);//for the first entry
		}
		
		$serializeIPList = serialize($oldIPAddress);
		
		//Check existing IDs
		$query = "SELECT count(*) as total FROM " .TABLERATING ." WHERE id='".$voteForID."'";
		$result = $this->querySelect($query);
			
		if (is_array($result) && count($result) > 0 && $result[0]['total'] > 0 ) {
			$query = "UPDATE " .TABLERATING ." SET total_votes = '".$addedVotes."', total_value='".$sum."', used_ips='".$serializeIPList."' WHERE id='".$voteForID."'";			
			$this->queryExecute($query);
		}
		else {
			$query = "INSERT INTO " .TABLERATING ." (id, total_votes, total_value, used_ips) VALUES ($voteForID, $addedVotes, $sum, '".$serializeIPList."')";
			$this->queryExecute($query);
		}
		
		
		$currentRating = @number_format($sum / $addedVotes, 2) * STARWIDTH ;
		$this->drawPrintedStars($currentRating, $voteForID, true);
	}
	
	public static function votedByUser($userID) {
		$query = "SELECT ";
	}
	
	public function drawPrintedStars($currentRating, $voteForID, $addDivID = false) {
//		echo " drawPrintedStars : </BR></BR>";
		ob_start();
		header("Cache-Control: no-cache");
		header("Pragma: nocache");		
		$ratingString = "<ul class=\"unit-rating\">\n" .
						"<li class=\"current-rating\" style=\"width:". $currentRating ."px;\">Currently $currentRating</li>\n";
			
			for ($ncount = 1; $ncount <= TOTALSTARS; $ncount++) { 
				$ratingString .= "<li class=\"r$ncount-unit\">$ncount</li>\n";
			}
			
		$ratingString .= "</ul>";//show the updated value of the vote
		
		//name of the div id to be updated | the html that needs to be changed
		if ($addDivID === false) {
			$output = $ratingString;
		}
		else {
			$output = "unit_long$voteForID|$ratingString";
		}
		
		echo $output;
	}
	
}

?> 
Staat je algemene error_reporting en display_errors aan? En welke meldingen krijg je?
error_reporting(E_ALL & ~E_NOTICE);

Bij de ene pagina geen error en bij de andere pagina wel, bij mij dan, want verschil zit er in dat ik voor de Marmotte zelf een keer een rating heb ingevoerd.

Error is:
Warning: Cannot modify header information - headers already sent by (output started at /home/cyctoe01/decyclo.nl/TEST/hulpProg/browserdetect.php:1) in /home/cyctoe01/decyclo.nl/TEST/prog/RatingManager.inc.php on line 264

Warning: Cannot modify header information - headers already sent by (output started at /home/cyctoe01/decyclo.nl/TEST/hulpProg/browserdetect.php:1) in /home/cyctoe01/decyclo.nl/TEST/prog/RatingManager.inc.php on line 265

En dat is op deze regels:

public function drawPrintedStars($currentRating, $voteForID, $addDivID = false) {
// echo " drawPrintedStars : </BR></BR>";
ob_start();
header("Cache-Control: no-cache");
header("Pragma: nocache");

Beide header regels

[size=xsmall]Toevoeging op 05/07/2019 22:00:19:[/size]

Het enige verschil tussen de php5.6 en php 7.3 code is dit:


php 5.6 script

	protected function querySelect($query) {
		
		if (strlen(trim($query)) < 0 ) {
			trigger_error("Database encountered empty query string in querySelect function", E_USER_ERROR);
			return false;
		}
		
		if ($this->connection === null ) {
			$this->connect();
		}

		$result = $this->query($query, $this->connection) ;




	protected function querySelect($query) {
		
		if (strlen(trim($query)) < 0 ) {
			trigger_error("Database encountered empty query string in querySelect function", E_USER_ERROR);
			return false;
		}
		
		if ($this->connection === null ) {
			$this->connect();
		}
//		$result = $this->query($query) ; // DIT GEEFT EEN FOUTMELDING
		$result = mysqli_query($this->connection, $query) ;



De foutmelding die ik krijg bij : $result = $this->query($query) ; is:

Fatal error: Uncaught Error: Call to undefined method RatingManager::query() in /home/cyctoe01/decyclo.nl/TEST/prog/RatingManager.inc.php:75 Stack trace: #0 /home/cyctoe01/decyclo.nl/TEST/prog/RatingManager.inc.php(158): Database->querySelect('SELECT total_vo...') #1 /home/cyctoe01/decyclo.nl/TEST/prog/cycloPage.php(156): RatingManager->drawStars('5678') #2 /home/cyctoe01/decyclo.nl/TEST/prog/content.php(60): include('/home/cyctoe01/...') #3 /home/cyctoe01/decyclo.nl/TEST/prog/index.php(782): include('/home/cyctoe01/...') #4 {main} thrown in /home/cyctoe01/decyclo.nl/TEST/prog/RatingManager.inc.php on line 75

Reageren