Skip to content
Permalink
Browse files

First GGZ public beta version

  • Loading branch information...
boguslaw.szczepanowski
boguslaw.szczepanowski committed Oct 21, 2014
1 parent bd2bbda commit 48785cb68ff95983b9e4eb064082be9a7a40ce8a
@@ -41,6 +41,7 @@ class OkapiServiceRunner
'services/caches/save_personal_notes',
'services/caches/formatters/gpx',
'services/caches/formatters/garmin',
'services/caches/formatters/ggz',
'services/caches/map/tile',
'services/logs/entries',
'services/logs/entry',
@@ -0,0 +1,107 @@
<?php
namespace okapi\services\caches\formatters\ggz;
use okapi\Okapi;
use okapi\Cache;
use okapi\Settings;
use okapi\OkapiRequest;
use okapi\OkapiHttpResponse;
use okapi\OkapiInternalRequest;
use okapi\OkapiServiceRunner;
use okapi\BadRequest;
use okapi\ParamMissing;
use okapi\InvalidParam;
use okapi\OkapiAccessToken;
use okapi\services\caches\search\SearchAssistant;
use \ZipArchive;
use \Exception;
require_once($GLOBALS['rootpath']."okapi/services/caches/formatters/gpx.php");
class WebService
{
private static $shutdown_function_registered = false;
private static $files_to_unlink = array();
public static function options()
{
return array(
'min_auth_level' => 1
);
}
public static function call(OkapiRequest $request)
{
$gpx_result = \okapi\services\caches\formatters\gpx\WebService::create_gpx(
$request,
\okapi\services\caches\formatters\gpx\WebService::FLAG_CREATE_GGZ_IDX
);
$tempfilename = Okapi::get_var_dir()."/garmin".time().rand(100000,999999).".zip";
$zip = new ZipArchive();
if ($zip->open($tempfilename, ZIPARCHIVE::CREATE) !== true)
throw new Exception("ZipArchive class could not create temp file $tempfilename. Check permissions!");
# Include a GPX file compatible with Garmin devices. It should include all
# Geocaching.com (groundspeak:) and Opencaching.com (ox:) extensions. It will
# also include personal data (if the method was invoked using Level 3 Authentication).
$file_item_name = "data_".time()."_".rand(100000,999999).".gpx";
$ggz_file = array(
'name' => $file_item_name,
'crc32' => sprintf('%08X', crc32($gpx_result['gpx'])),
'caches' => $gpx_result['ggz_index']
);
$vars = array();
$vars['files'] = array($ggz_file);
ob_start();
include 'ggzindex.tpl.php';
$index_content = ob_get_clean();
//$zip->addEmptyDir("index");
//$zip->addEmptyDir("index/com");
//$zip->addEmptyDir("index/com/garmin");
//$zip->addEmptyDir("index/com/garmin/geocaches");
//$zip->addEmptyDir("index/com/garmin/geocaches/v0");
$zip->addFromString("index/com/garmin/geocaches/v0/index.xml", $index_content);
//$zip->addEmptyDir("data");
$zip->addFromString("data/".$file_item_name, $gpx_result['gpx']);
$zip->close();
# The result could be big. Bigger than our memory limit. We will
# return an open file stream instead of a string. We also should
# set a higher time limit, because downloading this response may
# take some time over slow network connections (and I'm not sure
# what is the PHP's default way of handling such scenario).
set_time_limit(600);
$response = new OkapiHttpResponse();
$response->content_type = "application/x-ggz; charset=utf-8";
$response->content_disposition = 'attachment; filename="geocaches.ggz"';
$response->stream_length = filesize($tempfilename);
$response->body = fopen($tempfilename, "rb");
$response->allow_gzip = false;
self::add_file_to_unlink($tempfilename);
return $response;
}
private static function add_file_to_unlink($filename)
{
if (!self::$shutdown_function_registered)
register_shutdown_function(array("okapi\\services\\caches\\formatters\\ggz\\WebService", "unlink_temporary_files"));
self::$files_to_unlink[] = $filename;
}
public static function unlink_temporary_files()
{
foreach (self::$files_to_unlink as $filename)
@unlink($filename);
self::$files_to_unlink = array();
}
}
@@ -0,0 +1,18 @@
<xml>
<brief>Retrieve GGZ file for newer Garmin devices</brief>
<issue-id>323</issue-id>
<desc>
<p><b>Important note:</b> This method is in <b>beta version</b>. It's interface may change
in a backward-incompatible manner, or it may even be removed.</p>
<p>Produce a GGZ file (which is actually a zip file) with content compatible with newer
Geocaching-enabled Garmin GPS devices.</p>
<p>The method bahaves exactly as
<a href="%OKAPI:methodref:services/caches/formatters/gpx%">services/caches/formatters/gpx</a>
method, and takes the same parameters. Only output format is different.
</p>
</desc>
<import-params method='services/caches/formatters/gpx'/>
<returns>
<p>A GGZ file. You should copy the file to Garmin's internal memory storage.</p>
</returns>
</xml>
@@ -0,0 +1,43 @@
<?
namespace okapi\services\caches\formatters\ggz;
use okapi\Okapi;
echo '<?xml version="1.0" encoding="utf-8"?>'."\n";
?>
<ggz xmlns="http://www.opencaching.com/xmlschemas/ggz/1/0">
<time><?= date('c') ?></time>
<? foreach ($vars['files'] as $f) { ?>
<file>
<name><?= $f['name'] ?></name>
<crc><?= $f['crc32'] ?></crc>
<time><?= date('c') ?></time>
<?
foreach ($f['caches'] as $c) {
?><gch>
<code><?= $c['code'] ?></code>
<name><?= Okapi::xmlescape($c['name']) ?></name>
<type><?= Okapi::xmlescape($c['type']) ?></type>
<lat><?= $c['lat'] ?></lat>
<lon><?= $c['lon'] ?></lon>
<file_pos><?= $c['file_pos'] ?></file_pos>
<file_len><?= $c['file_len'] ?></file_len>
<? if (isset($c['ratings'])) {
?><ratings>
<?
foreach ($c['ratings'] as $rating_key => $rating_val){
echo "<$rating_key>$rating_val</$rating_key>\n";
}
?>
</ratings><?
}
if (isset($c['found']) && $c['found']) { ?>
<found>true</found>
<? } ?>
</gch>
<? } ?>
</file>
<? } ?>
</ggz>
@@ -54,7 +54,33 @@ public static function options()
'other' => 'Other',
);
/**
* Flag for create_gpx() method, which enables GGZ index geneation. The index
* is returned under 'ggz_index' key.
* @var int
*/
const FLAG_CREATE_GGZ_IDX = 1;
public static function call(OkapiRequest $request)
{
$response = new OkapiHttpResponse();
$response->content_type = "application/gpx; charset=utf-8";
$response->content_disposition = 'attachment; filename="results.gpx"';
$result_ref = self::create_gpx($request);
$response->body = &$result_ref['gpx'];
return $response;
}
/**
* Generates GPX file
* @param OkapiRequest $request
* @param integer $flags
* @throws BadRequest
* @return An array with GPX file content under 'gpx' key
*/
public static function create_gpx(OkapiRequest $request, $flags = null)
{
$vars = array();
@@ -387,15 +413,74 @@ public static function call(OkapiRequest $request)
}
}
}
# Store index data for GGZ format
$ggz_index = array();
if ($flags & self::FLAG_CREATE_GGZ_IDX){
foreach ($vars['caches'] as &$cache_ref)
{
if (!isset($cache_ref['ggz_index'])) {
$cache_ref['ggz_index'] = array();
}
$index_ref = &$cache_ref['ggz_index'];
$index_ref['code'] = $cache_ref['code'];
$index_ref['name'] = isset($cache_ref['name_2']) ? $cache_ref['name_2'] : $cache_ref['name'];
$index_ref['type'] = $vars['cache_GPX_types'][$cache_ref['type']];
list($lat, $lon) = explode("|", $cache_ref['location']);
$index_ref['lat'] = $lat;
$index_ref['lon'] = $lon;
$index_ref['ratings'] = array();
$ratings_ref = &$index_ref['ratings'];
if (isset($cache_ref['rating'])){
$ratings_ref['awesomeness'] = $cache_ref['rating'];
}
$ratings_ref['difficulty'] = $cache_ref['difficulty'];
if (!isset($cache_ref['size'])) {
$ratings_ref['size'] = 0; // Virtual, Event
} else if ($cache_ref['oxsize'] !== null) { // is this ox size one-to-one?
$ratings_ref['size'] = $cache_ref['oxsize'];
}
$ratings_ref['terrain'] = $cache_ref['terrain'];
if ($vars['mark_found'] && $cache_ref['is_found']) {
$index_ref['found'] = true;
}
$ggz_index[] = &$index_ref;
# Process additional waypoints - should we do this
if (isset($cache_ref['alt_wpts'])){
$idx = 1;
foreach ($cache_ref['alt_wpts'] as &$alt_wpt_ref) {
if (!isset($alt_wpt_ref['ggz_index'])) {
$alt_wpt_ref['ggz_index'] = array();
}
$index_ref = &$alt_wpt_ref['ggz_index'];
$index_ref['code'] = $cache_ref['code'] . '-' . $idx;
$index_ref['name'] = $alt_wpt_ref['type_name'];
$index_ref['type'] = $alt_wpt_ref['sym'];
list($lat, $lon) = explode("|", $alt_wpt_ref['location']);
$index_ref['lat'] = $lat;
$index_ref['lon'] = $lon;
$ggz_index[] = &$index_ref;
$idx++;
}
}
}
}
$response = new OkapiHttpResponse();
$response->content_type = "application/gpx; charset=utf-8";
$response->content_disposition = 'attachment; filename="results.gpx"';
ob_start();
Okapi::gettext_domain_init(explode("|", $langpref)); # Consumer gets properly localized GPX file.
include 'gpxfile.tpl.php';
Okapi::gettext_domain_restore();
$response->body = ob_get_clean();
return $response;
$result = array('gpx' => ob_get_clean());
if ($flags & self::FLAG_CREATE_GGZ_IDX){
$result['ggz_index'] = $ggz_index;
}
return $result;
}
}
@@ -22,9 +22,14 @@
<url><?= $vars['installation']['site_url'] ?></url>
<urlname><?= $vars['installation']['site_name'] ?></urlname>
<time><?= date('c') ?></time>
<? foreach ($vars['caches'] as $c) { ?>
<? list($lat, $lon) = explode("|", $c['location']); ?>
<wpt lat="<?= $lat ?>" lon="<?= $lon ?>">
<? foreach ($vars['caches'] as &$cache_ref) { ?>
<?
if (isset($cache_ref['ggz_index'])){
$cache_ref['ggz_index']['file_pos'] = ob_get_length();
}
$c = $cache_ref;
list($lat, $lon) = explode("|", $c['location']);
?><wpt lat="<?= $lat ?>" lon="<?= $lon ?>">
<time><?= $c['date_created'] ?></time>
<name><?= $c['code'] ?></name>
<desc><?= Okapi::xmlescape(isset($c['name_2']) ? $c['name_2'] : $c['name']) ?> <?= _("hidden by") ?> <?= Okapi::xmlescape($c['owner']['username']) ?> :: <?= ucfirst($c['type']) ?> Cache (<?= $c['difficulty'] ?>/<?= $c['terrain'] ?><? if ($c['size'] !== null) { echo "/".$c['size']; } else { echo "/X"; } ?>/<?= $c['rating'] ?>)</desc>
@@ -183,10 +188,21 @@
</ox:opencaching>
<? } ?>
</wpt>
<?
if (isset($cache_ref['ggz_index'])){
$cache_ref['ggz_index']['file_len'] = ob_get_length() - $cache_ref['ggz_index']['file_pos'];
}
?>
<? if ($vars['alt_wpts']) { ?>
<? foreach ($c['alt_wpts'] as $wpt) { ?>
<? list($lat, $lon) = explode("|", $wpt['location']); ?>
<wpt lat="<?= $lat ?>" lon="<?= $lon ?>">
<? foreach ($cache_ref['alt_wpts'] as &$wpt_ref) { ?>
<?
if (isset($wpt_ref['ggz_index'])){
$wpt_ref['ggz_index']['file_pos'] = ob_get_length();
}
$wpt = $wpt_ref;
list($lat, $lon) = explode("|", $wpt['location']);
?><wpt lat="<?= $lat ?>" lon="<?= $lon ?>">
<time><?= $c['date_created'] ?></time>
<name><?= Okapi::xmlescape($wpt['name']) ?></name>
<cmt><?= Okapi::xmlescape($wpt['description']) ?></cmt>
@@ -201,7 +217,11 @@
</gsak:wptExtension>
<? } ?>
</wpt>
<? } ?>
<?
if (isset($wpt_ref['ggz_index'])){
$wpt_ref['ggz_index']['file_len'] = ob_get_length() - $wpt_ref['ggz_index']['file_pos'];
}
} ?>
<? } ?>
<? } ?>
</gpx>

0 comments on commit 48785cb

Please sign in to comment.
You can’t perform that action at this time.