Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/tag_meged_pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
- name: Set up PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.3
php-version: 8.4
coverage: xdebug
tools: composer:v2

Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/test_pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
- name: Set up PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.3
php-version: 8.4
tools: composer:v2

- name: Checkout code
Expand Down Expand Up @@ -65,7 +65,7 @@ jobs:
- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: '20.x'
node-version: '22.x'

- name: Checkout code
uses: actions/checkout@v4
Expand Down Expand Up @@ -115,7 +115,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
php: ['8.3']
php: ['8.4']

steps:
- name: Set up PHP
Expand All @@ -128,7 +128,7 @@ jobs:
- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: '20.x'
node-version: '22.x'

- name: Checkout code
uses: actions/checkout@v4
Expand Down
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# Changelog

## 2025/03/29: version updated => 1.8.5

### what's changed

- Added `Uri::isReadable()` method.
- Added `Uri::isUri()` method.
- Added `Uri::getScheme()` method.
- Modified `Exif::get()` method to check readability of uri.
- Upgraded dependencies.

## 2025/01/04: version updated => 1.8.4

### what's changed
Expand Down
7 changes: 4 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "macocci7/php-photo-gps",
"version": "1.8.4",
"version": "1.8.5",
"description": "Retrieves EXIF GPS data from a photo.",
"type": "library",
"license": "MIT",
Expand All @@ -18,10 +18,11 @@
"minimum-stability": "stable",
"require": {
"nette/neon": "^3.4",
"intervention/image": "^3.10"
"intervention/image": "^3.11",
"guzzlehttp/guzzle": "^7.9"
},
"require-dev": {
"squizlabs/php_codesniffer": "^3.11",
"squizlabs/php_codesniffer": "^3.12",
"phpstan/phpstan": "^2.1",
"phpunit/phpunit": "^10.5",
"php-parallel-lint/php-parallel-lint": "1.4"
Expand Down
15 changes: 11 additions & 4 deletions src/Helpers/Exif.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,20 @@ public static function version(?string $version = null)
*/
public static function get(string $path)
{
if (!is_readable($path) && !Uri::isAvailable($path)) {
throw new \Exception("The file is not readable.");
}
if (Uri::isAvailable($path)) {
$isUri = Uri::isUri($path);
if ($isUri) {
if (!Uri::isAvailable($path)) {
$scheme = Uri::getScheme($path);
throw new \Exception("The scheme {$scheme} is unavailable.");
}
if (!Uri::isReadable($path)) {
throw new \Exception("The uri is not readable.");
}
if (!ini_get('allow_url_fopen')) {
ini_set('allow_url_fopen', '1');
}
} elseif (!is_readable($path)) {
throw new \Exception("The file is not readable.");
}
$exif = exif_read_data(
file: $path,
Expand Down
49 changes: 49 additions & 0 deletions src/Helpers/Uri.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Macocci7\PhpPhotoGps\Helpers;

use GuzzleHttp\Client;
use Macocci7\PhpPhotoGps\Helpers\Config;

/**
Expand All @@ -16,6 +17,9 @@ class Uri
*/
private static array|null $config;

private const URI_SCHEME_CHECK_PATTERN = '/^[A-Za-z0-9\+\-\.]+\:\/\//';
private const URI_SCHEME_RETRIEVE_PATTERN = '/^([A-Za-z0-9\+\-\.]+)\:\/\//';

/**
* init
* @return void
Expand Down Expand Up @@ -65,4 +69,49 @@ public static function isAvailable(string $uri)
}
return false;
}

/**
* judges if the uri is readable or not
* @param string $uri
* @return bool
*/
public static function isReadable(string $uri)
{
$client = new Client();
try {
$response = $client->request('HEAD', $uri);
if ($response->getStatusCode() === 200) {
return true;
}
return false;
} catch (\Exception $e) {
return false;
}
}

/**
* judges if the string is an uri or not
* this method checkes if the string starts with uri scheme or not
* @param string $string
* @return bool
* @see https://developer.mozilla.org/ja/docs/Web/URI/Reference/Schemes
*/
public static function isUri(string $string)
{
return preg_match(self::URI_SCHEME_CHECK_PATTERN, $string) === 1;
}

/**
* returns shceme
* @param string $uri
* @return string|null
*/
public static function getScheme(string $uri)
{
if (!static::isUri($uri)) {
return null;
}
preg_match(self::URI_SCHEME_RETRIEVE_PATTERN, $uri, $matches);
return $matches[1] ?? null;
}
}
26 changes: 26 additions & 0 deletions tests/Helpers/ExifTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,32 @@ public function test_get_can_return_exif_data_correctly(string $path, array $exp
$this->assertSame($value, Exif::get($path)[$tag]);
}

public static function provide_get_can_throw_exception_with_unreadable_paths(): array
{
return [
'local' => [
'uri' => '/no/such/file',
'message' => 'The file is not readable.',
],
'uri, unavaiable' => [
'uri' => 'ftps://macocci7.net/img/new-php-logo.png',
'message' => 'The scheme ftps is unavailable.',
],
'uri, unreadable' => [
'uri' => 'https://macocci7.net/no/such/file',
'message' => 'The uri is not readable.',
],
];
}

#[DataProvider('provide_get_can_throw_exception_with_unreadable_paths')]
public function test_get_can_throw_exception_with_unreadable_paths(string $uri, string $message): void
{
$this->expectException(\Exception::class);
$this->expectExceptionMessage($message);
Exif::get($uri);
}

public static function provide_byte2array_can_convert_value_correctly(): array
{
return [
Expand Down
160 changes: 160 additions & 0 deletions tests/Helpers/UriTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,164 @@ public function test_isAvailable_can_judge_correctly(string $uri, bool $expect):
{
$this->assertSame($expect, Uri::isAvailable($uri));
}

public static function provide_isReadable_can_judge_correctly(): array
{
return [
'http, 200' => [
'uri' => 'http://macocci7.net/',
'expect' => true,
],
'http, 404' => [
'uri' => 'http://macocci7.net/no-such-path',
'expect' => false,
],
'https, 200' => [
'uri' => 'https://macocci7.net/',
'expect' => true,
],
'https, 404' => [
'uri' => 'https://macocci7.net/no-such-path',
'expect' => false,
],
];
}

#[DataProvider('provide_isReadable_can_judge_correctly')]
public function test_isReadable_can_judge_correctly(string $uri, bool $expect): void
{
$this->assertSame($expect, Uri::isReadable($uri));
}

public static function provide_isUrl_can_judge_correctly(): array
{
return [
'empty string, false' => [
'string' => '',
'expect' => false,
],
'only lowercase letters, false' => [
'string' => 'hoge',
'expect' => false,
],
'only uppercase letters, false' => [
'string' => 'HOGE',
'expect' => false,
],
'only uppercase and lowercase letters, false' => [
'string' => 'Hoge',
'expect' => false,
],
'only alphabet and numbers, false' => [
'string' => 'Hoge123',
'expect' => false,
],
'alphabet, numbers and colon, false' => [
'string' => 'Hoge123:',
'expect' => false,
],
'alphabet, numbers, colon and slash, false' => [
'string' => 'Hoge123:/',
'expect' => false,
],
'alphabet, numbers, colon and double slash, true' => [
'string' => 'Hoge123://',
'expect' => true,
],
'without tdl, true' => [
'string' => 'http://foo/',
'expect' => true,
],
'alphabet and +, true' => [
'string' => 'svn+ssh://hoge',
'expect' => true,
],
'alphabet and dot, true' => [
'string' => 'custom.scheme://hoge',
'expect' => true,
],
'alphabet and hyphen, true' => [
'string' => 'custom-scheme://hoge',
'expect' => true,
],
'alphabet and underscore, false' => [
'string' => 'custom_scheme://hoge',
'expect' => false,
],
'alphabet and slash, false' => [
'string' => 'custom/scheme://hoge',
'expect' => false,
],
'colon-started, false' => [
'string' => ':https://hoge.com/',
'expect' => false,
],
'slash-started, false' => [
'string' => '/https://hoge.com/',
'expect' => false,
],
'absolute file path, false' => [
'string' => '/var/www/html/example.com',
'expect' => false,
],
'relative file path, false' => [
'string' => 'html/example.com',
'expect' => false,
],
'relative file paht with dot slash, false' => [
'string' => './html/example.com',
'expect' => false,
],
];
}

#[DataProvider('provide_isUrl_can_judge_correctly')]
public function test_isUrl_can_judge_correctly(string $string, bool $expect): void
{
$this->assertSame($expect, Uri::isUri($string));
}

public static function provide_getScheme_can_return_scheme_correctly(): array
{
return [
'http' => [
'uri' => 'http://example.com/',
'expect' => 'http',
],
'https' => [
'uri' => 'https://example.com/',
'expect' => 'https',
],
'svn+ssh' => [
'uri' => 'svn+ssh://example.com/',
'expect' => 'svn+ssh',
],
'file' => [
'uri' => 'file:///var/www/html',
'expect' => 'file',
],
'custom.scheme' => [
'uri' => 'custom.scheme://example.com/',
'expect' => 'custom.scheme',
],
'custom-scheme' => [
'uri' => 'custom-scheme://example.com/',
'expect' => 'custom-scheme',
],
'null (filepath)' => [
'uri' => '/var/www/html',
'expect' => null,
],
'null (invalid shceme)' => [
'uri' => ':https://example.com/',
'expect' => null,
],
];
}

#[DataProvider('provide_getScheme_can_return_scheme_correctly')]
public function test_getScheme_can_return_scheme_correctly(string $uri, string|null $expect): void
{
$this->assertSame($expect, Uri::getScheme($uri));
}
}