Location: PHPKode > projects > Content*Builder > contentbuilder/lib/CB_xmldocument.class.php
<?php

/**
* XML Document class for backup / import / export CB-data
*
*
*
*/
class xmldocument
{
/* pre-settings */
/*     var $xmlNodeNames=array("root"=>"document",
                            "metainfo"=>"meta",
                            "articledata"=>"article",
                            "startlines" => array ("<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ? >",
                                                   "<!DOCTYPE mitarbeiter SYSTEM 'mitarbeiter'>"));
 */
    var $xmlHeader="<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ? >\n<!DOCTYPE CB_article SYSTEM 'CB_article'>";

// list of predefined XML-Node-Names in document; constructor will enhance this list
// with data delivered from clients, building a 3-level complete DOM-Tree
// Level deepness is represented by 1st level array position ("root"-element is level 0)
// this array structure defines CB XML Data Model in 1st and 2nd level ..
    var $xmlNodes=array(
                        array("root"=>array("name"=>"document",
                                            "parent"=>"root",
                                            "value"=>""
                                      )
                        ),
                        array("metainfo"=>array("name"=>"meta",
                                                "parent"=>"root",
                                                "value"=>""
                                          ),
                              "articledata"=>array("name"=>"article",
                                                   "parent"=>"root",
                                                   "value"=>""
                                             )
                        )
                  );


    var $xmlFileDir="xmldir"; /* maybe overwritten by function setXmlFileDir($dir) */

    var $xmlFileTime;  /* will be set in constructor, maybe overriden by function setXmlFileTime()*/

    var $safe_mode=FALSE;  /* if set to TRUE, working with id-hashed subdirs will be avoided
                              set to TRUE happens by default in constructor if safe_mode is switched On */

    var $xmlCDATANodeNames=array("title","intro","content","x_description","x_keywords"); // which xmlNodes contains CDATA content?

    var $xmlFileList=array();  // after calling member function listXmlFiles() this list contains xmlFileNames
    var $xmlDeepness=0;        // expat parser var: actual node deepnees
    var $xmlActiveNode="";     // expat parser var: actual node ...

    var $parser;  // Class-var for expat xml-parser object
    var $xmldata=array();
    var $xmlentity;

    //var $metainfo=array();
    //var $articledata=array();
    var $articleID="";
    var $cmsUser="";
    var $xmlFileName;

    /* Constructor of this class
    * Function loads article-data into class-var arrays (no XML at this point  ..) */
    function xmldocument($articleID, $cmsUser, $metainfo, $articledata){
        // set XML-file-dir, take care of safe_mode users ...
        if ((ini_get("safe_mode"))||($this->safe_mode===TRUE)){
            $this->safe_mode=TRUE;
        }else{
            $this->xmlFileDir.="/".$articleID;
        }
        // set $this->xmlFileTime
        $this->setXmlFileTimeFromTime(time());

        $this->articleID=$articleID;
        $this->cmsUser=$cmsUser;
        //$this->metainfo=$metainfo;
        //$this->articledata=$articledata;

        if (is_array($metainfo)){
            foreach ($metainfo as $key => $value){
                $this->xmlNodes[2][$key]["name"]=$key;
                $this->xmlNodes[2][$key]["parent"]=$this->xmlNodes[1]["metainfo"]["name"];
                $this->xmlNodes[2][$key]["value"]=$value;
            }
        }
        if (is_array($articledata)){
            foreach ($articledata as $key => $value){
                $this->xmlNodes[2][$key]["name"]=$key;
                $this->xmlNodes[2][$key]["parent"]=$this->xmlNodes[1]["articledata"]["name"];
                $this->xmlNodes[2][$key]["value"]=$value;
            }
        }

        // Initialisierung eines expat Parser-Objektes fuer das Einlesen von XML-Dateien
        $this->parser=xml_parser_create();
        xml_set_object($this->parser, $this);
        xml_parser_set_option($this->parser,XML_OPTION_CASE_FOLDING,0);
        xml_set_default_handler($this->parser, array(&$this, "xml_default_handler"));
        xml_set_element_handler($this->parser, array(&$this, "xml_start_element_handler"), array(&$this, "xml_stop_element_handler"));
        xml_set_character_data_handler($this->parser,array(&$this, "xml_value_handler"));
        register_shutdown_function(array(&$this, "xml_parser_free"));

        // only Maguma editor color display helper ...
        $this->xmlHeader=str_replace("? >","?".">",$this->xmlHeader);
    }

/* function listXmlFiles
* fuellt die array-Variable $xmlFileList mit den Dateinamen der gepeicherten XML-Dateien,
* die zum aktuellen Artikel gehoeren
* Gibt den Dateinamen des zuletzt gespeicherten XML zurueck (mit Pfadangabe) anhand
* des Zeitschluessels im Dateinamen
 */
 function listXmlFiles(){
    $regs=array();
    $newestFile="";
    if ((is_dir($this->xmlFileDir))&&($handle = opendir($this->xmlFileDir))) {
       while (false !== ($file = readdir($handle))) {
           $tmpID=$this->articleID;
           if (is_file($this->xmlFileDir."/".$file)){
               if (ereg("^".$tmpID."_(.+)[.]{1}xml$",$file,$regs)) {
                   $this->xmlFileList[]=$this->xmlFileDir."/".$file;
                  //trigger_error("\$file=".$file." \$regs[1]=".$regs[1]);
                  if ((! $newestFile)||(strcmp($regs[1],$newestFile)>0)) {
                      //trigger_error("\$newestFile='".$newestFile."' \$regs[1]='".$regs[1]."'");
                      $newestFile=$file;
                  }
               } else {
                  //trigger_error("Fehler bei \$file ".$file);
               }
           }
       }
       closedir($handle);
    }
    return $this->xmlFileDir."/".$newestFile;
}

/*
* function loadXMLFile($fileName)
* Loads XML from $fileName to data structure $xmlNodes using expat parser
* returns TRUE if XML-File was written, FALSE otherwise
* @return boolean TRUE|FALSE
*/
function loadXmlFile($fileName){
   // erzeuge Output-Dateiname, wenn durch das Objekt noch keiner erzeugt wurde ..
    if ((! $fileName) && (! $this->xmlFileName)) {
        $fileName=$this->listXmlFiles();
    }
    // fall out, if xml-file is not readable ...
    if (! is_file($fileName)) return FALSE;

//trigger_error("\$fileName=".$fileName);
 // get out all whitespaces, not neccessary to parse ...
    $data=ereg_replace(">"."[[:space:]]+"."<","><",implode('', file($fileName)));
//trigger_error("$fileName='".$data."'");
    if ($data){
         $this->xmlNodes=array(); // empty existing nodes-object
         $this->xmlDeepness=0;
         $this->xmlActiveNode=array();

        // let's parse via expat!!! actions are performed by handler functions defined in class constructor
         $ret=xml_parse($this->parser,$data,TRUE);
         if (! $ret){
            trigger_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 FALSE;  // we stranded in hell ...
         }
         return TRUE; // we are in heaven ...
    }
    //xml_parser_free($this->parser);
    //print_r($this->xmlNodes);
    //print_r($this->xmlActiveNode);
    //trigger_error("\$this->xmlHeader='".$this->xmlHeader."'");
    //trigger_error("\$this->xmlentity='".$this->xmlentity."'");
    return FALSE;
}

/* Handler functions for expat parser */
function xml_default_handler($p,$data){
    $this->xmlHeader .= $data;
}
function xml_start_element_handler($p,$name,$attrs){
    //trigger_error("aktueller nodename='".$name."'");
    $this->xmlDeepness++;
    $this->xmlActiveNode[$this->xmlDeepness] = $name;
    $this->xmlentity.="<".$name.">";
}
function xml_stop_element_handler($p,$name){
    $this->xmlDeepness--;
    //print_r($this->xmlNodes); echo "<hr>";
    $this->xmldata=$this->xmlNodes;
}
function xml_value_handler($p,$data){
    $tmpdata=$data;
    $activeNode=$this->xmlActiveNode[$this->xmlDeepness];
    $this->xmlNodes[$this->xmlDeepness][$activeNode]["name"]=$activeNode;
    $this->xmlNodes[$this->xmlDeepness][$activeNode]["value"].=$tmpdata;
    if ($this->xmlDeepness > 0){
        $deepness=$this->xmlDeepness - 1;
        $this->xmlNodes[$this->xmlDeepness][$activeNode]["parent"]=$this->xmlActiveNode[$deepness];
    }
    //print_r($this->xmlNodes); echo "<hr>";
}
function xml_parser_free() {
  xml_parser_free($this->parser);
  //trigger_error("shutdown...");
}


/**
* function saveXmlFile()
* Saves XML-File to <xml-dir>/<file-id>_yyyy-mm-dd_HH-MM-SS.xml  if safe_mode is enabled,
* otherwise it saves something more nice to <xml-dir>/<file-id>/<file-id>_yyyy-mm-dd_HH-MM-SS.xml
* this function needs class data objects to be set before (via Constructor or function set ...)
* if last saved article-xml is aequivalent, no saving takes place ...
* returns TRUE if XML-File was written, FALSE otherwise
* @return boolean TRUE|FALSE
*/
    function saveXmlFile()  {
        $oldContent="";
        $newContent="";
        $newestFile="";
        // erzeuge Output-Dateiname, wenn durch das Objekt noch keiner erzeugt wurde ..
        if (! $this->xmlFileName) {
            $this->generateFilename($this->articleID);
        }
        // suche die letzte geschriebene XML-Version des Artikels und lade diese ggf.
        if (($newestFile=$this->listXmlFiles())&&(is_file($newestFile))){
            $oldContent=ereg_replace("\\\r","",implode('', file($newestFile)));
        }

        // schreibe den neuen Content in eine String-Variable ...
        $newContent.=$this->xmlHeader."\n";
        $newContent.="<".$this->xmlNodes[0]["root"]["name"].">\n";
        foreach ($this->xmlNodes[1] as $akey => $avalues){
            $newContent.="<".$avalues["name"].">\n";
            foreach($this->xmlNodes[2] as $key => $values){
                //trigger_error(implode(":",$values));
                if ($values["parent"]==$avalues["name"]){
                    $newContent.="<".$values["name"].">";
                    // strings possibly containing html-markup needs special handling ...
                    if (in_array($values["name"],$this->xmlCDATANodeNames)){
                        $newContent.="<![CDATA[".$values["value"]."]]>";
                    }else{
                        $newContent.=htmlentities($values["value"]);
                    }
                    $newContent.="</".$values["name"].">\n";
                }
            }
            $newContent.="</".$avalues["name"].">\n";
        }
        $newContent.="</".$this->xmlNodes[0]["root"]["name"].">\n";
        // fertig: der gesamte XML_String ist zusammengebastelt ...
        // jetzt noch die Windows-Spaesse rausparsen ...
        $newContent=ereg_replace("\r","",$newContent);

        // Vergleich: wurden Daten geaendert? Nur in diesem Fall eine neue Datei schreiben..
        if (strcmp($oldContent,$newContent)!=0){
/*             trigger_error("oldContent='".$oldContent."' Laenge=".strlen($oldContent));
            trigger_error("Laenge=".strlen($oldContent));
            trigger_error("newContent='".$newContent."' Laenge=".strlen($newContent));
            for ($i=0;$i<strlen($newContent);$i++){
                if (substr($oldContent,$i,1) != substr($newContent,$i,1)){
                    trigger_error("Fehlerposition ".$i."startend bei '".substr($oldContent,$i,25)."' mit oldContent-Zeichen '".ord( substr($oldContent,$i,1) )."' und newContent-Zeichen '".ord( substr($newContent,$i,1) )."'");
                    break;
                }
            }
 */            if ($this->xmlFileName) {
               if ($fp=fopen($this->xmlFileName,"w")){
                   fputs($fp,$newContent,strlen($newContent));
                   fclose($fp);

                   return TRUE;
               }

/*                 fputs($fp,"<".$this->xmlNodes[0]["root"]["name"].">\n");
                foreach ($this->xmlNodes[1] as $akey => $avalues){
                    fputs($fp,"<".$avalues["name"].">\n");
                    foreach($this->xmlNodes[2] as $key => $values){
                        //trigger_error(implode(":",$values));
                        if ($values["parent"]==$avalues["name"]){
                            fputs($fp,"<".$values["name"].">");
                            $tmp=htmlspecialchars($values["value"]);
                            fputs($fp,$tmp,strlen($tmp));
                            fputs($fp,"</".$values["name"].">\n");
                        }
                    }
                    fputs($fp,"</".$avalues["name"].">\n");
                }

 *//*                 fputs($fp,"\t<".$this->xmlNodes[1]["articledata"]["name"].">\n");
                foreach($this->articledata as $key => $values){
                    fputs($fp,"\t\t<".$key.">");
                    $tmp=htmlspecialchars($values);
                    fputs($fp,$tmp,strlen($tmp));
                    fputs($fp,"</".$key.">\n");
                }
                fputs($fp,"\t</".$this->xmlNodes[1]["articledata"]["name"].">\n");
 */
/*                 fputs($fp,"</".$this->xmlNodes[0]["root"]["name"].">\n");

                fclose($fp);

                return TRUE;
 */
            }
        }
        return FALSE;
    }

/* Function takes unix time in seconds and sets $this->xmlFileTime to formatted string.
* If you already have an appropriate prepared string, just use $this->xmlFileTime
* function setXmlFileTimeFromString($time)
* directly from your external code */
     function setXmlFileTimeFromTime($time){
         if ($tmp=date("Y-m-d_H-i-s",$time)){
            $this->xmlFileTime=$tmp;
         }
     }
     function setXmlFileTimeFromString($time){
        if ($time) $this->xmlFileTime=$time;
    }

/* Funktion fuer die Generierung eines XML-Dateinamens ...
* maybe more for class-internal usage ... */
    function generateFilename($articleID) {
        if (! is_dir($this->xmlFileDir)){
                umask(0000);
                mkdir($this->xmlFileDir,0777);
        }
        $this->xmlFileName=$this->xmlFileDir."/".$articleID."_".$this->xmlFileTime.".xml";
    }

/* setup xmlFileDir overrides default class-var $xmlFileDir ... */
    function setXmlFileDir($dir){
        if (is_dir($dir)) $this->xmlFileDir=$dir;
    }
/* returns member-var $this->xmldata ... */
    function get_xmldata(){
        return $this->xmldata;
    }
/* returns member-var $this->xmlFileList ... */
    function get_xmlFileList(){
        return $this->xmlFileList;
    }
}



?>

Return current item: Content*Builder