php simplexml object caching - php

Consider the following function prototype for caching object from cached RSS(XML) feed:
function cacheObject($xml,$name,$age = 3600)
{
// directory in which to store cached files
$cacheDir = "cache/";
// cache filename
$filename = $cacheDir.$name;
// default to fetch the file
$cache = true;
// but if the file exists, don't fetch if it is recent enough
if (file_exists($filename))
{
$cache = (filemtime($filename) < (time()-$age));
}
// fetch the file if required
if ($cache)
{
$item = $xml->channel->item;
file_put_contents($filename,serialize($item));
// update timestamp to now
touch($filename);
}
// return the cache filename
return unserialize(file_get_contents($filename));
}
The function calls are as follows:
$urlD = "http://somerss.php";
$xmlD = simplexml_load_file(cacheFetch($urlD,'cachedfeedD.xml',3600));
$itemD = '';
if($xmlD === FALSE)
{$itemD = '';}
else
{$itemD = cacheObject($xmlD,'cacheobjectD',3600);}
$urlM = "somerss2.php";
$xmlM = simplexml_load_file(cacheFetch($urlM,'cachedfeedM.xml',3600));
$itemM = '';
if($xmlM === FALSE)
{$itemM = '';}
else
{$itemM = cacheObject($xmlM,'cacheobjectM',3600);}
I get the following error:
Fatal error: Uncaught exception 'Exception'
with message 'Serialization of 'SimpleXMLElement' is not allowed' in C:\xampp\htdocs\sitefinal\cacheObject.php:20 Stack trace: #0 C:\xampp\htdocs\sitefinal\cacheObject.php(20): serialize(Object(SimpleXMLElement))
Any help making this program to work is greatly appreciated.

Probably, the SimpleXMLElement class, like many built-in PHP objects, cannot be serialized.
Instead, you could call the class method asXML (which returns a valid XML string if you pass no parameters) and serialize this. You can then recreate the SimpleXMLElement class by calling simplexml_load_string() on this string.

Magpierss (free open source) is supposed to cache external xml files. I used it some years ago. You set the software a time frame to pull the xml file again. It worked well. Only problem I saw was that it kept pulling the xml file whether there was a frontend request for it or not which was using up the server. I think there might be a fix for that however. Good luck.

Related

ini_get_all('Zend OPcache') echos warning that the extension couldn't be found

I have an app where the user or rather the admin, can check the configuration of PHP. Cause it is an API the ini values are collected by calling ini_get_all with all the extension names.
This is the code I use
public function getLoadedExtensions(): array
{
$extensions = [];
$loadedExtensions = get_loaded_extensions();
foreach ($loadedExtensions as $extensionName) {
try {
$iniValues = #ini_get_all($extensionName);
} catch (Throwable) {
$iniValues = [];
}
$extension = new PhpExtension();
$extension->setExtensionName($extensionName);
$extension->setVersion(phpversion($extensionName));
$extensions[] = $extension;
}
return $extensions;
}
It works for nearly all extensions as expected, just for Zend OPcache and a few with no ini values I get the following warning:
<b>Warning</b>: ini_get_all(): Extension "Zend OPcache" cannot be found in <b>/var/www/html/src/Maintenance/PhpInfo/PhpInfoService.php</b> on line <b>39</b><br />
Is there a clean way to get the ini values used by OPcache? I currently run a ini_get_all() and filter if the key starts with opcache.
I found a way to get the correct values. This piece of code gets the correct infos:
$extension = new ReflectionExtension('Zend OPcache'); // or the name of any other extension
$iniValues = $extension->getINIEntries();
This way all extensions get the correct ini values.

XML fail to load with error

I'd like to parse an xml file with PHP. I used this code:
$images = parsage("Rambod_catalog.xml", "Thumbnail");
$prices = parsage("Rambod_catalog.xml", "Retail_Price");
echo sizeof($images);
function getindex($element, $liste) {
for($i=0;$i<sizeof($liste);$i) {
if($liste[$i] == $element)return $i;
}
return 0;
}
function parsage($document, $noeud) {
$document_xml = new DomDocument;
$document_xml->load($document);
$elements = $document_xml->getElementsByTagName($noeud);
return $elements;
}
but i got this exception:
Warning: DOMDocument::load() [domdocument.load]: I/O warning :
failed to load external entity "/Rambod_catalog.xml"
So, what is the problem? How can i fix my code?
"/Rambod_catalog.xml"
The path you have given is invalid. What you have wrote there is, unfortunately, referring to filesystem root. either the file is stored in the current directory and you delete the leading slash or specify a full path. (include_path is at times unreliable).
you should refer to files like CONSTANT_TO_DOCUMENT_ROOT.PATH_SEPARATOR.$fileName in order to be flexible.
also see getcwd() and $_SERVER global variable and in need, print_r or var_dump the reserved globlas to find what you might use for the CONSTANT_TO_DOCUMENT_ROOT.

Error handling loading a URL

I'm using a library called Simple HTML DOM
One of it's methods, loads the url into a DOM object:
function load_file()
{
$args = func_get_args();
$this->load(call_user_func_array('file_get_contents', $args), true);
// Throw an error if we can't properly load the dom.
if (($error=error_get_last())!==null) {
$this->clear();
return false;
}
}
In order to test error handling, I created this code:
include_once 'simple_html_dom.php';
function getSimpleHtmlDomLoaded($url)
{
$html = false;
$count = 0;
while ($html === false && ($count < 10)) {
$html = new simple_html_dom();
$html->load_file($url);
if ($html === false) {
echo "Error loading url!\n";
sleep(5);
$count++;
}
}
return $html;
}
$url = "inexistent.html";
getSimpleHtmlDomLoaded($url);
The idea behind this code it's to try again if the url is failing to load, if after 10 attemps still fails, it should return false.
However it seems that with an inexistent url, the load_file method never returns false.
Instead I get the following warning message:
PHP Warning: file_get_contents(inexisten.html): failed to open stream
Any idea how to fix this?
Note: Preferably I would like to avoid hacking into the library.
Change your following code:
$html->load_file($url);
if ($html === false) {
for this one:
$ret = $html->load_file($url);
if ($ret === false) {
because you were checking object instance instead of the returned value from load_file() method.
By adding the # sign before a method call, any warnings get supressed. If you use this, always be sure to check for errors yourself as you do now and are sure no other methods are available to make sure no warnings and/or errors pop up.
You should check the actual data that is saved somewhere by the load() method if that equals FALSE instead of the object instance $html.

Is there a way to keep a php object in memory to avoid disk reads and wirtes?

So I have an object that reads a file from disk gnugpg it appears to always create a gnugpg key ring in a home directory.
I want to avoid having to load this object every time a php script is called from apache.
is there away to have a php object stay in memory?
If it's a small object that doesn't take up much memory and is serializable you could just store it in the session:
function getSessionObject($objectName, $params){
$sessionObjectSerialized = getSessionVariable($objectName, FALSE);
if($sessionObjectSerialized == FALSE){
$sessionObjectSerialized = constructSessionObject($objectName, $params);
setSessionVariable($objectName, $sessionObjectSerialized);
}
$sessionObject = unserialize($sessionObjectSerialized);
return $sessionObject;
}
function constructSessionObject($objectName, $params = array()){
switch($objectName){
case('gnugpg_key_ring'):{
$gnugpgKeyRing = getGNUPGKeyRing(); //do whatever you need to do to make the keyring.
return serialize($countryScheme);
}
default:{
throw new UnsupportedOperationException("Unknown object name objectName, cannot retrieve from session.");
break;
}
}
}
//Call this before anything else
function initSession(){
session_name('projectName');
session_start();
}
function setSessionVariable($name, $value){
$_SESSION['projectName'][$name] = $value;
}
function getSessionVariable($name, $default = FALSE){
if(isset($_SESSION['projectName'])){
if(isset($_SESSION['projectName'][$name])){
$value = $_SESSION['projectName'][$name];
}
}
return $default;
}
and then retrieve that object by calling
getSessionObject('gnugpg_key_ring');
However not all objects are always serializable e.g. if the object holds a file handle to an open file, that would need to have some extra code to close the file when the object is serialized and then re-open the file when the object was unserialized.
If the object is large, then you would be better off using a proper caching tool like memcached to store the serialized object, rather than the session.

Channel.Connect.Failed error NetConnection.Call.BadVersion

Okay - So I've been looking all over the place to try and correct this problem - But I keep finding different answers, and frankly, it is getting terribly frustrating trying to figure this out. Lemme post some code for you to look at:
PHP Script:
public function addNewCompany(CompanyVO $item)
{
$stmt = mysqli_prepare($this->connection,
"INSERT INTO `companies` ('companyName') VALUES (?);");
$this->throwExceptionOnError();
mysqli_bind_param($stmt, 's', $item->companyName);
$this->throwExceptionOnError();
mysqli_stmt_execute($stmt);
$this->throwExceptionOnError();
$autoid = mysqli_stmt_insert_id($stmt);
mysqli_stmt_free_result($stmt);
mysqli_close($this->connection);
return $autoid;
}
Portions of the MXML Main App:
protected function companysignupsheet1_addCompanyEventHandler(event:AddCompanyEvent):void
{
companyservicero.addNewCompany({Data:event.companyData});
}
<s:RemoteObject id="companyservicero"
source="CompanyServices"
destination="addNewCompany"
endpoint = "http://localhost/PHP_RO/public/gateway.php"
result="companyservicero_resultHandler(event)"
fault="companyservicero_faultHandler(event)"/>
A Part of code from Component:
protected function button_submitNewCompany_clickHandler(event:MouseEvent):void
{
var companyData11:CompanyVO = new CompanyVO();
companyData11.companyName = textinput_NewCompanyName.text;
var eventObject:AddCompanyEvent = new AddCompanyEvent("addCompanyEvent", companyData11);
dispatchEvent(eventObject);
}
The Event:
package events
{
import flash.events.Event;
import valueObjects.CompanyVO;
public class AddCompanyEvent extends Event
{
public var companyData:CompanyVO;
public function AddCompanyEvent(type:String, companyData:CompanyVO)
{
super(type);
this.companyData = companyData;
}
}
}
If I need to post more I will be happy to do so. Also - I know it is a bit overkill to try and just send the one text value in this fashion, but there will be much, much more that will go with it when I get it working - I just was trying to focus on where the problem is. Oh - and I don't know if it helps at all...But currently I can retrieve records from the mySQL database this is attached to (although I am not doing that via the RemoteObject way) - I can also add to the same table using the old drag-and-drop (Connect to Data/Services) functionality of an exact copy of the PHP above (although with the information hard coded in (I.E. the CompanyName=testtest)).
And to finish it all off - earlier when I didn't define the datatype for the argument:
public function addNewCompany($item){.....
for addNewCompany - it DID add a record in the database, although it was blank and it would still popup an error message with the whole Channel.Connect, etc..... And now in Zend Server's logs it is saying that the data is getting transferred in a stdClass wrapper and it is needed in CompanyVO datatype.
I am sooo frustrated with this all - I've been stuck with this type of problems for about 2-3 days now and I give up! PLEASE help. Thank you so much for your time and assistance!
-CS
EDIT - MORE INFO
GATEWAY.PHP
<?php
ini_set("display_errors", 1);
$dir = dirname(__FILE__);
$webroot = $_SERVER['DOCUMENT_ROOT'];
$configfile = "$dir/amf_config.ini";
$servicesdir = $dir.'/../services';
$librarydir = $dir.'/../library';
//default zend install directory
$zenddir = $webroot.'/ZendFramework/library';
//Load ini file and locate zend directory
if (file_exists($configfile)) {
$arr = parse_ini_file($configfile, true);
if (isset($arr['zend']['webroot'])) {
$webroot = $arr['zend']['webroot'];
$zenddir = $webroot.'/ZendFramework/library';
}
if (isset($arr['zend']['zend_path'])) {
$zenddir = $arr['zend']['zend_path'];
}
if (isset($arr['zend']['library'])) {
$librarydir = $arr['zend']['library'];
}
if (isset($arr['zend']['services'])) {
$servicesdir = $arr['zend']['services'];
}
}
// Setup include path
// add zend directory, library and services to include path
set_include_path(get_include_path()
.PATH_SEPARATOR.$zenddir
.PATH_SEPARATOR.$librarydir
.PATH_SEPARATOR.$servicesdir);
// Initialize Zend Framework loader
require_once 'Zend/Loader/Autoloader.php';
Zend_Loader_Autoloader::getInstance()->setFallbackAutoloader(true)- >suppressNotFoundWarnings(true);
// Load configuration
$default_config = new Zend_Config(array("production" => false), true);
$default_config->merge(new Zend_Config_Ini($configfile, 'zendamf'));
$default_config->setReadOnly();
$amf = $default_config->amf;
// Store configuration in the registry
Zend_Registry::set("amf-config", $amf);
// Initialize AMF Server
$server = new Zend_Amf_Server();
$server->setProduction($amf->production);
if (isset($amf->directories)) {
$dirs = $amf->directories->toArray();
foreach ($dirs as $dir) {
if ($dir == "./") {
$server->addDirectory($webroot);
} else
if (realpath("{$webroot}/{$dir}")) {
$server->addDirectory("{$webroot}/{$dir}");
} else
if (realpath($dir)) {
$server->addDirectory(realpath($dir));
}
}
}
// Initialize introspector for non-production
if (! $amf->production) {
$server->setClass('Zend_Amf_Adobe_Introspector', '',
array("config" => $default_config, "server" => $server));
$server->setClass('Zend_Amf_Adobe_DbInspector', '',
array("config" => $default_config, "server" => $server));
}
// Handle request
echo $server->handle();
AMF_CONFIG
[zend]
;set the absolute location path of webroot directory, example:
;Windows: C:\apache\www
;MAC/UNIX: /user/apache/www
webroot = "C:/Zend/Apache2/htdocs"
;set the absolute location path of zend installation directory, example:
;Windows: C:\apache\PHPFrameworks\ZendFramework\library
;MAC/UNIX: /user/apache/PHPFrameworks/ZendFramework/library
zend_path ="C:/Zend/Apache2/htdocs/.metadata/.plugins/org.zend.php.framework.resource/resources/ZendFramework-1/library"
library ="C:/Zend/Apache2/htdocs/PHP_RO/library"
services ="C:/Zend/Apache2/htdocs/PHP_RO/services"
[zendamf]
amf.production = false
amf.directories[]=PHP_RO/services
Channel.Connect.Failed error NetConnection.Call.BadVersion usually happens when PHP echoes an error or warning to the amf response. Flex gets an amf message appended with something like 'warning something went wrong on line X' and can't parse it.
Turn on the network monitor in Flash Builder and view the latest raw response. You will see the error formatted with html tags.

Categories