{"id":14974572,"url":"https://github.com/rattfieldnz/safe-urls","last_synced_at":"2026-02-22T23:33:16.594Z","repository":{"id":35038660,"uuid":"199432762","full_name":"rattfieldnz/safe-urls","owner":"rattfieldnz","description":"A laravel package to check URLs with Google's Safe Browsing API.","archived":false,"fork":false,"pushed_at":"2022-03-26T01:05:03.000Z","size":1254,"stargazers_count":2,"open_issues_count":3,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-10-22T08:24:05.324Z","etag":null,"topics":["api","google","google-safebrowsing","laravel55","laravel56","laravel57","laravel58","safe-browsing","spam-detection","spam-filter","spam-filtering","spam-protection"],"latest_commit_sha":null,"homepage":"","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rattfieldnz.png","metadata":{"files":{"readme":"readme.md","changelog":"changelog.md","contributing":"contributing.md","funding":null,"license":"license.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-07-29T10:38:13.000Z","updated_at":"2022-02-21T00:45:08.000Z","dependencies_parsed_at":"2022-08-08T04:01:08.646Z","dependency_job_id":null,"html_url":"https://github.com/rattfieldnz/safe-urls","commit_stats":null,"previous_names":[],"tags_count":58,"template":false,"template_full_name":null,"purl":"pkg:github/rattfieldnz/safe-urls","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rattfieldnz%2Fsafe-urls","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rattfieldnz%2Fsafe-urls/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rattfieldnz%2Fsafe-urls/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rattfieldnz%2Fsafe-urls/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rattfieldnz","download_url":"https://codeload.github.com/rattfieldnz/safe-urls/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rattfieldnz%2Fsafe-urls/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29730736,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-22T20:09:16.275Z","status":"ssl_error","status_checked_at":"2026-02-22T20:09:13.750Z","response_time":110,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["api","google","google-safebrowsing","laravel55","laravel56","laravel57","laravel58","safe-browsing","spam-detection","spam-filter","spam-filtering","spam-protection"],"created_at":"2024-09-24T13:50:45.481Z","updated_at":"2026-02-22T23:33:16.577Z","avatar_url":"https://github.com/rattfieldnz.png","language":"HTML","funding_links":[],"categories":[],"sub_categories":[],"readme":"# safe-urls\n\n[![PHP Version](https://img.shields.io/badge/php-7.3%2B-green.svg)](https://packagist.org/packages/rattfieldnz/safe-urls) [![PHP Version](https://img.shields.io/badge/php-7.2%2B-green.svg)](https://packagist.org/packages/rattfieldnz/safe-urls) \n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![Latest Version on Packagist][ico-version]][link-packagist]\n[![Total Downloads][ico-downloads]][link-downloads]\n[![Build Status][ico-travis]][link-travis]\n[![StyleCI][ico-styleci]][link-styleci] \n[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/rattfieldnz/safe-urls/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/rattfieldnz/safe-urls/?branch=master) \n[![codecov](https://codecov.io/gh/rattfieldnz/safe-urls/branch/master/graph/badge.svg)](https://codecov.io/gh/rattfieldnz/safe-urls)\n\nA Laravel package to check URLs with [Google's Safe Browsing API (look up)](https://developers.google.com/safe-browsing/v4/lookup-api). \n\nInspired by another similar package @ [https://github.com/snipe/Safebrowsing](https://github.com/snipe/Safebrowsing).\n\nTake a look at [contributing.md](contributing.md) to see a to do list.\n\n\u003chr/\u003e\n\n* [Installation](#installation)\n  * [Update Config](#update_config)\n  * [Publish Config](#publish_config)\n  * [Set Your Google Safebrowsing API Key](#set_google_safebrowsing_key)\n* [Usage](#usage)\n  * [Using Blade Syntax](#usage_blade)\n  * [Using Facades](#usage_facades)\n* [Example With Input and Output](#example_with_input_and_output)\n* [Test URLs](#testing_urls)\n* [Testing](#testing)\n* [Contributing](#contributing)\n* [Security](#security)\n* [Credits](#credits)\n* [License](#license)\n\n\u003chr/\u003e\n\n## Please Note:\n__This package requires that you have [an active Google Safebrowsing API key](https://developers.google.com/safe-browsing/v4/get-started). It absolutely will not work without one.__ It's free to create an API key .\n\nGoogle also throttles API usage, so if you have a high-traffic site, you may want to build in a caching layer or something so you don't burn through your requests too quickly. You can keep an eye on your usage through the [Google API console](https://console.developers.google.com/apis/api/safebrowsing.googleapis.com/usage).\n\n__This project is not ready for use in production yet. When it is, there will be first major release (i.e. 1.0.0).__\n\n## A Note About Google Safebrowsing API Results\n\nDuring testing, there were a few times when the API showed some malware sites as 'safe', whereas in reality they weren't. \n\nFor example, running PHPUnit tests showed the [sample sites below](#testing_urls) as being 'safe'; however, running the API in [Postman](https://www.getpostman.com/downloads/) produced expected results. I have not found a solution yet; however, any feedback / suggestions are welcome, as are pull requests etc. Below are links which I have read about this issue further:\n\n- https://github.com/google/safebrowsing/issues/30#issuecomment-302508958.\n- https://stackoverflow.com/questions/41934692/google-url-safe-browsingv4-lookup-api-is-not-working.\n- https://groups.google.com/forum/#!topic/google-safe-browsing-api/Z5FVGfBbl20\n- https://stackoverflow.com/questions/54625443/google-safe-browsing-not-detecting-url-even-it-unsafe-url\n\n\n## \u003ca id=\"installation\"\u003e\u003c/a\u003eInstallation\n\nVia Composer\n\n``` bash\n$ composer require rattfieldnz/safe-urls\n```\n### \u003ca id=\"update_config\"\u003e\u003c/a\u003eUpdate Your Config\n\n#### For applications using Laravel =\u003c 5.4\n\nOpen `config/app.php` and add:\n\n``` php\nRattfieldNz\\SafeUrls\\SafeUrlsServiceProvider::class,\n```\n\nto your `providers` array in `config/app.php`, and:\n\n``` php\n'SafeUrls' =\u003e RattfieldNz\\SafeUrls\\Facades\\SafeUrlsFacade::class,\n```\n\nto your `aliases` array in `config/app.php`.\n\n### \u003ca id=\"publish_config\"\u003e\u003c/a\u003ePublish the config\n\n``` bash\nphp artisan vendor:publish\n```\n\nThis will add a `safe-urls.php` config file into your project's `config` folder.\n\n### \u003ca id=\"set_google_safebrowsing_key\"\u003e\u003c/a\u003eSet Your Google Safebrowsing API Key\n\nIn your `.env`, add:\n\n``` bash\nGOOGLE_API_KEY=YOUR-ACTUAL-API-KEY\nGOOGLE_CLIENT_ID=your-client-id\nGOOGLE_CLIENT_VERSION=1.0 (or your preferred number)\nGOOGLE_CURL_TIMEOUT=10 (in seconds)\n```\n\nThere are additional options in the config file that relate to what specific types of threats you want to check for, and what platforms you want to check on, but you only really need to worry about that if you want to check *fewer* things, as it's pretty inclusive already.\n\n## \u003ca id=\"usage\"\u003e\u003c/a\u003eUsage\n\n### \u003ca id=\"usage_blade\"\u003e\u003c/a\u003eUsing Blade Syntax\n\n```php\n@if(isset(SafeUrls::check($urls, true)[\"response\"][\"matches\"]))\n    \u003cp\u003eThere are {{ count(SafeUrls::check($urls, true)[\"response\"][\"matches\"]) }} dangerous URLs.\u003c/p\u003e\n@else\n    \u003cp\u003eNo results were found\u003c/p\u003e\n@endif\n```\n\nWhere `$urls` could be an array of URLs to check, perhaps [passed through your Controller to a view](https://laravel.com/docs/5.8/views#passing-data-to-views).\n\nWhere `true` will return the results as an associative array. \n\n`false` (or not having the second parameter) will return the results as a JSON-encoded string.\n\n``` php\n@if (SafeUrls::isDangerous('http://twitter.com/'))\n    // do something if the url is flagged as suspicious\n@else\n    // hooray - it's not flagged!\n@endif\n```\n\n### \u003ca id=\"usage_facades\"\u003e\u003c/a\u003eUsing Facades\n``` php\nSafeUrls::add(['http://ianfette.org']);\nSafeUrls::add(['http://malware.testing.google.test/testing/malware/']);\nSafeUrls::execute();\nprint('Status of the third URL is: '.SafeUrls::isDangerous('http://twitter.com/'));\n```\n\n## \u003ca id=\"example_with_input_and_output\"\u003e\u003c/a\u003eExample with input and output\n\nIf the value of `$urls` was:\n\n```php\n$urls = [\n    'http://www.yahoo.com/'\n    'http://www.google.com/'\n    'http://malware.testing.google.test/testing/malware/'\n    'http://twitter.com/'\n    'http://ianfette.org'\n    'https://github.com/'\n    'https://testsafebrowsing.appspot.com/s/phishing.html'\n    'https://testsafebrowsing.appspot.com/s/malware.html'\n    'http://testsafebrowsing.appspot.com/apiv4/ANY_PLATFORM/MALWARE/URL/'\n    'http://testsafebrowsing.appspot.com/apiv4/ANY_PLATFORM/SOCIAL_ENGINEERING/URL/'\n];   \n```\n\n`SafeUrls::check($urls, true)` Would return the following associative array:\n\n```php\n[\n    \"status\" =\u003e 200,\n    \"response\" =\u003e \n        [\n            \"matches\" =\u003e [\n                [\n                    \"threatType\" =\u003e \"MALWARE\",\n                    \"platformType\" =\u003e \"ANY_PLATFORM\",\n                    \"threat\" =\u003e [\n                        \"url\" =\u003e \"http://malware.testing.google.test/testing/malware/\"\n                    ],\n                    \"cacheDuration\" =\u003e \"300s\",\n                    \"threatEntryType\" =\u003e \"URL\"\n                ],\n                [\n                    \"threatType\" =\u003e \"SOCIAL_ENGINEERING\",\n                    \"platformType\" =\u003e \"ANY_PLATFORM\",\n                    \"threat\" =\u003e [\n                        \"url\" =\u003e \"http://malware.testing.google.test/testing/malware/\"\n                    ],\n                    \"cacheDuration\" =\u003e \"300s\",\n                    \"threatEntryType\" =\u003e \"URL\"\n                ],\n                [\n                    \"threatType\" =\u003e \"SOCIAL_ENGINEERING\",\n                    \"platformType\" =\u003e \"ANY_PLATFORM\",\n                    \"threat\" =\u003e [\n                        \"url\" =\u003e \"https://testsafebrowsing.appspot.com/s/phishing.html\"\n                    ],\n                    \"cacheDuration\" =\u003e \"300s\",\n                    \"threatEntryType\" =\u003e \"URL\"\n                ],\n                [\n                    \"threatType\" =\u003e \"MALWARE\",\n                    \"platformType\" =\u003e \"ANY_PLATFORM\",\n                    \"threat\" =\u003e [\n                        \"url\" =\u003e \"https://testsafebrowsing.appspot.com/s/malware.html\"\n                    ],\n                \"cacheDuration\" =\u003e \"300s\",\n                \"threatEntryType\" =\u003e \"URL\"\n            ],\n            [\n                \"threatType\" =\u003e \"MALWARE\",\n                \"platformType\" =\u003e \"ANY_PLATFORM\",\n                \"threat\" =\u003e [\n                    \"url\" =\u003e \"http://testsafebrowsing.appspot.com/apiv4/ANY_PLATFORM/MALWARE/URL/\"\n                ],\n                \"cacheDuration\" =\u003e \"300s\",\n                \"threatEntryType\" =\u003e \"URL\"\n            ],\n            [\n                \"threatType\" =\u003e \"SOCIAL_ENGINEERING\",\n                \"platformType\" =\u003e \"ANY_PLATFORM\",\n                \"threat\" =\u003e [\n                    \"url\" =\u003e \"http://testsafebrowsing.appspot.com/apiv4/ANY_PLATFORM/SOCIAL_ENGINEERING/URL/\"\n                ],\n                \"cacheDuration\" =\u003e \"300s\",\n                \"threatEntryType\" =\u003e \"URL\"\n            ],\n        ],\n    ],\n]\n```\n\n`SafeUrls::check($urls)` (or `SafeUrls::check($urls, false)`) Would return the following JSON-encoded string:\n\n```json\n{  \n   \"status\":200,\n   \"response\":{  \n      \"matches\":[  \n         {  \n            \"threatType\":\"MALWARE\",\n            \"platformType\":\"ANY_PLATFORM\",\n            \"threat\":{  \n               \"url\":\"http:\\/\\/malware.testing.google.test\\/testing\\/malware\\/\"\n            },\n            \"cacheDuration\":\"300s\",\n            \"threatEntryType\":\"URL\"\n         },\n         {  \n            \"threatType\":\"SOCIAL_ENGINEERING\",\n            \"platformType\":\"ANY_PLATFORM\",\n            \"threat\":{  \n               \"url\":\"http:\\/\\/malware.testing.google.test\\/testing\\/malware\\/\"\n            },\n            \"cacheDuration\":\"300s\",\n            \"threatEntryType\":\"URL\"\n         },\n         {  \n            \"threatType\":\"SOCIAL_ENGINEERING\",\n            \"platformType\":\"ANY_PLATFORM\",\n            \"threat\":{  \n               \"url\":\"https:\\/\\/testsafebrowsing.appspot.com\\/s\\/phishing.html\"\n            },\n            \"cacheDuration\":\"300s\",\n            \"threatEntryType\":\"URL\"\n         },\n         {  \n            \"threatType\":\"MALWARE\",\n            \"platformType\":\"ANY_PLATFORM\",\n            \"threat\":{  \n               \"url\":\"https:\\/\\/testsafebrowsing.appspot.com\\/s\\/malware.html\"\n            },\n            \"cacheDuration\":\"300s\",\n            \"threatEntryType\":\"URL\"\n         },\n         {  \n            \"threatType\":\"MALWARE\",\n            \"platformType\":\"ANY_PLATFORM\",\n            \"threat\":{  \n               \"url\":\"http:\\/\\/testsafebrowsing.appspot.com\\/apiv4\\/ANY_PLATFORM\\/MALWARE\\/URL\\/\"\n            },\n            \"cacheDuration\":\"300s\",\n            \"threatEntryType\":\"URL\"\n         },\n         {  \n            \"threatType\":\"SOCIAL_ENGINEERING\",\n            \"platformType\":\"ANY_PLATFORM\",\n            \"threat\":{  \n               \"url\":\"http:\\/\\/testsafebrowsing.appspot.com\\/apiv4\\/ANY_PLATFORM\\/SOCIAL_ENGINEERING\\/URL\\/\"\n            },\n            \"cacheDuration\":\"300s\",\n            \"threatEntryType\":\"URL\"\n         }\n      ]\n   }\n}\n```\n\nBoth outputs will depend on what options you have set in your `config/safe-urls.php` file.\n\n## \u003ca id=\"testing_urls\"\u003e\u003c/a\u003eTest URLs\n\nHere are some handy test urls you can use while you're experimenting with this Laravel package.\n\n- http://www.yahoo.com/ (OK)\n- http://www.google.com/ (OK)\n- http://malware.testing.google.test/testing/malware/ (Malware)\n- http://twitter.com/ (OK)\n- http://ianfette.org (Malware)\n- https://github.com/ (OK)\n- https://testsafebrowsing.appspot.com/s/phishing.html (Malware)\n- https://testsafebrowsing.appspot.com/s/malware.html (Malware)\n- http://testsafebrowsing.appspot.com/apiv4/ANY_PLATFORM/MALWARE/URL/ (Malware)\n- http://testsafebrowsing.appspot.com/apiv4/ANY_PLATFORM/SOCIAL_ENGINEERING/URL/ (Malware / Social Engineering)\n\n## \u003ca id=\"changelog\"\u003e\u003c/a\u003eChange log\n\nPlease see the [changelog](changelog.md) for more information on what has changed recently.\n\n## \u003ca id=\"testing\"\u003e\u003c/a\u003eTesting\n\nFrom inside the root folder of this package:\n\n``` bash\n$ ./run_phpunit YOUR_GOOGLE_API_KEY\n```\nReplace YOUR_GOOGLE_API_KEY with your key. Get one by visiting [https://developers.google.com/safe-browsing/v4/get-started](https://developers.google.com/safe-browsing/v4/get-started).\n\n## \u003ca id=\"contributing\"\u003e\u003c/a\u003eContributing\n\nPlease see [contributing.md](contributing.md) for details and a todolist.\n\n## \u003ca id=\"security\"\u003e\u003c/a\u003eSecurity\n\nIf you discover any security related issues, please email author email instead of using the issue tracker.\n\n## \u003ca id=\"credits\"\u003e\u003c/a\u003eCredits\n\n- [Rob Attfield][link-author]\n- [All Contributors][link-contributors]\n\n## \u003ca id=\"license\"\u003e\u003c/a\u003eLicense\nPlease see the [license file](license.md) for more information.\n\n[ico-version]: https://img.shields.io/packagist/v/rattfieldnz/safe-urls.svg?style=flat-square\n[ico-downloads]: https://img.shields.io/packagist/dt/rattfieldnz/safe-urls.svg?style=flat-square\n[ico-travis]: https://img.shields.io/travis/rattfieldnz/safe-urls/master.svg?style=flat-square\n[ico-styleci]: https://styleci.io/repos/199432762/shield\n\n[link-packagist]: https://packagist.org/packages/rattfieldnz/safe-urls\n[link-downloads]: https://packagist.org/packages/rattfieldnz/safe-urls\n[link-travis]: https://travis-ci.org/rattfieldnz/safe-urls\n[link-styleci]: https://styleci.io/repos/199432762\n[link-author]: https://github.com/rattfieldnz\n[link-contributors]: ../../contributors\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frattfieldnz%2Fsafe-urls","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frattfieldnz%2Fsafe-urls","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frattfieldnz%2Fsafe-urls/lists"}