Example #1
0
 /**
  * Constructor which load an existent lab or create an empty one.
  *
  * @param	  string  $f                  the file of the lab with full path
  * @param	  int     $tenant             Tenant ID
  * @return	  void
  */
 public function __construct($f, $tenant)
 {
     $modified = False;
     if (!is_file($f)) {
         // File does not exist, create a new empty lab
         $this->filename = basename($f);
         $this->path = dirname($f);
         $this->tenant = (int) $tenant;
         if (!checkLabFilename($this->filename)) {
             // Invalid filename
             error_log('ERROR: ' . $f . ' ' . $GLOBALS['messages'][20001]);
             throw new Exception('20001');
         }
         if (!checkLabPath($this->path)) {
             // Invalid path
             error_log('ERROR: ' . $f . ' ' . $GLOBALS['messages'][20002]);
             throw new Exception('20002');
         }
         $this->name = substr(basename($f), 0, -4);
         $this->id = genUuid();
         $modified = True;
     } else {
         // Load the existent lab
         $this->filename = basename($f);
         $this->path = dirname($f);
         $this->tenant = (int) $tenant;
         if (!checkLabFilename($this->filename)) {
             // Invalid filename
             error_log('ERROR: ' . $f . ' ' . $GLOBALS['messages'][20001]);
             throw new Exception('20001');
         }
         if (!checkLabPath($this->path)) {
             // Invalid path
             error_log('ERROR: ' . $f . ' ' . $GLOBALS['messages'][20002]);
             throw new Exception('20002');
         }
         libxml_use_internal_errors(true);
         $xml = simplexml_load_file($f);
         if (!$xml) {
             // Invalid XML document
             error_log('ERROR: ' . $f . ' ' . $GLOBALS['messages'][20003]);
             throw new Exception('20003');
         }
         // Lab name
         $result = $xml->xpath('//lab/@name');
         if (empty($result)) {
             // Invalid UNetLab file (attribute is missing)
             error_log('ERROR: ' . $f . ' ' . $GLOBALS['messages'][20004]);
             throw new Exception('20004');
             return;
         } else {
             if (!checkLabName($result[0])) {
                 // Attribute not valid
                 error_log('ERROR: ' . $f . ' ' . $GLOBALS['messages'][20005]);
                 throw new Exception('20005');
                 return;
             } else {
                 $this->name = (string) $result[0];
             }
         }
         // Lab ID
         $result = $xml->xpath('//lab/@id');
         if (empty($result)) {
             // Lab ID not set, create a new one
             $this->id = genUuid();
             error_log('WARNING: ' . $f . ' ' . $GLOBALS['messages'][20011]);
             $modified = True;
         } else {
             if (!checkUuid($result[0])) {
                 // Attribute not valid
                 $this->id = genUuid();
                 error_log('WARNING: ' . $f . ' ' . $GLOBALS['messages'][20012]);
                 $modified = True;
             } else {
                 $this->id = (string) $result[0];
             }
         }
         // Lab description
         $result = (string) array_pop($xml->xpath('//lab/description'));
         if (strlen($result) !== 0) {
             $this->description = htmlspecialchars($result, ENT_DISALLOWED, 'UTF-8', TRUE);
         } else {
             if (strlen($result) !== 0) {
                 error_log('WARNING: ' . $f . ' ' . $GLOBALS['messages'][20006]);
             }
         }
         // Lab author
         $result = (string) array_pop($xml->xpath('//lab/@author'));
         if (strlen($result) !== 0) {
             $this->author = htmlspecialchars($result, ENT_DISALLOWED, 'UTF-8', TRUE);
         } else {
             if (strlen($result) !== 0) {
                 error_log('WARNING: ' . $f . ' ' . $GLOBALS['messages'][20007]);
             }
         }
         // Lab version
         $result = (string) array_pop($xml->xpath('//lab/@version'));
         if (strlen($result) !== 0 && (int) $result >= 0) {
             $this->version = $result;
         } else {
             if (strlen($result) !== 0) {
                 error_log('WARNING: ' . $f . ' ' . $GLOBALS['messages'][20008]);
             }
         }
         // Lab networks
         foreach ($xml->xpath('//lab/topology/networks/network') as $network) {
             $w = array();
             if (isset($network->attributes()->id)) {
                 $w['id'] = (string) $network->attributes()->id;
             }
             if (isset($network->attributes()->left)) {
                 $w['left'] = (string) $network->attributes()->left;
             }
             if (isset($network->attributes()->name)) {
                 $w['name'] = (string) $network->attributes()->name;
             }
             if (isset($network->attributes()->top)) {
                 $w['top'] = (string) $network->attributes()->top;
             }
             if (isset($network->attributes()->type)) {
                 $w['type'] = (string) $network->attributes()->type;
             }
             try {
                 $this->networks[$w['id']] = new Network($w, $w['id'], $this->tenant);
             } catch (Exception $e) {
                 // Invalid network
                 error_log('WARNING: ' . $f . ':net' . $w['id'] . ' ' . $GLOBALS['messages'][20009]);
                 error_log((string) $e);
                 continue;
             }
         }
         // Lab nodes (networks must be alredy loaded)
         foreach ($xml->xpath('//lab/topology/nodes/node') as $node_id => $node) {
             $n = array();
             if (isset($node->attributes()->config)) {
                 $n['config'] = (string) $node->attributes()->config;
             }
             if (isset($node->attributes()->console)) {
                 $n['console'] = (string) $node->attributes()->console;
             }
             if (isset($node->attributes()->cpu)) {
                 $n['cpu'] = (int) $node->attributes()->cpu;
             }
             if (isset($node->attributes()->delay)) {
                 $n['delay'] = (string) $node->attributes()->delay;
             }
             if (isset($node->attributes()->ethernet)) {
                 $n['ethernet'] = (int) $node->attributes()->ethernet;
             }
             if (isset($node->attributes()->icon)) {
                 $n['icon'] = (string) $node->attributes()->icon;
             }
             if (isset($node->attributes()->id)) {
                 $n['id'] = (int) $node->attributes()->id;
             }
             if (isset($node->attributes()->idlepc)) {
                 $n['idlepc'] = (string) $node->attributes()->idlepc;
             }
             if (isset($node->attributes()->image)) {
                 $n['image'] = (string) $node->attributes()->image;
             }
             if (isset($node->attributes()->left)) {
                 $n['left'] = (string) $node->attributes()->left;
             }
             if (isset($node->attributes()->name)) {
                 $n['name'] = (string) $node->attributes()->name;
             }
             if (isset($node->attributes()->nvram)) {
                 $n['nvram'] = (int) $node->attributes()->nvram;
             }
             if (isset($node->attributes()->ram)) {
                 $n['ram'] = (int) $node->attributes()->ram;
             }
             if (isset($node->attributes()->serial)) {
                 $n['serial'] = (int) $node->attributes()->serial;
             }
             if (isset($node->attributes()->template)) {
                 $n['template'] = (string) $node->attributes()->template;
             }
             if (isset($node->attributes()->top)) {
                 $n['top'] = (string) $node->attributes()->top;
             }
             if (isset($node->attributes()->type)) {
                 $n['type'] = (string) $node->attributes()->type;
             }
             if (isset($node->attributes()->uuid)) {
                 $n['uuid'] = (string) $node->attributes()->uuid;
             }
             try {
                 $this->nodes[$n['id']] = new Node($n, $n['id'], $this->tenant, $this->id);
             } catch (Exception $e) {
                 // Invalid node
                 error_log('WARNING: ' . $f . ':node' . $n['id'] . ' ' . $GLOBALS['messages'][20010]);
                 error_log((string) $e);
                 continue;
             }
             // Slot must be loaded before interfaces
             foreach ($node->slot as $slot) {
                 // Loading configured slots for this node
                 $s = array();
                 if (isset($slot->attributes()->id)) {
                     $s['id'] = (string) $slot->attributes()->id;
                 }
                 if (isset($slot->attributes()->module)) {
                     $s['module'] = (string) $slot->attributes()->module;
                 }
                 if ($this->nodes[$n['id']]->setSlot($s['id'], $s['module']) !== 0) {
                     error_log('WARNING: ' . $f . ':node' . $n['id'] . ':slot' . $s['id'] . ' ' . $GLOBALS['messages'][20013]);
                 }
             }
             foreach ($node->interface as $interface) {
                 // Loading configured interfaces for this node
                 $i = array();
                 if (isset($interface->attributes()->id)) {
                     $i['id'] = (string) $interface->attributes()->id;
                 }
                 if (isset($interface->attributes()->network_id)) {
                     $i['network_id'] = (string) $interface->attributes()->network_id;
                 }
                 if (isset($interface->attributes()->remote_id)) {
                     $i['remote_id'] = (string) $interface->attributes()->remote_id;
                 }
                 if (isset($interface->attributes()->remote_if)) {
                     $i['remote_if'] = (string) $interface->attributes()->remote_if;
                 }
                 if (isset($interface->attributes()->remote_host)) {
                     $i['remote_host'] = (string) $interface->attributes()->remote_host;
                 }
                 if (isset($interface->attributes()->type)) {
                     $i['type'] = (string) $interface->attributes()->type;
                 }
                 switch ($i['type']) {
                     default:
                         error_log('WARNING: ' . $f . ':node' . $n['id'] . ':inv' . $s['id'] . ' ' . $GLOBALS['messages'][20016]);
                         break;
                     case 'ethernet':
                         if ($this->nodes[$n['id']]->linkInterface($i) !== 0) {
                             error_log('WARNING: ' . $f . ':node' . $n['id'] . ':eth' . $i['id'] . ' ' . $GLOBALS['messages'][20014]);
                         }
                         break;
                     case 'serial':
                         // Serial
                         if ($this->nodes[$n['id']]->linkInterface($i) !== 0) {
                             error_log('WARNING: ' . $f . ':node' . $n['id'] . ':ser' . $i['id'] . ' ' . $GLOBALS['messages'][20015]);
                         }
                         break;
                 }
             }
         }
         // startup-config
         foreach ($xml->xpath('//lab/objects/configs/config') as $config) {
             $node_id = 0;
             $config_data = '';
             if (isset($config->attributes()->id)) {
                 $node_id = (string) $config->attributes()->id;
             }
             $result = (string) array_pop($config->xpath('.'));
             if (strlen($result) > 0) {
                 $config_data = base64_decode($result);
             }
             $rc = $this->nodes[$node_id]->setConfigData($config_data);
             if ($rc != 0) {
                 error_log('WARNING: ' . $f . ':cfg' . $node_id . ' ' . $GLOBALS['messages'][20037]);
                 continue;
             }
         }
         // Lab Pictures
         foreach ($xml->xpath('//lab/objects/pictures/picture') as $picture) {
             $p = array();
             if (isset($picture->attributes()->id)) {
                 $p['id'] = (string) $picture->attributes()->id;
             }
             if (isset($picture->attributes()->name)) {
                 $p['name'] = (string) $picture->attributes()->name;
             }
             if (isset($picture->attributes()->type)) {
                 $p['type'] = (string) $picture->attributes()->type;
             }
             $result = (string) array_pop($picture->xpath('./data'));
             if (strlen($result) > 0) {
                 $p['data'] = base64_decode($result);
             }
             $result = (string) array_pop($picture->xpath('./map'));
             if (strlen($result) > 0) {
                 $p['map'] = html_entity_decode($result);
             }
             try {
                 $this->pictures[$p['id']] = new Picture($p, $p['id']);
             } catch (Exception $e) {
                 // Invalid picture
                 error_log('WARNING: ' . $f . ':pic' . $p['id'] . ' ' . $GLOBALS['messages'][20020]);
                 error_log((string) $e);
                 continue;
             }
         }
         // Update attached network count
         $this->setNetworkCount();
     }
     if ($modified) {
         // Need to save
         $rc = $this->save();
         if ($rc != 0) {
             throw new Exception($rc);
             return $rc;
         }
     }
     return 0;
 }
Example #2
0
 /**
  * Constructor which load an existent lab or create an empty one.
  *
  * @param	  string  $f                  the file of the lab with full path
  * @param	  int     $tenant             Tenant ID
  * @return	  void
  */
 public function __construct($f, $tenant)
 {
     $modified = False;
     if (!is_file($f)) {
         // File does not exist, create a new empty lab
         $this->filename = basename($f);
         $this->path = dirname($f);
         $this->tenant = (int) $tenant;
         if (!checkLabFilename($this->filename)) {
             // Invalid filename
             error_log(date('M d H:i:s ') . 'ERROR: ' . $f . ' ' . $GLOBALS['messages'][20001]);
             throw new Exception('20001');
         }
         if (!checkLabPath($this->path)) {
             // Invalid path
             error_log(date('M d H:i:s ') . 'ERROR: ' . $f . ' ' . $GLOBALS['messages'][20002]);
             throw new Exception('20002');
         }
         $this->name = substr(basename($f), 0, -4);
         $this->id = genUuid();
         $modified = True;
         $this->scripttimeout = 600;
     } else {
         // Load the existent lab
         $this->filename = basename($f);
         $this->path = dirname($f);
         $this->tenant = (int) $tenant;
         if (!checkLabFilename($this->filename)) {
             // Invalid filename
             error_log(date('M d H:i:s ') . 'ERROR: ' . $f . ' ' . $GLOBALS['messages'][20001]);
             throw new Exception('20001');
         }
         if (!checkLabPath($this->path)) {
             // Invalid path
             error_log(date('M d H:i:s ') . 'ERROR: ' . $f . ' ' . $GLOBALS['messages'][20002]);
             throw new Exception('20002');
         }
         libxml_use_internal_errors(true);
         $xml = simplexml_load_file($f);
         if (!$xml) {
             // Invalid XML document
             error_log(date('M d H:i:s ') . 'ERROR: ' . $f . ' ' . $GLOBALS['messages'][20003]);
             throw new Exception('20003');
         }
         // Lab name
         $patterns[0] = '/\\.unl$/';
         $replacements[0] = '';
         $this->name = preg_replace($patterns, $replacements, basename($f));
         // Lab ID
         $result = $xml->xpath('//lab/@id');
         if (empty($result)) {
             // Lab ID not set, create a new one
             $this->id = genUuid();
             error_log(date('M d H:i:s ') . 'WARNING: ' . $f . ' ' . $GLOBALS['messages'][20011]);
             $modified = True;
         } else {
             if (!checkUuid($result[0])) {
                 // Attribute not valid
                 $this->id = genUuid();
                 error_log(date('M d H:i:s ') . 'WARNING: ' . $f . ' ' . $GLOBALS['messages'][20012]);
                 $modified = True;
             } else {
                 $this->id = (string) $result[0];
             }
         }
         // Lab description
         $result = (string) array_pop($xml->xpath('//lab/description'));
         if (strlen($result) !== 0) {
             $this->description = htmlspecialchars($result, ENT_DISALLOWED, 'UTF-8', TRUE);
         } else {
             if (strlen($result) !== 0) {
                 error_log(date('M d H:i:s ') . 'WARNING: ' . $f . ' ' . $GLOBALS['messages'][20006]);
             }
         }
         // Lab body
         $result = (string) array_pop($xml->xpath('//lab/body'));
         if (strlen($result) !== 0) {
             $this->body = htmlspecialchars($result, ENT_DISALLOWED, 'UTF-8', TRUE);
         } else {
             if (strlen($result) !== 0) {
                 error_log(date('M d H:i:s ') . 'WARNING: ' . $f . ' ' . $GLOBALS['messages'][20006]);
             }
         }
         // Lab author
         $result = (string) array_pop($xml->xpath('//lab/@author'));
         if (strlen($result) !== 0) {
             $this->author = htmlspecialchars($result, ENT_DISALLOWED, 'UTF-8', TRUE);
         } else {
             if (strlen($result) !== 0) {
                 error_log(date('M d H:i:s ') . 'WARNING: ' . $f . ' ' . $GLOBALS['messages'][20007]);
             }
         }
         // Lab version
         $result = (string) array_pop($xml->xpath('//lab/@version'));
         if (strlen($result) !== 0 && (int) $result >= 0) {
             $this->version = $result;
         } else {
             if (strlen($result) !== 0) {
                 error_log(date('M d H:i:s ') . 'WARNING: ' . $f . ' ' . $GLOBALS['messages'][20008]);
             }
         }
         // Lab networks
         foreach ($xml->xpath('//lab/topology/networks/network') as $network) {
             $w = array();
             if (isset($network->attributes()->id)) {
                 $w['id'] = (string) $network->attributes()->id;
             }
             if (isset($network->attributes()->left)) {
                 $w['left'] = (string) $network->attributes()->left;
             }
             if (isset($network->attributes()->name)) {
                 $w['name'] = (string) $network->attributes()->name;
             }
             if (isset($network->attributes()->top)) {
                 $w['top'] = (string) $network->attributes()->top;
             }
             if (isset($network->attributes()->type)) {
                 $w['type'] = (string) $network->attributes()->type;
             }
             try {
                 $this->networks[$w['id']] = new Network($w, $w['id'], $this->tenant);
             } catch (Exception $e) {
                 // Invalid network
                 error_log(date('M d H:i:s ') . 'WARNING: ' . $f . ':net' . $w['id'] . ' ' . $GLOBALS['messages'][20009]);
                 error_log(date('M d H:i:s ') . (string) $e);
                 continue;
             }
         }
         // Lab nodes (networks must be alredy loaded)
         foreach ($xml->xpath('//lab/topology/nodes/node') as $node_id => $node) {
             $n = array();
             if (isset($node->attributes()->config)) {
                 $n['config'] = (string) $node->attributes()->config;
             }
             if (isset($node->attributes()->console)) {
                 $n['console'] = (string) $node->attributes()->console;
             }
             if (isset($node->attributes()->cpu)) {
                 $n['cpu'] = (int) $node->attributes()->cpu;
             }
             if (isset($node->attributes()->delay)) {
                 $n['delay'] = (string) $node->attributes()->delay;
             }
             if (isset($node->attributes()->ethernet)) {
                 $n['ethernet'] = (int) $node->attributes()->ethernet;
             }
             if (isset($node->attributes()->icon)) {
                 $n['icon'] = (string) $node->attributes()->icon;
             }
             if (isset($node->attributes()->id)) {
                 $n['id'] = (int) $node->attributes()->id;
             }
             if (isset($node->attributes()->idlepc)) {
                 $n['idlepc'] = (string) $node->attributes()->idlepc;
             }
             if (isset($node->attributes()->image)) {
                 $n['image'] = (string) $node->attributes()->image;
             }
             if (isset($node->attributes()->left)) {
                 $n['left'] = (string) $node->attributes()->left;
             }
             if (isset($node->attributes()->name)) {
                 $n['name'] = (string) $node->attributes()->name;
             }
             if (isset($node->attributes()->nvram)) {
                 $n['nvram'] = (int) $node->attributes()->nvram;
             }
             if (isset($node->attributes()->ram)) {
                 $n['ram'] = (int) $node->attributes()->ram;
             }
             if (isset($node->attributes()->serial)) {
                 $n['serial'] = (int) $node->attributes()->serial;
             }
             if (isset($node->attributes()->template)) {
                 $n['template'] = (string) $node->attributes()->template;
             }
             if (isset($node->attributes()->top)) {
                 $n['top'] = (string) $node->attributes()->top;
             }
             if (isset($node->attributes()->type)) {
                 $n['type'] = (string) $node->attributes()->type;
             }
             if (isset($node->attributes()->uuid)) {
                 $n['uuid'] = (string) $node->attributes()->uuid;
             }
             $n['config'] == 'Exported' ? $n['config'] = '1' : $n['config'];
             // Fix startup-config
             $n['config'] == 'None' ? $n['config'] = '0' : $n['config'];
             // Fix startup-config
             // If config is empty, force "None"
             $result = (string) array_pop($xml->xpath('//lab/objects/configs/config[@id="' . $n['id'] . '"]'));
             if (strlen($result) == 0) {
                 $n['config'] = 0;
                 $config_data = False;
             } else {
                 $config_data = base64_decode($result);
             }
             // F5 needs a first mac address
             if ($n['template'] == "bigip") {
                 if (isset($node->attributes()->firstmac)) {
                     $n['firstmac'] = (string) $node->attributes()->firstmac;
                 } else {
                     $n['firstmac'] = (string) '00:' . sprintf('%02x', $this->tenant) . ':' . sprintf('%02x', $this->id / 512) . ':' . sprintf('%02x', $this->id % 512) . ':00:10';
                 }
             }
             try {
                 $this->nodes[$n['id']] = new Node($n, $n['id'], $this->tenant, $this->id);
             } catch (Exception $e) {
                 // Invalid node
                 error_log(date('M d H:i:s ') . 'WARNING: ' . $f . ':node' . $n['id'] . ' ' . $GLOBALS['messages'][20010]);
                 error_log(date('M d H:i:s ') . (string) $e);
                 continue;
             }
             // Slot must be loaded before interfaces
             foreach ($node->slot as $slot) {
                 // Loading configured slots for this node
                 $s = array();
                 if (isset($slot->attributes()->id)) {
                     $s['id'] = (string) $slot->attributes()->id;
                 }
                 if (isset($slot->attributes()->module)) {
                     $s['module'] = (string) $slot->attributes()->module;
                 }
                 if ($this->nodes[$n['id']]->setSlot($s['id'], $s['module']) !== 0) {
                     error_log(date('M d H:i:s ') . 'WARNING: ' . $f . ':node' . $n['id'] . ':slot' . $s['id'] . ' ' . $GLOBALS['messages'][20013]);
                 }
             }
             foreach ($node->interface as $interface) {
                 // Loading configured interfaces for this node
                 $i = array();
                 if (isset($interface->attributes()->id)) {
                     $i['id'] = (string) $interface->attributes()->id;
                 }
                 if (isset($interface->attributes()->network_id)) {
                     $i['network_id'] = (string) $interface->attributes()->network_id;
                 }
                 if (isset($interface->attributes()->remote_id)) {
                     $i['remote_id'] = (string) $interface->attributes()->remote_id;
                 }
                 if (isset($interface->attributes()->remote_if)) {
                     $i['remote_if'] = (string) $interface->attributes()->remote_if;
                 }
                 if (isset($interface->attributes()->remote_host)) {
                     $i['remote_host'] = (string) $interface->attributes()->remote_host;
                 }
                 if (isset($interface->attributes()->type)) {
                     $i['type'] = (string) $interface->attributes()->type;
                 }
                 switch ($i['type']) {
                     default:
                         error_log(date('M d H:i:s ') . 'WARNING: ' . $f . ':node' . $n['id'] . ':inv' . $s['id'] . ' ' . $GLOBALS['messages'][20016]);
                         break;
                     case 'ethernet':
                         if ($this->nodes[$n['id']]->linkInterface($i) !== 0) {
                             error_log(date('M d H:i:s ') . 'WARNING: ' . $f . ':node' . $n['id'] . ':eth' . $i['id'] . ' ' . $GLOBALS['messages'][20014]);
                         }
                         break;
                     case 'serial':
                         // Serial
                         if ($this->nodes[$n['id']]->linkInterface($i) !== 0) {
                             error_log(date('M d H:i:s ') . 'WARNING: ' . $f . ':node' . $n['id'] . ':ser' . $i['id'] . ' ' . $GLOBALS['messages'][20015]);
                         }
                         break;
                 }
             }
             // startup-config (read before)
             if ($config_data !== False) {
                 $rc = $this->nodes[$n['id']]->setConfigData($config_data);
                 if ($rc != 0) {
                     error_log(date('M d H:i:s ') . 'WARNING: ' . $f . ':cfg' . $node_id . ' ' . $GLOBALS['messages'][20037]);
                 }
             }
         }
         // lab script timeout
         $result = (string) array_pop($xml->xpath('//lab/@scripttimeout'));
         if (strlen($result) !== 0 && (int) $result >= 300) {
             $this->scripttimeout = $result;
         } else {
             if (strlen($result) !== 0) {
                 error_log(date('M d H:i:s ') . 'WARNING: ' . $f . ' ' . $GLOBALS['messages'][20045]);
                 $this->scripttimeout = 300;
             }
         }
         // Lab Pictures
         foreach ($xml->xpath('//lab/objects/pictures/picture') as $picture) {
             $p = array();
             if (isset($picture->attributes()->id)) {
                 $p['id'] = (string) $picture->attributes()->id;
             }
             if (isset($picture->attributes()->name)) {
                 $p['name'] = (string) $picture->attributes()->name;
             }
             if (isset($picture->attributes()->type)) {
                 $p['type'] = (string) $picture->attributes()->type;
             }
             $result = (string) array_pop($picture->xpath('./data'));
             if (strlen($result) > 0) {
                 $p['data'] = base64_decode($result);
             }
             $result = (string) array_pop($picture->xpath('./map'));
             if (strlen($result) > 0) {
                 $p['map'] = html_entity_decode($result);
             }
             try {
                 $this->pictures[$p['id']] = new Picture($p, $p['id']);
             } catch (Exception $e) {
                 // Invalid picture
                 error_log(date('M d H:i:s ') . 'WARNING: ' . $f . ':pic' . $p['id'] . ' ' . $GLOBALS['messages'][20020]);
                 error_log(date('M d H:i:s ') . (string) $e);
                 continue;
             }
         }
         // Text Objects
         foreach ($xml->xpath('//lab/objects/textobjects/textobject') as $textobject) {
             $p = array();
             if (isset($textobject->attributes()->id)) {
                 $p['id'] = (string) $textobject->attributes()->id;
             }
             if (isset($textobject->attributes()->name)) {
                 $p['name'] = (string) $textobject->attributes()->name;
             }
             if (isset($textobject->attributes()->type)) {
                 $p['type'] = (string) $textobject->attributes()->type;
             }
             $result = (string) array_pop($textobject->xpath('./data'));
             if (strlen($result) > 0) {
                 $p['data'] = $result;
             }
             try {
                 $this->textobjects[$p['id']] = new TextObject($p, $p['id']);
             } catch (Exception $e) {
                 // Invalid picture
                 error_log(date('M d H:i:s ') . 'WARNING: ' . $f . ':obj' . $p['id'] . ' ' . $GLOBALS['messages'][20041]);
                 error_log(date('M d H:i:s ') . (string) $e);
                 continue;
             }
         }
         // Update attached network count
         $this->setNetworkCount();
     }
     if ($modified) {
         // Need to save
         $rc = $this->save();
         if ($rc != 0) {
             throw new Exception($rc);
             return $rc;
         }
     }
     return 0;
 }