protected function getcapabilities()
 {
     $result = parent::getcapabilities();
     if ($result->cached) {
         return $result;
     }
     $data = $result->data;
     if (empty($data) or floor($result->code / 100) >= 4) {
         jMessage::add('Server Error !', 'Error');
         return $this->serviceException();
     }
     if (preg_match('#ServiceExceptionReport#i', $data)) {
         return $result;
     }
     // Replace qgis server url in the XML (hide real location)
     $sUrl = jUrl::getFull("lizmap~service:index", array("repository" => $this->repository->getKey(), "project" => $this->project->getKey()));
     $sUrl = str_replace('&', '&', $sUrl);
     preg_match('/<get>.*\\n*.+xlink\\:href="(.+)"/i', $data, $matches);
     if (count($matches) < 2) {
         preg_match('/get onlineresource="(.+)"/i', $data, $matches);
     }
     if (count($matches) > 1) {
         $data = str_replace($matches[1], $sUrl, $data);
     }
     $data = str_replace('&amp;&amp;', '&amp;', $data);
     // Add response to cache
     $cacheId = $this->repository->getKey() . '_' . $this->project->getKey() . '_' . $this->param('service');
     $newhash = md5_file(realpath($this->repository->getPath()) . '/' . $this->project->getKey() . ".qgs");
     jCache::set($cacheId . '_hash', $newhash);
     jCache::set($cacheId . '_mime', $result->mime);
     jCache::set($cacheId . '_data', $data);
     return (object) array('code' => 200, 'mime' => $result->mime, 'data' => $data, 'cached' => False);
 }
 protected function getcapabilities()
 {
     $result = parent::getcapabilities();
     if ($result->cached) {
         return $result;
     }
     $data = $result->data;
     if (empty($data) or floor($result->code / 100) >= 4) {
         jMessage::add('Server Error !', 'Error');
         return $this->serviceException();
     }
     if (preg_match('#ServiceExceptionReport#i', $data)) {
         return $result;
     }
     // Remove no interoparable elements
     $data = preg_replace('@<GetPrint[^>]*?>.*?</GetPrint>@si', '', $data);
     $data = preg_replace('@<ComposerTemplates[^>]*?>.*?</ComposerTemplates>@si', '', $data);
     // Replace qgis server url in the XML (hide real location)
     $sUrl = jUrl::getFull("lizmap~service:index", array("repository" => $this->repository->getKey(), "project" => $this->project->getKey()));
     $sUrl = str_replace('&', '&amp;', $sUrl);
     preg_match('/<get>.*\\n*.+xlink\\:href="(.+)"/i', $data, $matches);
     if (count($matches) < 2) {
         preg_match('/get onlineresource="(.+)"/i', $data, $matches);
     }
     if (count($matches) > 1) {
         $data = str_replace($matches[1], $sUrl, $data);
     }
     $data = str_replace('&amp;&amp;', '&amp;', $data);
     if (preg_match('@WMS_Capabilities@i', $data)) {
         // Update namespace
         $schemaLocation = "http://www.opengis.net/wms";
         $schemaLocation .= " http://schemas.opengis.net/wms/1.3.0/capabilities_1_3_0.xsd";
         $schemaLocation .= " http://www.opengis.net/sld";
         $schemaLocation .= " http://schemas.opengis.net/sld/1.1.0/sld_capabilities.xsd";
         $schemaLocation .= " http://www.qgis.org/wms";
         $schemaLocation .= " " . $sUrl . "SERVICE=WMS&amp;REQUEST=GetSchemaExtension";
         $data = preg_replace('@xsi:schemaLocation=".*?"@si', 'xsi:schemaLocation="' . $schemaLocation . '"', $data);
         if (!preg_match('@xmlns:qgs@i', $data)) {
             $data = preg_replace('@xmlns="http://www.opengis.net/wms"@', 'xmlns="http://www.opengis.net/wms" xmlns:qgs="http://www.qgis.org/wms"', $data);
             $data = preg_replace('@GetStyles@', 'qgs:GetStyles', $data);
         }
         if (!preg_match('@xmlns:sld@i', $data)) {
             $data = preg_replace('@xmlns="http://www.opengis.net/wms"@', 'xmlns="http://www.opengis.net/wms" xmlns:sld="http://www.opengis.net/sld"', $data);
             $data = preg_replace('@GetLegendGraphic@', 'sld:GetLegendGraphic', $data);
         }
     }
     // Add response to cache
     $cacheId = $this->repository->getKey() . '_' . $this->project->getKey() . '_' . $this->param('service');
     $newhash = md5_file(realpath($this->repository->getPath()) . '/' . $this->project->getKey() . ".qgs");
     jCache::set($cacheId . '_hash', $newhash);
     jCache::set($cacheId . '_mime', $result->mime);
     jCache::set($cacheId . '_data', $data);
     return (object) array('code' => 200, 'mime' => $result->mime, 'data' => $data, 'cached' => False);
 }
 protected function getcapabilities()
 {
     //Get Cache
     $cacheId = $this->repository->getKey() . '_' . $this->project->getKey() . '_WMTS';
     $hash = jCache::get($cacheId . '_hash');
     $newhash = md5_file(realpath($this->repository->getPath()) . '/' . $this->project->getKey() . ".qgs");
     $tileMatrixSetList = jCache::get($cacheId . '_tilematrixsetlist');
     $layers = jCache::get($cacheId . '_layers');
     if (!$tileMatrixSetList || !$layers || $hash != $newhash) {
         $wmsRequest = new lizmapWMSRequest($this->project, array('service' => 'WMS', 'request' => 'GetCapabilities'));
         $wmsResult = $wmsRequest->process();
         $wms = $wmsResult->data;
         $wms_xml = simplexml_load_string($wms);
         $wms_xml->registerXPathNamespace("wms", "http://www.opengis.net/wms");
         $wms_xml->registerXPathNamespace("xlink", "http://www.w3.org/1999/xlink");
         $tileMatrixSetList = lizmapTiler::getTileMatrixSetList($this->project, $wms_xml);
         $cfgLayers = $this->project->getLayers();
         $layers = array();
         foreach ($cfgLayers as $n => $l) {
             if ($l->cached == 'True' && $l->singleTile != 'True' && strtolower($l->name) != 'overview') {
                 $layer = lizmapTiler::getLayerTileInfo($l->name, $this->project, $wms_xml, $tileMatrixSetList);
                 if ($layer) {
                     $layers[] = $layer;
                 }
             }
         }
         jCache::set($cacheId . '_hash', $newhash, 3600);
         jCache::set($cacheId . '_tilematrixsetlist', $tileMatrixSetList, 3600);
         jCache::set($cacheId . '_layers', $layers, 3600);
     }
     $sUrl = jUrl::getFull("lizmap~service:index", array("repository" => $this->repository->getKey(), "project" => $this->project->getKey()));
     $tpl = new jTpl();
     $tpl->assign('url', $sUrl);
     $tpl->assign('repository', $this->param('repository'));
     $tpl->assign('project', $this->param('project'));
     $tpl->assign('tileMatrixSetList', $tileMatrixSetList);
     $tpl->assign('layers', $layers);
     return (object) array('code' => 200, 'mime' => 'text/xml', 'data' => $tpl->fetch('lizmap~wmts_capabilities'), 'cached' => False);
 }
예제 #4
0
 public function testGarbage()
 {
     $this->assertFalse(jCache::garbage());
     jCache::set('remainingDataKey', 'remaining data', 0, $this->profile);
     jCache::set('garbage1DataKey', 'data send to the garbage', 1, $this->profile);
     jCache::set('garbage2DataKey', 'other data send to the garbage', strtotime("-1 day"), $this->profile);
     sleep(2);
     $this->assertTrue(jCache::garbage($this->profile));
 }
예제 #5
0
 public function save()
 {
     foreach ($this->containers as $key => $container) {
         jCache::set($key, serialize($container), null, 'jforms');
     }
 }
예제 #6
0
 protected function getAnonymousRight($subject, $resource = '-')
 {
     if (empty($resource)) {
         $resource = '-';
     }
     if ($this->anonacl === null) {
         $rights = jCache::get('acl2dbanon/rights', 'acl2db');
         if ($rights === false) {
             // let's load rights for anonymous group
             $dao = jDao::get('jacl2db~jacl2rights', 'jacl2_profile');
             $this->anonacl = array();
             foreach ($dao->getAllAnonymousRights() as $rec) {
                 if (isset($this->anonacl[$rec->id_aclsbj])) {
                     if ($rec->canceled) {
                         $this->anonacl[$rec->id_aclsbj] = false;
                     }
                 } else {
                     $this->anonacl[$rec->id_aclsbj] = $rec->canceled ? false : true;
                 }
             }
             jCache::set('acl2dbanon/rights', $this->anonacl, null, 'acl2db');
         } else {
             $this->anonacl = $rights;
         }
     }
     if (!isset($this->anonacl[$subject])) {
         $this->anonacl[$subject] = false;
         jCache::set('acl2dbanon/rights', $this->anonacl, null, 'acl2db');
     }
     // no resource given, just return the global right for the given subject
     if ($resource === '-') {
         return $this->anonacl[$subject];
     }
     if (!isset($this->anonaclres[$subject])) {
         $rights = jCache::get('acl2dbanon/rightsres/' . $subject, 'acl2db');
         if ($rights !== false) {
             $this->anonaclres[$subject] = $rights;
         }
     }
     // if we already have loaded the corresponding right, returns it
     if (isset($this->anonaclres[$subject][$resource])) {
         return $this->anonaclres[$subject][$resource];
     }
     // default right for the resource is the global right
     $this->anonaclres[$subject][$resource] = $this->anonacl[$subject];
     // if the general right is not given, check the specific right for the resource
     if (!$this->anonacl[$subject]) {
         $dao = jDao::get('jacl2db~jacl2rights', 'jacl2_profile');
         $right = $dao->getAnonymousRightWithRes($subject, $resource);
         $this->anonaclres[$subject][$resource] = $right != false ? $right->canceled ? false : true : false;
         jCache::set('acl2dbanon/rightsres/' . $subject, $this->anonaclres[$subject], null, 'acl2db');
         return $this->anonaclres[$subject][$resource];
     } else {
         jCache::set('acl2dbanon/rightsres/' . $subject, $this->anonaclres[$subject], null, 'acl2db');
         return true;
     }
 }
예제 #7
0
 /**
  * Get data from map service or from the cache.
  * @param lizmapProject $project The project.
  * @param array $params Array of parameters.
  * @return array $data Normalized and filtered array.
  */
 public static function getMap($project, $params, $forced = False)
 {
     // Get cache if exists
     $keyParams = array();
     foreach ($params as $pk => $value) {
         if (in_array($pk, array("bbox", "format", "height", "layers", "transparent"))) {
             $keyParams[$pk] = $value;
         }
     }
     ksort($keyParams);
     $layers = str_replace(',', '_', $params['layers']);
     $crs = preg_replace('#[^a-zA-Z0-9_]#', '_', $params['crs']);
     // Get repository data
     $ser = lizmap::getServices();
     $lrep = $project->getRepository();
     $lproj = $project;
     $project = $lproj->getKey();
     $repository = $lrep->getKey();
     // Change to true to put some information in debug files
     $debug = $ser->debugMode;
     // Read config file for the current project
     $layername = $params["layers"];
     $configLayers = $lproj->getLayers();
     $configLayer = null;
     if (property_exists($configLayers, $layername)) {
         $configLayer = $configLayers->{$layername};
     }
     // Set or get tile from the parent project in case of embedded layers
     if ($configLayer and property_exists($configLayer, 'sourceRepository') and property_exists($configLayer, 'sourceProject')) {
         $newRepository = (string) $configLayer->sourceRepository;
         $newProject = (string) $configLayer->sourceProject;
         $repository = $newRepository;
         $project = $newProject;
         $lrep = lizmap::getRepository($repository);
         if (!$lrep) {
             jMessage::add('The repository ' . strtoupper($repository) . ' does not exist !', 'RepositoryNotDefined');
             return array('error', 'text/plain', '404');
         }
         try {
             $lproj = lizmap::getProject($repository . '~' . $project);
             if (!$lproj) {
                 jMessage::add('The lizmapProject ' . strtoupper($project) . ' does not exist !', 'ProjectNotDefined');
                 return array('error', 'text/plain', '404');
             }
         } catch (UnknownLizmapProjectException $e) {
             jLog::logEx($e, 'error');
             jMessage::add('The lizmapProject ' . strtoupper($project) . ' does not exist !', 'ProjectNotDefined');
             return array('error', 'text/plain', '404');
         }
     }
     $key = md5(serialize($keyParams));
     // Get tile cache virtual profile (tile storage)
     // And get tile if already in cache
     // --> must be done after checking that parent project is involved
     $profile = lizmapProxy::createVirtualProfile($repository, $project, $layers, $crs);
     if ($debug) {
         lizmap::logMetric('LIZMAP_PROXY_READ_LAYER_CONFIG');
     }
     // Has the user asked for cache for this layer ?
     $useCache = False;
     if ($configLayer) {
         $useCache = strtolower($configLayer->cached) == 'true';
     }
     // Avoid using cache for requests concerning not square tiles or too big
     // Focus on real web square tiles
     $wmsClient = 'web';
     if ($useCache and $params['width'] != $params['height'] and ($params['width'] > 300 or $params['height'] > 300)) {
         $wmsClient = 'gis';
         $useCache = False;
     }
     if ($useCache and !$forced) {
         $tile = jCache::get($key, $profile);
         if ($tile) {
             $_SESSION['LIZMAP_GETMAP_CACHE_STATUS'] = 'read';
             $mime = 'image/jpeg';
             if (preg_match('#png#', $params['format'])) {
                 $mime = 'image/png';
             }
             if ($debug) {
                 lizmap::logMetric('LIZMAP_PROXY_HIT_CACHE');
             }
             return array($tile, $mime, 200);
         }
     }
     // ***************************
     // No cache hit : need to ask the tile from QGIS Server
     // ***************************
     // Construction of the WMS url : base url + parameters
     $url = $ser->wmsServerURL . '?';
     // Add project path into map parameter
     $params["map"] = realpath($lproj->getQgisPath());
     // Metatile : if needed, change the bbox
     // Avoid metatiling when the cache is not active for the layer
     $metatileSize = '1,1';
     if ($configLayer and property_exists($configLayer, 'metatileSize')) {
         if (preg_match('#^[3579],[3579]$#', $configLayer->metatileSize)) {
             $metatileSize = $configLayer->metatileSize;
         }
     }
     # Metatile buffer
     $metatileBuffer = 5;
     // Also checks if gd is installed
     if ($metatileSize and $useCache and $wmsClient == 'web' and extension_loaded('gd') && function_exists('gd_info')) {
         # Metatile Size
         $metatileSizeExp = explode(',', $metatileSize);
         $metatileSizeX = (int) $metatileSizeExp[0];
         $metatileSizeY = (int) $metatileSizeExp[1];
         # Get requested bbox
         $bboxExp = explode(',', $params['bbox']);
         $width = $bboxExp[2] - $bboxExp[0];
         $height = $bboxExp[3] - $bboxExp[1];
         # Calculate factors
         $xFactor = (int) ($metatileSizeX / 2);
         $yFactor = (int) ($metatileSizeY / 2);
         # Calculate the new bbox
         $xmin = $bboxExp[0] - $xFactor * $width - $metatileBuffer * $width / $params["width"];
         $ymin = $bboxExp[1] - $yFactor * $height - $metatileBuffer * $height / $params["height"];
         $xmax = $bboxExp[2] + $xFactor * $width + $metatileBuffer * $width / $params["width"];
         $ymax = $bboxExp[3] + $yFactor * $height + $metatileBuffer * $height / $params["height"];
         # Replace request bbox by metatile bbox
         $params["bbox"] = "{$xmin},{$ymin},{$xmax},{$ymax}";
         # Keep original param value
         $originalParams = array("width" => $params["width"], "height" => $params["height"]);
         # Replace width and height before requesting the image from qgis
         $params["width"] = $metatileSizeX * $params["width"] + 2 * $metatileBuffer;
         $params["height"] = $metatileSizeY * $params["height"] + 2 * $metatileBuffer;
     }
     // Build params before send the request to Qgis
     $builtParams = http_build_query($params);
     // Replace needed characters (not needed for php >= 5.4, just use the 4th parameter of the method http_build_query)
     $a = array('+', '_', '.', '-');
     $b = array('%20', '%5F', '%2E', '%2D');
     $builtParams = str_replace($a, $b, $builtParams);
     // Get data from the map server
     $proxyMethod = $ser->proxyMethod;
     $getRemoteData = lizmapProxy::getRemoteData($url . $builtParams, $proxyMethod, $debug);
     $data = $getRemoteData[0];
     $mime = $getRemoteData[1];
     $code = $getRemoteData[2];
     if ($debug) {
         lizmap::logMetric('LIZMAP_PROXY_REQUEST_QGIS_MAP');
     }
     if ($useCache && !preg_match('/^image/', $mime)) {
         $useCache = False;
     }
     // Metatile : if needed, crop the metatile into a single tile
     // Also checks if gd is installed
     if ($metatileSize and $useCache and $wmsClient == 'web' and extension_loaded('gd') && function_exists('gd_info')) {
         # Save original content into an image var
         $original = imagecreatefromstring($data);
         # crop parameters
         $newWidth = (int) $originalParams["width"];
         // px
         $newHeight = (int) $originalParams["height"];
         // px
         $positionX = (int) ($xFactor * $originalParams["width"]) + $metatileBuffer;
         // left translation of 30px
         $positionY = (int) ($yFactor * $originalParams["height"]) + $metatileBuffer;
         // top translation of 20px
         # create new gd image
         $image = imageCreateTrueColor($newWidth, $newHeight);
         # save transparency if needed
         if (preg_match('#png#', $params['format'])) {
             imagesavealpha($original, true);
             imagealphablending($image, false);
             $color = imagecolortransparent($image, imagecolorallocatealpha($image, 0, 0, 0, 127));
             imagefill($image, 0, 0, $color);
             imagesavealpha($image, true);
         }
         # crop image
         imagecopyresampled($image, $original, 0, 0, $positionX, $positionY, $newWidth, $newHeight, $newWidth, $newHeight);
         # Output the image as a string (use PHP buffering)
         ob_start();
         if (preg_match('#png#', $params['format'])) {
             imagepng($image, null, 9);
         } else {
             imagejpeg($image, null, 90);
         }
         $data = ob_get_contents();
         // read from buffer
         ob_end_clean();
         // delete buffer
         // Destroy image handlers
         imagedestroy($original);
         imagedestroy($image);
         if ($debug) {
             lizmap::logMetric('LIZMAP_PROXY_CROP_METATILE');
         }
     }
     $_SESSION['LIZMAP_GETMAP_CACHE_STATUS'] = 'off';
     // Store into cache if needed
     if ($useCache) {
         //~ jLog::log( ' Store into cache');
         $cacheExpiration = (int) $ser->cacheExpiration;
         if (property_exists($configLayer, 'cacheExpiration')) {
             $cacheExpiration = (int) $configLayer->cacheExpiration;
         }
         jCache::set($key, $data, $cacheExpiration, $profile);
         $_SESSION['LIZMAP_GETMAP_CACHE_STATUS'] = 'write';
         if ($debug) {
             lizmap::logMetric('LIZMAP_PROXY_WRITE_CACHE');
         }
     }
     return array($data, $mime, $code);
 }
 /**
  * Get data from map service or from the cache.
  * @param string $repository The repository.
  * @param string $project The project.
  * @param array $params Array of parameters.
  * @return array $data Normalized and filtered array.
  */
 public static function getServiceData($repository, $project, $params)
 {
     // Get cache if exists
     $keyParams = $params;
     if (array_key_exists('map', $keyParams)) {
         unset($keyParams['map']);
     }
     ksort($keyParams);
     $key = md5(serialize($keyParams));
     $layers = str_replace(',', '_', $params['layers']);
     $crs = preg_replace('#[^a-zA-Z0-9_]#', '_', $params['crs']);
     // Get repository data
     $ser = lizmap::getServices();
     $lrep = lizmap::getRepository($repository);
     $lproj = lizmap::getProject($repository . '~' . $project);
     // Change to true to put some information in debug files
     $debug = $ser->debugMode;
     // Read config file for the current project
     $layername = $params["layers"];
     $configLayers = $lproj->getLayers();
     $configLayer = null;
     if (property_exists($configLayers, $layername)) {
         $configLayers->{$layername};
     }
     // Set or get tile from the parent project in case of embedded layers
     if ($configLayer and property_exists($configLayer, 'sourceRepository') and property_exists($configLayer, 'sourceProject')) {
         $newRepository = (string) $configLayer->sourceRepository;
         $newProject = (string) $configLayer->sourceProject;
         $repository = $newRepository;
         $project = $newProject;
         $lrep = lizmap::getRepository($repository);
         $lproj = lizmap::getProject($repository . '~' . $project);
     }
     // Get tile cache virtual profile (tile storage)
     // And get tile if already in cache
     // --> must be done after checking that parent project is involved
     $profile = 'lizmapCache_' . $repository . '_' . $project . '_' . $layers . '_' . $crs;
     lizmapCache::createVirtualProfile($repository, $project, $layers, $crs);
     $tile = jCache::get($key, $profile);
     // Return tile if cache hit !
     if ($tile) {
         //~ jLog::log( 'cache hit !');
         return $tile;
     }
     // Has the user asked for cache for this layer ?
     $string2bool = array('false' => False, 'False' => False, 'True' => True, 'true' => True);
     $useCache = False;
     if ($configLayer) {
         $string2bool[$configLayer->cached];
     }
     // Avoid using cache for requests concerning not square tiles or too big
     // Focus on real web square tiles
     $wmsClient = 'web';
     if ($useCache and $params['width'] != $params['height'] and ($params['width'] > 300 or $params['height'] > 300)) {
         $wmsClient = 'gis';
         $useCache = False;
     }
     // ***************************
     // No cache hit : need to ask the tile from QGIS Server
     // ***************************
     // Construction of the WMS url : base url + parameters
     $url = $ser->wmsServerURL . '?';
     // Add project path into map parameter
     $params["map"] = realpath($lrep->getPath()) . '/' . $lproj->getKey() . ".qgs";
     // Metatile : if needed, change the bbox
     // Avoid metatiling when the cache is not active for the layer
     $metatileSize = '1,1';
     if ($configLayer and property_exists($configLayer, 'metatileSize')) {
         if (preg_match('#^[3579],[3579]$#', $configLayer->metatileSize)) {
             $metatileSize = $configLayer->metatileSize;
         }
     }
     # Metatile buffer
     $metatileBuffer = 5;
     // Also checks if gd is installed
     if ($metatileSize and $useCache and $wmsClient == 'web' and extension_loaded('gd') && function_exists('gd_info')) {
         # Metatile Size
         $metatileSizeExp = explode(',', $metatileSize);
         $metatileSizeX = (int) $metatileSizeExp[0];
         $metatileSizeY = (int) $metatileSizeExp[1];
         # Get requested bbox
         $bboxExp = explode(',', $params['bbox']);
         $width = $bboxExp[2] - $bboxExp[0];
         $height = $bboxExp[3] - $bboxExp[1];
         # Calculate factors
         $xFactor = (int) ($metatileSizeX / 2);
         $yFactor = (int) ($metatileSizeY / 2);
         # Calculate the new bbox
         $xmin = $bboxExp[0] - $xFactor * $width - $metatileBuffer * $width / $params["width"];
         $ymin = $bboxExp[1] - $yFactor * $height - $metatileBuffer * $height / $params["height"];
         $xmax = $bboxExp[2] + $xFactor * $width + $metatileBuffer * $width / $params["width"];
         $ymax = $bboxExp[3] + $yFactor * $height + $metatileBuffer * $height / $params["height"];
         # Replace request bbox by metatile bbox
         $params["bbox"] = "{$xmin},{$ymin},{$xmax},{$ymax}";
         # Keep original param value
         $originalParams = array("width" => $params["width"], "height" => $params["height"]);
         # Replace width and height before requesting the image from qgis
         $params["width"] = $metatileSizeX * $params["width"] + 2 * $metatileBuffer;
         $params["height"] = $metatileSizeY * $params["height"] + 2 * $metatileBuffer;
     }
     // Build params before send the request to Qgis
     $builtParams = http_build_query($params);
     // Replace needed characters (not needed for php >= 5.4, just use the 4th parameter of the method http_build_query)
     $a = array('+', '_', '.', '-');
     $b = array('%20', '%5F', '%2E', '%2D');
     $builtParams = str_replace($a, $b, $builtParams);
     // Get data from the map server
     $proxyMethod = $ser->proxyMethod;
     $getRemoteData = lizmapCache::getRemoteData($url . $builtParams, $proxyMethod, $debug);
     $data = $getRemoteData[0];
     $mime = $getRemoteData[1];
     if ($useCache && !preg_match('/^image/', $mime)) {
         $useCache = False;
     }
     // Metatile : if needed, crop the metatile into a single tile
     // Also checks if gd is installed
     if ($metatileSize and $useCache and $wmsClient == 'web' and extension_loaded('gd') && function_exists('gd_info')) {
         # Save original content into an image var
         $original = imagecreatefromstring($data);
         # crop parameters
         $newWidth = (int) $originalParams["width"];
         // px
         $newHeight = (int) $originalParams["height"];
         // px
         $positionX = (int) ($xFactor * $originalParams["width"]) + $metatileBuffer;
         // left translation of 30px
         $positionY = (int) ($yFactor * $originalParams["height"]) + $metatileBuffer;
         // top translation of 20px
         # create new gd image
         $image = imageCreateTrueColor($newWidth, $newHeight);
         # save transparency if needed
         if (preg_match('#png#', $params['format'])) {
             imagesavealpha($original, true);
             imagealphablending($image, false);
             $color = imagecolortransparent($image, imagecolorallocatealpha($image, 0, 0, 0, 127));
             imagefill($image, 0, 0, $color);
             imagesavealpha($image, true);
         }
         # crop image
         imagecopyresampled($image, $original, 0, 0, $positionX, $positionY, $newWidth, $newHeight, $newWidth, $newHeight);
         # Output the image as a string (use PHP buffering)
         ob_start();
         if (preg_match('#png#', $params['format'])) {
             imagepng($image, null);
         } else {
             imagejpeg($image, null, 80);
         }
         $data = ob_get_contents();
         // read from buffer
         ob_end_clean();
         // delete buffer
         // Destroy image handlers
         imagedestroy($original);
         imagedestroy($image);
     }
     // Store into cache if needed
     if ($useCache) {
         //~ jLog::log( ' Store into cache');
         $cacheExpiration = (int) $ser->cacheExpiration;
         if (property_exists($configLayer, 'cacheExpiration')) {
             $cacheExpiration = (int) $configLayer->cacheExpiration;
         }
         jCache::set($key, $data, $cacheExpiration, $profile);
     }
     return $data;
 }
 /**
  * constructor
  * @param string $key : the project name
  * @param lizmapRepository $ rep : the repository
  */
 public function __construct($key, $rep)
 {
     $this->key = $key;
     $this->repository = $rep;
     $file = $rep->getPath() . $key . '.qgs';
     // Verifying if the files exist
     if (!file_exists($file)) {
         throw new UnknownLizmapProjectException('The QGIS project ' . $file . ' does not exist!');
     }
     if (!file_exists($file . '.cfg')) {
         throw new UnknownLizmapProjectException('The lizmap config ' . $file . '.cfg does not exist!');
     }
     // For the cache key, we use the full path of the project file
     // to avoid collision in the cache engine
     $data = false;
     try {
         $data = jCache::get($file, 'qgisprojects');
     } catch (Exception $e) {
         // if qgisprojects profile does not exist, or if there is an
         // other error about the cache, let's log it
         jLog::log($e->getMessage(), 'error');
     }
     if ($data === false || $data['qgsmtime'] < filemtime($file) || $data['qgscfgmtime'] < filemtime($file . '.cfg')) {
         // FIXME reading XML could take time, so many process could
         // read it and construct the cache at the same time. We should
         // have a kind of lock to avoid this issue.
         $this->readXml($key, $rep);
         $data['qgsmtime'] = filemtime($file);
         $data['qgscfgmtime'] = filemtime($file . '.cfg');
         foreach ($this->cachedProperties as $prop) {
             $data[$prop] = $this->{$prop};
         }
         try {
             jCache::set($file, $data, null, 'qgisprojects');
         } catch (Exception $e) {
             jLog::log($e->getMessage(), 'error');
         }
     } else {
         foreach ($this->cachedProperties as $prop) {
             $this->{$prop} = $data[$prop];
         }
     }
 }