Skip to content
This repository has been archived by the owner on Nov 15, 2020. It is now read-only.

Commit

Permalink
Merge pull request #50 from elricho/master
Browse files Browse the repository at this point in the history
ZipArchive errors now gracefully caught.
Iterate over devices in store rather than building one ginormous array.
Tweaks to benchmark script.
  • Loading branch information
elricho authored Dec 13, 2016
2 parents 28a22d6 + 68014ab commit f779d04
Show file tree
Hide file tree
Showing 7 changed files with 183 additions and 45 deletions.
32 changes: 30 additions & 2 deletions src/HD4.php
Original file line number Diff line number Diff line change
Expand Up @@ -386,8 +386,36 @@ function installArchive($file) {
return $this->setError(299, "Error : Failed to open ". $file." is the ZIP module installed ?");

$zip = new \ZipArchive();
if ($zip->open($file) === false)
return $this->setError(299, "Error : Failed to open ". $file);
$code = $zip->open($file);
if ($code !== true) {
switch($code) {
case \ZipArchive::ER_MULTIDISK : $msg = 'Multi-disk zip archives not supported.'; break;
case \ZipArchive::ER_RENAME : $msg = 'Renaming temporary file failed.'; break;
case \ZipArchive::ER_CLOSE : $msg = 'Closing zip archive failed.'; break;
case \ZipArchive::ER_SEEK : $msg = 'Seek error.'; break;
case \ZipArchive::ER_READ : $msg = 'Read error.'; break;
case \ZipArchive::ER_WRITE : $msg = 'Write error.'; break;
case \ZipArchive::ER_CRC : $msg = 'CRC error.'; break;
case \ZipArchive::ER_ZIPCLOSED : $msg = 'Containing zip archive was closed.'; break;
case \ZipArchive::ER_NOENT : $msg = 'No such file.'; break;
case \ZipArchive::ER_EXISTS : $msg = 'File already exists.'; break;
case \ZipArchive::ER_OPEN : $msg = 'Can\'t open file.'; break;
case \ZipArchive::ER_TMPOPEN : $msg = 'Failure to create temporary file.'; break;
case \ZipArchive::ER_ZLIB : $msg = 'Zlib error.'; break;
case \ZipArchive::ER_MEMORY : $msg = 'Memory allocation failure.'; break;
case \ZipArchive::ER_CHANGED : $msg = 'Entry has been changed.'; break;
case \ZipArchive::ER_COMPNOTSUPP : $msg = 'Compression method not supported.'; break;
case \ZipArchive::ER_EOF : $msg = 'Premature EOF.'; break;
case \ZipArchive::ER_INVAL : $msg = 'Invalid argument.'; break;
case \ZipArchive::ER_NOZIP : $msg = 'Not a zip archive.'; break;
case \ZipArchive::ER_INTERNAL : $msg = 'Internal error.'; break;
case \ZipArchive::ER_INCONS : $msg = 'Zip archive inconsistent.'; break;
case \ZipArchive::ER_REMOVE : $msg = 'Can\'t remove file.'; break;
case \ZipArchive::ER_DELETED : $msg = 'Entry has been deleted.'; break;
default : $msg = 'Unknown error.';
}
return $this->setError(299, "Error : Failed to open ". $file . ", Message : $msg, Code : $code");
}

for ($i = 0; $i < $zip->numFiles; $i++) {
$filename = $zip->getNameIndex($i);
Expand Down
53 changes: 19 additions & 34 deletions src/HDDevice.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,10 @@ function setConfig($config) {
*/
function localVendors() {
$this->reply = array();
$data = $this->fetchDevices();
if (empty($data))
return false;

$tmp = array();
foreach($data['devices'] as $item) {
$tmp[] = $item['Device']['hd_specs']['general_vendor'];
$i = 0;
foreach($this->Store as $device) {
$tmp[] = $device['Device']['hd_specs']['general_vendor'];
}
$this->reply['vendor'] = array_unique($tmp);
sort($this->reply['vendor']);
Expand All @@ -92,20 +89,16 @@ function localVendors() {
*/
function localModels($vendor) {
$this->reply = array();
$data = $this->fetchDevices();
if (empty($data))
return false;

$vendor = strtolower($vendor);
$tmp = array();
$trim = '';
foreach($data['devices'] as $item) {
if ($vendor === strtolower($item['Device']['hd_specs']['general_vendor'])) {
$tmp[] = $item['Device']['hd_specs']['general_model'];
foreach($this->Store as $device) {
if ($vendor === strtolower($device['Device']['hd_specs']['general_vendor'])) {
$tmp[] = $device['Device']['hd_specs']['general_model'];
}
$key = $vendor." ";
if (! empty($item['Device']['hd_specs']['general_aliases'])) {
foreach($item['Device']['hd_specs']['general_aliases'] as $alias_item) {
if (! empty($device['Device']['hd_specs']['general_aliases'])) {
foreach($device['Device']['hd_specs']['general_aliases'] as $alias_item) {
// Note : Position is 0, at the start of the string, NOT False.
$result = stripos($alias_item, $key);
if ($result == 0 && $result !== false) {
Expand All @@ -128,15 +121,11 @@ function localModels($vendor) {
*/
function localView($vendor, $model) {
$this->reply = array();
$data = $this->fetchDevices();
if (empty($data))
return false;

$vendor = strtolower($vendor);
$model = strtolower($model);
foreach($data['devices'] as $item) {
if ($vendor === strtolower($item['Device']['hd_specs']['general_vendor']) && $model === strtolower($item['Device']['hd_specs']['general_model'])) {
$this->reply['device'] = $item['Device']['hd_specs'];
foreach($this->Store as $device) {
if ($vendor === strtolower($device['Device']['hd_specs']['general_vendor']) && $model === strtolower($device['Device']['hd_specs']['general_model'])) {
$this->reply['device'] = $device['Device']['hd_specs'];
return $this->setError(0, 'OK');
}
}
Expand All @@ -152,32 +141,28 @@ function localView($vendor, $model) {
* @return bool true on success, false otherwise. Use getReply to inspect results on success.
*/
function localWhatHas($key, $value) {
$data = $this->fetchDevices();
if (empty($data))
return false;

$tmp = array();
$value = strtolower($value);
foreach($data['devices'] as $item) {
if (empty($item['Device']['hd_specs'][$key])) {
foreach($this->Store as $device) {
if (empty($device['Device']['hd_specs'][$key])) {
continue;
}

$match = false;
if (is_array($item['Device']['hd_specs'][$key])) {
foreach($item['Device']['hd_specs'][$key] as $check) {
if (is_array($device['Device']['hd_specs'][$key])) {
foreach($device['Device']['hd_specs'][$key] as $check) {
if (stristr($check, $value)) {
$match = true;
}
}
} elseif (stristr($item['Device']['hd_specs'][$key], $value)) {
} elseif (stristr($device['Device']['hd_specs'][$key], $value)) {
$match = true;
}

if ($match == true) {
$tmp[] = array('id' => $item['Device']['_id'],
'general_vendor' => $item['Device']['hd_specs']['general_vendor'],
'general_model' => $item['Device']['hd_specs']['general_model']);
$tmp[] = array('id' => $device['Device']['_id'],
'general_vendor' => $device['Device']['hd_specs']['general_vendor'],
'general_model' => $device['Device']['hd_specs']['general_model']);
}
}
$this->reply['devices'] = $tmp;
Expand Down
62 changes: 61 additions & 1 deletion src/HDStore.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,19 +35,23 @@

use HandsetDetection\HDCache;

class HDStore {
class HDStore implements \Iterator {
public $dirname = "hd40store";
var $path = "";
var $directory = "";
private $Cache = null;
private static $_instance = null;
private $config = array();
private $indexPosition = 0;
private $indexArray = array();

/**
* Constructor
*
**/
private function __construct() {
$this->indexPosition = 0;
$this->indexArray = array();
}

/**
Expand Down Expand Up @@ -200,4 +204,60 @@ function purge() {
}
return $this->Cache->purge();
}

/**
* Rewind - iterator for looping over the device list
*
* @param void
* @return void
**/
function rewind() {
$this->indexPosition = 0;
// Build the device list.
$this->indexArray = array();
foreach(glob($this->directory . DIRECTORY_SEPARATOR . 'Device*.json') as $file) {
$this->indexArray[] = preg_replace('/\.json$/', '', basename($file));
}
}

/**
* Current - return current device pointer
*
* @param void
* @return array device
**/
function current() {
$file = $this->indexArray[$this->indexPosition];
return $this->fetch($file);
}

/**
* Current - return current device key
*
* @param void
* @return string device
**/
function key() {
return $this->indexArray[$this->indexPosition];
}

/**
* Next - move to the next device
*
* @param void
* @return array device
**/
function next() {
++$this->indexPosition;
}

/**
* Valid - Is the current entry valid
*
* @param void
* @return array device
**/
function valid() {
return isset($this->indexArray[$this->indexPosition]);
}
}
22 changes: 15 additions & 7 deletions tests/benchmark.php
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
<?php
/**
* API Kit Benchmarker - Quick check to ensure local (ultimate) detection is performant.
**/

ini_set('display_errors', 1);
ini_set('max_execution_time', 120);
ini_set('memory_limit', "128M");
error_reporting(E_ALL | E_STRICT);

// Use composer autoloader
$loader = require '../vendor/autoload.php';
$loader->add('HandsetDetection', __DIR__.'/../src/');

//$configFile = 'hdconfig.php';
$configFile = "../hd4UltimateConfig.php";
$dataFile = "benchmarkData.txt";
Expand All @@ -21,14 +28,13 @@
if (@$hdconfig['username'] == "your_api_username")
die('Please configure your username, secret and site_id');

require_once('../HD4.php');
// Note : After running once comment out deviceFetchArchive so you don't keep downloading the 40Mb specs file.
$hd = new HandsetDetection\HD4($configFile);
//$hd->deviceFetchArchive();
$hd->deviceFetchArchive();

class FileException extends Exception {};

class Benchmark {

private $file;
private $time_start;
private $time;
Expand Down Expand Up @@ -56,13 +62,15 @@ private function getmicrotime() {
}

function flyThrough($hd) {
$hd->setup();
$this->time_start = $this->getmicrotime();

foreach($this->headers as $key => $device) {
$hd->setDetectVar("User-Agent", $device[0]);
$hd->setDetectVar("x-wap-profile", $device[1]);
$result = $hd->deviceDetect();
$headers = array();
$headers['user-agent'] = $device[0];
if (isset($device[1]))
$headers['x-wap-profile'] = $device[1];

$result = $hd->deviceDetect($headers);

if ($this->verbose) {
echo "<tr>";
Expand Down
5 changes: 4 additions & 1 deletion tests/benchmarkData.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1061,4 +1061,7 @@ SAMSUNG-SGH-i900Orange/RTIC1 (compatible; MSIE 6.0; Windows CE; IEMobile 7.11)|h
Mozilla/5.0 (Linux; U; Android 2.2; en-gb; HTC_DesireHD-orange-LS Build/FRF91)|http://www.htcmms.com.tw/Android/Common/Bravo/HTC_Desire_A8181.xml
Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_3_5 like Mac OS X; en_US) AppleWebKit (KHTML, like Gecko) Mobile [FBAN/FBForIPhone;FBAV/4.0.2;FBBV/4020.0;FBDV/iPhone3,1;FBMD/iPhone;FBSN/iPhone OS;FBSV/4.3.5;FBSS/2; FBCR/OrangeUK;FBID/phone;FBLC/en_US;FBSF/2.0]|
Mozilla/5.0 (Linux; U; Android 2.1-update1; cs-cz; SonyEricssonX10i Build/2.1.B.0.1) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17|http://wap.sonyericsson.com/UAprof/X10iR201.xml
NokiaC2-00/2.0 (03.42) Profile/MIDP-2.1 Configuration/CLDC-1.1|
NokiaC2-00/2.0 (03.42) Profile/MIDP-2.1 Configuration/CLDC-1.1|
Mozilla/5.0 (Linux; U; Android 2.2; en-gb; HTC_DesireHD-orange-LS Build/FRF91)|http://www.htcmms.com.tw/Android/Common/Bravo/HTC_Desire_A8181.xml
Mozilla/5.0 (compatible; 4SeoHuntBot; +http://4seohunt.biz/about.html)|
NokiaC2-00/2.0 (03.42) Profile/MIDP-2.1 Configuration/CLDC-1.1|
19 changes: 19 additions & 0 deletions tests/hd4Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,21 @@ function test_deviceDetectBIiPhoneOverlay() {
// ***************************************** Ultimate Tests ******************************************
// ***************************************************************************************************

/**
* Broken Archive Test
* @group ultimate
**/
function test_unzipBogusArchive() {
$hd = new HandsetDetection\HD4($this->ultimateConfig);
$hd->setTimeout(500);

file_put_contents('/tmp/test.zip', 'testy mc testery fish fish fish');
$result = $hd->installArchive('/tmp/test.zip');
$data = $hd->getReply();
$this->assertFalse($result);
$this->assertEquals(299, $data['status']);
}

/**
* Fetch Archive Test
* @group ultimate
Expand All @@ -710,6 +725,10 @@ function test_fetchArchive() {
$data = $hd->getRawReply();
$size = strlen($data);
echo "Downloaded $size bytes ";
if (! $result) {
$data = $hd->getReply();
print_r($data);
}
if ($size < 1000) {
$this->markTestSkipped($data);
} else {
Expand Down
35 changes: 35 additions & 0 deletions tests/hdStoreTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,41 @@ function testSingleton() {
$store->setConfig(array('filesdir' => '/tmp/storetest'));
$this->assertEquals($store2->directory, '/tmp/storetest/hd40store');
}

// Test iterability
function testIterability() {
$store = HandsetDetection\HDStore::getInstance();
$store->setConfig(array('filesdir' => '/tmp'), true);
$store->purge();

$tmpData = '{"Device":{"_id":"3454","hd_ops":{"is_generic":0,"stop_on_detect":0,"overlay_result_specs":0},"hd_specs":{"general_vendor":"Sagem","general_model":"MyX5-2","general_platform":"","general_image":"","general_aliases":"","general_eusar":"","general_battery":"","general_type":"","general_cpu":"","design_formfactor":"","design_dimensions":"","design_weight":0,"design_antenna":"","design_keyboard":"","design_softkeys":"","design_sidekeys":"","display_type":"","display_color":"","display_colors":"","display_size":"","display_x":"128","display_y":"160","display_other":"","memory_internal":"","memory_slot":"","network":"","media_camera":"","media_secondcamera":"","media_videocapture":"","media_videoplayback":"","media_audio":"","media_other":"","features":"","connectors":"","general_platform_version":"","general_browser":"","general_browser_version":"","general_language":"","general_platform_version_max":"","general_app":"","general_app_version":"","display_ppi":0,"display_pixel_ratio":0,"benchmark_min":0,"benchmark_max":0,"general_app_category":"","general_virtual":0,"display_css_screen_sizes":""}}}';
file_put_contents('Device_3454.json', $tmpData);
$store->moveIn('Device_3454.json', 'Device_3454.json');
$this->assertFileNotExists('Device_3454.json');
$this->assertFileExists($store->directory . DIRECTORY_SEPARATOR . 'Device_3454.json');

$tmpData = '{"Device":{"_id":"3455","hd_ops":{"is_generic":0,"stop_on_detect":0,"overlay_result_specs":0},"hd_specs":{"general_aliases":"","display_x":"120","display_y":"120","general_vendor":"Sagem","general_model":"MY X55","general_platform":"","general_image":"","network":"","general_type":"","general_eusar":"","general_battery":"","general_cpu":"","design_formfactor":"","design_dimensions":"","design_weight":0,"design_antenna":"","design_keyboard":"","design_softkeys":"","design_sidekeys":"","display_type":"","display_color":"","display_colors":"","display_size":"","display_other":"","memory_internal":"","memory_slot":"","media_camera":"","media_secondcamera":"","media_videocapture":"","media_videoplayback":"","media_audio":"","media_other":"","features":"","connectors":"","general_platform_version":"","general_browser":"","general_browser_version":"","general_language":"","general_platform_version_max":"","general_app":"","general_app_version":"","display_ppi":0,"display_pixel_ratio":0,"benchmark_min":0,"benchmark_max":0,"general_app_category":"","general_virtual":0,"display_css_screen_sizes":""}}}';
file_put_contents('Device_3455.json', $tmpData);
$store->moveIn('Device_3455.json', 'Device_3455.json');

$tmpData = '{"Device":{"_id":"3456","hd_ops":{"is_generic":0,"stop_on_detect":0,"overlay_result_specs":0},"hd_specs":{"general_vendor":"Sagem","general_model":"myX5-2v","general_platform":"","general_image":"","general_aliases":"","general_eusar":"","general_battery":"","general_type":"","general_cpu":"","design_formfactor":"","design_dimensions":"","design_weight":0,"design_antenna":"","design_keyboard":"","design_softkeys":"","design_sidekeys":"","display_type":"","display_color":"","display_colors":"","display_size":"","display_x":"128","display_y":"160","display_other":"","memory_internal":"","memory_slot":"","network":"","media_camera":"","media_secondcamera":"","media_videocapture":"","media_videoplayback":"","media_audio":"","media_other":"","features":"","connectors":"","general_platform_version":"","general_browser":"","general_browser_version":"","general_language":"","general_platform_version_max":"","general_app":"","general_app_version":"","display_ppi":0,"display_pixel_ratio":0,"benchmark_min":0,"benchmark_max":0,"general_app_category":"","general_virtual":0,"display_css_screen_sizes":""}}}';
file_put_contents('Device_3456.json', $tmpData);
$store->moveIn('Device_3456.json', 'Device_3456.json');

$tmp = array();
foreach($store as $key => $value) {
$tmp[$key] = $value;
}
$this->assertArrayHasKey('Device_3454', $tmp);
$this->assertArrayHasKey('Device_3455', $tmp);
$this->assertArrayHasKey('Device_3456', $tmp);

$this->assertArrayHasKey('Device', $tmp['Device_3454']);
$this->assertArrayHasKey('Device', $tmp['Device_3455']);
$this->assertArrayHasKey('Device', $tmp['Device_3456']);

$store->purge();
}
}


0 comments on commit f779d04

Please sign in to comment.