{"id":13409715,"url":"https://github.com/drewm/morse","last_synced_at":"2025-10-13T04:14:04.674Z","repository":{"id":33427146,"uuid":"37072440","full_name":"drewm/morse","owner":"drewm","description":"A feature detection library for PHP code that needs to run in multiple different environments","archived":false,"fork":false,"pushed_at":"2016-03-13T21:27:24.000Z","size":43,"stargazers_count":160,"open_issues_count":1,"forks_count":4,"subscribers_count":10,"default_branch":"master","last_synced_at":"2025-09-02T03:56:07.629Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/drewm.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-06-08T14:38:38.000Z","updated_at":"2024-06-14T16:39:21.000Z","dependencies_parsed_at":"2022-08-21T10:50:54.596Z","dependency_job_id":null,"html_url":"https://github.com/drewm/morse","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/drewm/morse","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drewm%2Fmorse","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drewm%2Fmorse/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drewm%2Fmorse/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drewm%2Fmorse/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/drewm","download_url":"https://codeload.github.com/drewm/morse/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drewm%2Fmorse/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279013694,"owners_count":26085390,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-13T02:00:06.723Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-30T20:01:02.954Z","updated_at":"2025-10-13T04:14:04.645Z","avatar_url":"https://github.com/drewm.png","language":"PHP","funding_links":[],"categories":["PHP"],"sub_categories":[],"readme":"# Morse: the PHP detective-inspector\n\nMorse is a feature detection library for PHP code that needs to run in multiple different environments.\n\n[![Build Status](https://travis-ci.org/drewm/morse.svg?branch=master)](https://travis-ci.org/drewm/morse)\n[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/drewm/morse/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/drewm/morse/?branch=master)\n\nSupports PHP 5.3 and up.\n\n## Why?\n\nWriting PHP that works in unknown (some sometimes hostile) environments is hard. You don't always know what functionality is available to you, so you have to test for it. Morse is a library to encapsulate those tests.\n\nMost tests are really simple - just a `function_exists()` or similar - but you can often end up needing to repeat that test over and over across your codebase. Morse centralises those tests, providing reusability and consistancy.\n\nSome tests aren't so simple, perhaps due to _that one weird PHP bug_ or unusual hosting configurations or whatever. You have to do a weird dance to check if something is _really_ going to work. Morse takes care of that, and keeps the weird dancing out of your application code, safe from the next developer who thinks it's dumb and rips it out.\n\n## Install\n\nEither download and include, or install via Composer:\n\n```\ncomposer require drewm/morse\n```\n\n## How to\n\n```php\nuse \\DrewM\\Morse\\Morse;\n\nif (Morse::featureExists('http/curl')) {\n\t// use curl\n}else{\n\t// use sockets\n}\n```\n\n## Testing if a feature exists\n\n```php\nMorse::featureExists('group/feature');\n```\n\nFeatures that may be available in either newer class support or older function support can return a value of `Morse::CLASS_SUPPORT` or `Morse::FUNCTION_SUPPORT`, both of which are truthy.\n\nSo this works:\n\n```php\nif (Morse::featureExists('file/finfo')) {\n\t...\n}\n```\n\nbut equally:\n\n```php\nswitch(Morse::featureExists('file/finfo')) {\n\tcase Morse::CLASS_SUPPORT:\n\t\t$finfo = new finfo(...);\n\t\tbreak;\n\n\tcase Morse::FUNCTION_SUPPORT:\n\t\t$finfo = finfo_open(...);\n\t\tbreak;\n\n\tdefault:\n\t\tdie('No finfo support!');\n\t\tbreak;\n}\n```\n\nIf class support is found, this returns regardless of function support.\n\n\n## Finding the first match in a list\n\n```php\n$best_match = Morse::getFirstAvailable(['image/gd', 'image/imagick']);\n```\n\nor\n\n```php\n$best_match = Morse::getFirstAvailable([\n\t\t\t\t\t'image/gd' =\u003e 'gd',\n\t\t\t\t\t'image/imagick' =\u003e 'imagick'\n\t\t\t\t]);\n\nswitch($best_match) {\n\n\tcase 'gd':\n\t\t...\n\t\tbreak;\n\n\tcase 'imagick':\n\t\t...\n\t\tbreak;\n}\n```\n\n## Features\n\nFeature detection tests currently exist for the following:\n\n- cache\n\t- apc\n\t- memcache\n\t- memcached\n\t- opcache\n- crypto\n\t- mcrypt\n\t- openssl\n\t- password\n- data\n\t- json\n- db\n\t- mysqli\n\t- pdo\n\t- pdo-mysql\n\t- pdo-pgsql\n\t- pdo-sqlite\n- file\n\t- finfo\n\t- zip\n- http\n\t- curl\n\t- filter\n\t- sockets\n- image\n\t- gd\n\t- imagick\n- number\n\t- bigint\n- protocol\n\t- ldap\n- system\n\t- exec\n\t- ignore_user_abort\n\t- ini_set\n\t- passthru\n\t- popen\n\t- proc_open\n\t- set_time_limit\n\t- shell_exec\n\t- system\n- text\n\t- ctype\n\t- iconv\n\t- intl\n\t- multibyte\n\t- transliterate\n\n## Contributing feature tests\n\nFeature tests are functions in the appropriate class that return true or false to indicate support for a feature.\n\nLet's say you wanted to add a feature detection test for a database called Pongo. You would test for it with the feature identifier `db/pongo`, which would map to a function called `testPongo` in the `Feature/Db.php` class file.\n\nBoth half of the feature identifier are run through `ucwords()` to correct case. Dashes are changed to underscores. So `db/pongo-panda` would map to `Feature\\Db::testPongo_Panda`.\n\n```php\nnamespace DrewM\\Morse\\Feature;\n\nclass Db extends \\DrewM\\Morse\\Feature\n{\n\tpublic function testPongo_Panda()\n\t{\n\t\t// do whatever needs to be done to determine support\n\t\t// return true for support, false for no support;\n\t\treturn true;\n\t}\n}\n```\n\nIf a feature can exist in both OO-style classes and procedural-style function form, return `\\DrewM\\Morse\\Morse::CLASS_SUPPORT` or `\\DrewM\\Morse\\Morse::FUNCTION_SUPPORT` as your truthy value. Check for classes first.\n\n```php\nnamespace DrewM\\Morse\\Feature;\n\nclass Db extends \\DrewM\\Morse\\Feature\n{\n\tpublic function testPongo_Panda()\n\t{\n\t\tif (class_exists('PongoPanda')) {\n\t\t\treturn \\DrewM\\Morse\\Morse::CLASS_SUPPORT;\n\t\t}\n\n\t\tif (self::functionAvailable('pongo_panda')) {\n\t\t\treturn \\DrewM\\Morse\\Morse::FUNCTION_SUPPORT;\n\t\t}\n\n\t\treturn false;\n\t}\n}\n```\n\nFeature classes should be big concepts (image, text, database) and the tests themselves should be specific features.\n\nPlease write a corresponding PHPUnit test for the feature you're adding. Note that you can't rely on the environment, so just test that the detection works and returns a sane value.\n\n### Testing for function availability\n\nPHP gives us `function_exists()` for testing if a function has been declared. In some circumstances (e.g. when suhosin blacklisting is invoked), this can return `true` even if the function has been disabled and isn't available for use. Therefore, do the following within a feature class to detect whether a function is both declared _and_ not disabled:\n\n    self::functionAvailable('pongo_panda')","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdrewm%2Fmorse","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdrewm%2Fmorse","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdrewm%2Fmorse/lists"}