We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 4429
    • 429 Posts
    I am developing a website for the lacrosse club I am part of. As part of the site, it should display fixtures direct from the governing bodies website using rest.

    this has worked on previous sites and worked when i was initially developing the modx based site.

    Here is my snippet:

    <?php
    require_once('rest.inc');
    
    $xmlfile = 'mens-fixtures-East+Coast.xml';  // local file name to store XML data
    $xmlurl = 'http://www.southlacrosse.org.uk/rest/fixtures/mens/East+Coast'; // URL of data on South Lacrosse site
    
    
    $httpCache = new httpCache($xmlurl,$xmlfile);
    $httpCache->fetch();
    
    
    
    // parse XML data into arrays for easier processing
    if (!$httpCache->isError()) {
        $parser = new simpleParser();
        $xml = &$parser->parseString($httpCache->getXml());
    }
    // output page heading
    ?>
    
    
    
    <?
    if ($httpCache->isError()) {
        echo '<p style="color: red;"><b>Error retrieving data : ' . $httpCache->getError()
            . "</b></p>\n"; 
    } elseif (!$xml) {
        echo '<p style="color: red;"><b>Error converting data : ' . $parser->getError()
            . "</b></p>\n"; 
    } else {
    ?>
    <table style="text-align: center;" cellpadding="3" cellspacing="2" border="0" width="100%">
    <thead>
    <tr>
    <th>Date</th>
    <th>Home</th>
    <th/>
    <th/>
    <th/>
    <th>Away</th>
    <th>Competition</th>
    </tr>
    </thead>
    <tbody>
    <?
        // Loop thru all the fixtures in the XML document
        foreach ($xml->fixture as $fixture) {
            $date = date('j M y',strtotime($fixture->date));
            // note: competition is wrapped in htmlspecialchars() as it
            // may contain &
    ?>
    <tr>
    <td><? echo $date; ?></td>
    <td><? echo $fixture->{'home-team'}; ?></td>
    <td><? echo $fixture->{'home-goals'}; ?></td>
    <td><? if ($fixture->{'home-team'} || $fixture->{'away-team'}) echo 'v'; ?></td>
    <td><? echo $fixture->{'away-goals'}; ?></td>
    <td><? echo $fixture->{'away-team'}; ?></td>
    <td><? echo htmlspecialchars($fixture->competition); ?></td>
    </tr>
    <?    } // end of fixtures loop ?>
    </tbody>
    </table>
    <?
    } // end of else
    
    // finish off page
    ?>


    Here is the error when I try to call that snippet:
    « MODx Parse Error »
    MODx encountered the following error while attempting to parse the requested resource:
    « PHP Parse Error »

    PHP error debug
    Error: touch() [function.touch]: Utime failed: Operation not permitted
    Error type/ Nr.: Warning - 2
    File: /home/x0149128/public_html/playlacrosse.co.uk/rest.inc
    Line: 337
    Line 337 source: touch($this->destCacheInfoFile, time(), $remoteDate);

    Parser timing
    MySQL: 0.0009 s (5 Requests)
    PHP: 0.5093 s
    Total: 0.5102 s

    Here is the full rest.ini file

    <?php
    
    ////////////////////////////////////////////////////
    
    // Support for accessing REST services.  Includes:
    
    //
    
    // simpleParser - XML parsing for PHP4/5
    
    // cacheHeaders - allow dynamic pages to be cached in the browser
    
    // httpCache - cache http requests (in this case REST xml pages)
    
    //
    
    // Copyright (C) 2006 Dave Slaughter [email protected]
    
    //
    
    // This library is free software; you can redistribute it and/or
    
    // modify it under the terms of the GNU Lesser General Public
    
    // License as published by the Free Software Foundation; either
    
    // version 2.1 of the License, or (at your option) any later version.
    
    // 
    
    // This library is distributed in the hope that it will be useful,
    
    // but WITHOUT ANY WARRANTY; without even the implied warranty of
    
    // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    
    // Lesser General Public License for more details.
    
    //
    
    // See http://www.gnu.org/copyleft/lesser.html
    
    ////////////////////////////////////////////////////
    
    
    
    // simpleParser/simpleNode 
    
    //
    
    // Classes for parsing XML into an array of objects in a similar
    
    // fashion to SimpleXml in PHP5, but will also work in PHP4.
    
    //
    
    // If a node has attributes or children then it will be a simpleNode,
    
    // otherwise a string.  The root node will always be a simpleNode,
    
    // and have a field "tag" to indicate the name of the root tag.
    
    // Child nodes are added as fields of the same name to their parent node.  If there
    
    // are multiple child nodes with the same name then they will be defined as
    
    // an array.  Attributes are added as an array called "attributes".
    
    //
    
    // You can check if the node you have got is a simpleNode by using is_object(). 
    
    //
    
    // e.g. xml file
    
    // <a>
    
    //   <b>B text</b>
    
    //   <c attr="c-attr">C text</c>
    
    //   <d>d one</d>
    
    //   <d>d two</d>
    
    // </a>
    
    // will parse to
    
    //   simpleNode {
    
    //     tag ="a",
    
    //     b = "B text"
    
    //     c = simplenode {
    
    //	     attributes = array(1) { attr->"c-attr" } 
    
    //	     cdata = "C text"
    
    //     }	 
    
    //	   d = array(2) { "d one", "d two" }
    
    // 	 }
    
    //   
    
    //  Simple example is
    
    //
    
    //  $parser = new simpleParser();
    
    //  $xml = $parser.parseFile("somefile");
    
    //  echo "b=" . $xml->b . "\n"; //  <b> node text, i.e. "B text"
    
    //  echo echo "c=" . $xml->c->cdata . "\n"; //  <c> node text, i.e. "C text"
    
    //  foreach ($xml->d as $d) { // loop thru all <d> nodes
    
    //    echo "d=$d\n";
    
    //  }
    
    class simpleNode {
    
    	var $tag;
    
    	var $cdata = '';
    
    	function simpleNode($tag, $attributes) {
    
    		$this->tag = $tag;
    
    		if (count($attributes) != 0) {
    
    			$this->attributes = $attributes;
    
    		}
    
    	}
    
    	// PHP5 will return cdata for this node
    
    	function __toString() {
    
    		return cdata;
    
    	}
    
    	function debugString() {
    
    		return $str = '[' . $this->tag
    
    			. ', attrCount=' . count($this->attributes)
    
    			. ', haschildren='.$this->hasChildren . ']';
    
    	}
    
    } // end of class simpleNode
    
    
    
    class simpleParser  {
    
    	var $parser;
    
    	var $nodeStack;
    
    	var $currentNode;
    
    
    
        function simpleParser() {  }
    
    
    
        /**
    
         * Parse XML within a file into an array 
    
         * @return the parsed array, or FALSE for failure
    
         */
    
        function parseFile($file) {
    
        	$this->_createParser();
    
    		if (!($fp = fopen($file, "r"))) {
    
      			die ("Cannot locate XML file : $xmlFile");
    
    		}
    
    		// read & parse
    
    		while ($data = fread($fp, 4096)) {
    
      			if (!xml_parse($this->parser, $data, feof($fp))) {
    
        			$this->error = sprintf("XML error: %s at line %d",
    
            			xml_error_string(xml_get_error_code($this->parser)),
    
    	        		xml_get_current_line_number($this->parser));
    
      			}
    
    		}
    
    		return $this->_freeParser();
    
    	}
    
        	
    
        /**
    
         * Parse XML in a string into an array 
    
         * @return the parsed array, or FALSE for failure
    
         */
    
        function parseString(&$data) {
    
        	$this->_createParser();
    
    		if (!xml_parse($this->parser, $data, TRUE)) {
    
       			$this->error = sprintf("XML error: %s at line %d",
    
           			xml_error_string(xml_get_error_code($this->parser)),
    
            		xml_get_current_line_number($this->parser));
    
    		}
    
    		return $this->_freeParser();
    
        }
    
    	function getError() {
    
    		return $this->error;
    
    	}
    
        function _createParser() {
    
        	$this->nodeStack = array();
    
        	$this->currentNode = -1;
    
        	unset($this->error);
    
            $this->parser = xml_parser_create();
    
    		xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);	
    
       		xml_parser_set_option($this->parser, XML_OPTION_SKIP_WHITE, 1);
    
       		xml_set_object($this->parser, $this);
    
            xml_set_element_handler($this->parser, "_tag_open", "_tag_close");
    
            xml_set_character_data_handler($this->parser, "_cdata");
    
        }
    
        function _freeParser() {
    
            xml_parser_free($this->parser);
    
            if (isset($this->error)) {
    
    	        unset($this->nodeStack);
    
            	return false;
    
            }
    
            $root =& $this->nodeStack[0];
    
            unset($this->nodeStack);
    
            return $root;
    
        }
    
    
    
        function _tag_open($parser, $tag, $attributes) {
    
        	// just pop the new node onto the stack
    
        	$this->nodeStack[] =& new simpleNode($tag,$attributes);
    
        	$this->currentNode++;
    
        }
    
    
    
        function _cdata($parser, $cdata) {
    
        	// add characrer data to the current node
    
        	$this->nodeStack[$this->currentNode]->cdata .= $cdata;
    
        }
    
    
    
        function _tag_close($parser, $tag) {
    
        	// get current node and tidy it up
    
    		$node =& $this->nodeStack[$this->currentNode];
    
    		$node->cdata = trim($node->cdata);
    
            if ($node->cdata == '') {
    
            	unset($node->cdata);
    
            }
    
            // don't do anything to the root node, and also make sure we keep it
    
            // to return from the parse functions
    
            if ($this->currentNode > 0) {
    
        		$tag = $node->tag;
    
        		// if current node only has character data then add it as a 
    
        		// string to the parent, but if it has children or attributes
    
        		// then add it as a simpleNode
    
    	 		if (!$node->hasChildren && count($node->attributes) == 0) {
    
    	 			$node = $node->cdata;
    
    			} else {
    
    	        	unset($node->hasChildren);
    
    	 		}
    
    	        // get field "$node->tag" from parent (i.e. the field with the same name
    
    	        // as this nodes tag), so we can add this node to it. 
    
    	        // need to decide if it was unset, a single value, or an array
    
    	        $parent =& $this->nodeStack[$this->currentNode - 1];
    
    	        if (!isset($parent->{$tag})) { // no field
    
    	        	$parent->{$tag} = $node;
    
    	        	$parent->hasChildren = true;
    
    	        } elseif (count($parent->{$tag}) > 1) { // field is array
    
    				$parent->{$tag}[] = $node;
    
    			} else { // single field, so make array
    
    				$parent->{$tag} = array($parent->{$tag}, $node);
    
    			}
    
    			array_pop($this->nodeStack);
    
            } else {
    
            	// tidy up root node
    
    			unset($node->hasChildren);
    
    		}
    
            $this->currentNode--;
    
    	}
    
    
    
    } // end of class simpleParser
    
    
    
    // cacheHeaders - send "Not Modified" response, or set Last-Modified header
    
    // $depends should be an array of dependant files
    
    function cacheHeaders($depends) {
    
    	$modDate = getlastmod();
    
    	// check for extra dependancies from script
    
    	if (!empty($depends) && is_array($depends)) {
    
    		while (list($key,$item) = each ($depends)) {
    
    			$fileModDate = filemtime($item);
    
    			if ($fileModDate > $modDate) {
    
    				$modDate = $fileModDate;
    
    			}
    
    		}
    
    	}
    
    	$fileModDate = filemtime(__FILE__);
    
    	if ($fileModDate > $modDate) {
    
    		$modDate = $fileModDate;
    
    	}
    
    	// send HTTP 304 if possible
    
    	if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) >= $modDate) {
    
    		if (substr(php_sapi_name(), 0, 3) == 'cgi') {
    
    			header('Status: 304 Not Modified');
    
    		} else {
    
      			header('HTTP/1.1 304 Not Modified');
    
      		}
    
        	exit;
    
    	}
    
    	header('Last-Modified: '.gmdate('D, d M Y H:i:s', $modDate).' GMT');
    
    }
    
    
    
    // httpCache - cache an HTTP request for a REST service
    
    class httpCache {
    
    	var $url;
    
    	var $destFile;
    
    	// Keep time we last asked the server for the XML file.  Don't set the
    
    	// modified date on $destFile as 304 processing in cacheHeaders won't work
    
    	// correctly.
    
    	// Stores the remote server time in accessTime, so when we send the
    
    	// If-Modified-Since header it is the correct date.  However, we also use
    
    	// this for checking if the cache is stale, so the local time is stored in
    
    	// the modifiedTime.
    
    	var $destCacheInfoFile;
    
    	var $timeout;
    
    	var $xml = null;
    
    	
    
    	function httpCache($url, $destFile, $timeout=7200) {
    
    		$this->url = $url;
    
    		$this->destFile = $destFile;
    
    		$this->destCacheInfoFile = $destFile . '.cacheinfo';
    
    		$this->timeout = $timeout;
    
    	}
    
    	// remove the file from the cache
    
    	function delete() {
    
    		unlink($this->destFile);
    
    		unlink($this->destCacheInfoFile);
    
    	}
    
    	// Fetch the file from the remote server and cache it locally.
    
    	function fetch() {
    
    		if (file_exists($this->destFile) && file_exists($this->destCacheInfoFile)) {
    
    			$lastChecked = filemtime($this->destCacheInfoFile);
    
    		} else {
    
    			$lastChecked = 0;
    
    		}
    
    		if($lastChecked < (time() - $this->timeout)) {
    
    			// Initialize the session
    
    			$session = curl_init($this->url);
    
    	
    
    			// Set curl options
    
    			curl_setopt($session, CURLOPT_HEADER, true);
    
    			curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
    
    			// send the If-Modified-Since header with the last accessed time
    
    			if ($lastChecked != 0) {
    
    				$fileModGMT = gmdate('D, d M Y H:i:s', fileatime($this->destCacheInfoFile)).' GMT';
    
    				curl_setopt($session, CURLOPT_HTTPHEADER, array("If-Modified-Since: $fileModGMT"));
    
    			}
    
    	
    
    			// Make the request
    
    			$response = curl_exec($session);
    
    	
    
    			// Close the curl session
    
    			curl_close($session);
    
    	
    
    			// Get HTTP Status code from the response
    
    			$statusCode = array();
    
    			if (!preg_match('/\d\d\d/', $response, $statusCode)) {
    
    				$this->error = 'Invalid response from '+$this->url;
    
    			}
    
    	
    
    			// Check the HTTP Status code
    
    			switch( $statusCode[0] ) {
    
    				case 200:
    
    					// Success
    
    					break;
    
    				case 304:
    
    					// file on server was not modified - so update the file with the current date
    
    					// from the server (otherwise on the next view of this page we will try to
    
    					// fetch it again), and return the cached file contents (since the request
    
    					// returns no data)
    
    					$this->_setCacheInfoDate($response);
    
    					return;
    
    				default:
    
    					$this-> error =  'Retrieving data from '.$this->url.' failed, and returned an unexpected HTTP status of:' . $statusCode[0];
    
    					return;
    
    			}		
    
    			// Get the XML from the response, bypassing the header
    
    			if (!($this->xml = strstr($response, '<?xml'))) {
    
    				$this->error = 'Cannot find XML in response from '.$this->url;
    
    				return;
    
    			}
    
    			$tmpf = tempnam('/tmp','YWS');
    
    			$fp = fopen($tmpf,"w");
    
    			fwrite($fp, $this->xml);
    
    			fclose($fp);
    
    			rename($tmpf, $this->destFile);
    
    			$this->_setCacheInfoDate($response);
    
    		}
    
    	}
    
    	
    
    	// Return the actual XML data
    
    	function getXml() {
    
    		if ($this->xml) {
    
    			return $this->xml;
    
    		}
    
    		return file_get_contents($this->destFile);
    
    	}
    
    	function isError() {
    
    		return isset($this->error);
    
    	}
    
    	function getError() {
    
    		return $this->error;
    
    	}
    
    	// internal function to update modified/accessed date on cacheinfo file.
    
    	function _setCacheInfoDate($response) {
    
    		$modDate = array();
    
    		if (preg_match('/^Date: (.*)$/m', $response, $modDate)) {
    
    			$remoteDate = strtotime($modDate[1]);
    
    			touch($this->destCacheInfoFile, time(), $remoteDate);
    
    		} else {
    
    			touch($this->destCacheInfoFile);
    
    		}
    
    	}
    
    } // end of class HttpCache
    
    ?>


    Does anyone know what the problem is at all?

      • 26903
      • 1,336 Posts
      The error your getting is a permissions error, touch will create an empty file with the current time if the file doesn’t exist, or update an existing files utime(last updated) to the current time if it does i.e. ’touch’ it.You can specufy the touch update and access times also.

      It looks as though you dont have permission to update this files utime, I’d check your permissions here, remember the file in question has to be updateable by your webserver user, e.g. apache
        Use MODx, or the cat gets it!
        • 4429
        • 429 Posts
        ok that makes sense. But what file/folder do i need to change the permissions on? I don’t know what file touch creates or where it stores it.
          • 26903
          • 1,336 Posts
          Looking at your code the $this->destCacheInfoFile is set here :-

          function httpCache($url, $destFile, $timeout=7200) {
          
          		$this->url = $url;
          
          		[b]$this->destFile = $destFile;
          
          		$this->destCacheInfoFile = $destFile . '.cacheinfo';[/b]
          
          		$this->timeout = $timeout;
          


          You need to find where this class is instantiated, i.e what script calls this one and look at the parameters passed, the file your after is $destfile, i.e. the second parameter.
            Use MODx, or the cat gets it!