외부 코드를 Composer 기반으로 변경
This commit is contained in:
1 parent
8a181055a0
commit
d422c03003
101 files changed
+12743
-19
No files matched your search
@@ -0,0 +1 @@
|
||||
service_name: travis-ci
|
||||
@@ -0,0 +1,4 @@
|
||||
test.php
|
||||
build/*
|
||||
report/*
|
||||
tests/test*
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
language: php
|
||||
|
||||
php:
|
||||
- 5.3
|
||||
- 5.4
|
||||
- 5.5
|
||||
- 5.6
|
||||
- hhvm
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- php: hhvm
|
||||
|
||||
before_script:
|
||||
- pyrus install pear/PHP_CodeSniffer
|
||||
- wget -nc http://getcomposer.org/composer.phar
|
||||
- php composer.phar install --dev --no-interaction
|
||||
- mkdir -p build/logs
|
||||
- phpenv rehash
|
||||
|
||||
after_script:
|
||||
- php vendor/bin/coveralls
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
Change Log
|
||||
==========
|
||||
|
||||
1.1.0
|
||||
-----
|
||||
|
||||
This release introduces a deprecation notice for `slugify()`, please update your code.
|
||||
|
||||
* Added a cryptographically secure random string function `secure_random_string`. Thanks to @abhimanyusharma003 via [Pull Request #53](https://github.com/brandonwamboldt/utilphp/pull/53)
|
||||
* Added `limit_characters` and `limit_words` functions. Thanks to @abhimanyusharma003 via [Pull Request #55](https://github.com/brandonwamboldt/utilphp/pull/55)
|
||||
* Added `rmdir` method to recursively delete a directory. Thanks to @ARACOOOL via [Pull Request #56](https://github.com/brandonwamboldt/utilphp/pull/56)
|
||||
* Added `set_executable`, `set_readable`, `set_writable`, `directory_size`, `directory_contents` and `get_user_dir` functions. Thanks to @sergserg via [Pull Request #70](https://github.com/brandonwamboldt/utilphp/pull/70)
|
||||
* Changed parameter ordering for `slugify`, `$css_mode` is now the third argument. For backwards compatibility, the old order will still work but it will generate an `E_USER_DEPRECATED` warning. Thanks to @abhimanyusharma003 via [Pull Request #71](https://github.com/brandonwamboldt/utilphp/pull/71)
|
||||
* Added `match_string` method. Thanks to @abhimanyusharma003 via [Pull Request #72](https://github.com/brandonwamboldt/utilphp/pull/72)
|
||||
* Renamed internal methods (protected ones) for PSR-2 compliance
|
||||
* General performance improvements, code quality improvements, and increased unit test coverage (special thanks to @hopeseekr for getting us near 100% coverage)
|
||||
|
||||
1.0.7
|
||||
-----
|
||||
|
||||
* Added `fix_broken_serialization` to fix broken serialized strings (Thanks to @hopeseekr via [Pull Request #48](https://github.com/brandonwamboldt/utilphp/pull/48))
|
||||
* Fixed `get_current_url` appending port 80 or 443 when not needed (Thanks to @scottchiefbaker via [Pull Request #49](https://github.com/brandonwamboldt/utilphp/pull/49))
|
||||
* `var_dump` can now handle recursive data structures without crashing
|
||||
* `var_dump` code was minified and cleaned up
|
||||
* `array_flatten` was optimized (thanks to @hopeseekr via [Pull Request #47](https://github.com/brandonwamboldt/utilphp/pull/47))
|
||||
* `remove_accents` was completely rewritten and is now ~4x faster
|
||||
|
||||
1.0.6
|
||||
-----
|
||||
|
||||
* Added `start_with` function
|
||||
* Added `ends_with` function
|
||||
* Added `str_contains` function
|
||||
* Added `str_icontains` function
|
||||
* Added `get_file_ext` function
|
||||
* Fixing permissions on the files & directories
|
||||
* Fixing a bug with the include path of util.php
|
||||
|
||||
1.0.5
|
||||
-----
|
||||
|
||||
* [Issue #29](https://github.com/brandonwamboldt/utilphp/issues/29) Fixed error in `var_dump` if mbstring extension wasn't present
|
||||
* Adding Composer support
|
||||
* Updating license from GPL to MIT
|
||||
* Adding Changelog to project
|
||||
* Bumping minimum version to PHP 5.3.3
|
||||
|
||||
1.0.4
|
||||
-----
|
||||
|
||||
* [Issue #22](https://github.com/brandonwamboldt/utilphp/issues/22) Removed all superglobal *_get functions, you can use the modified array_get now
|
||||
* [Issue #22](https://github.com/brandonwamboldt/utilphp/issues/22) Modifed the behaviour of `array_get`, see documentation
|
||||
* [Pull Request #21](https://github.com/brandonwamboldt/utilphp/pull/21) Added multibyte support to html* functions
|
||||
* [Issue #9](https://github.com/brandonwamboldt/utilphp/issues/9) Removed the `str_to_utf8` function
|
||||
* [Issue #3](https://github.com/brandonwamboldt/utilphp/issues/3) Removed the `absint` function
|
||||
* Removed declare() from util.php to avoid errors
|
||||
* Updated PHPUnit tests to use PHPUnit 3.6
|
||||
|
||||
1.0.3
|
||||
-----
|
||||
|
||||
* [Issue #16](https://github.com/brandonwamboldt/utilphp/issues/16) Improved performance of `slugify`
|
||||
* [Issue #14](https://github.com/brandonwamboldt/utilphp/issues/14) Modified the regex for `seems_utf8` to be more accurate
|
||||
* [Issue #13](https://github.com/brandonwamboldt/utilphp/issues/13) Changed `validate_email` to be wrapper for `filter_var`
|
||||
* Added 'ok' to the list of yes words for `str_to_bool`
|
||||
* `str_to_bool` matches no followed by any number of 'o's
|
||||
|
||||
1.0.2
|
||||
-----
|
||||
|
||||
* [Issue #12](https://github.com/brandonwamboldt/utilphp/issues/12) `get_current_url` now includes the port and user/password if required
|
||||
* [Issue #11](https://github.com/brandonwamboldt/utilphp/issues/11) `human_time_diff` now uses the DateTime functions
|
||||
* [Issue #10](https://github.com/brandonwamboldt/utilphp/issues/10) `is_https` no longer checks the port as well
|
||||
|
||||
1.0.1
|
||||
-----
|
||||
|
||||
* [Issue #7](https://github.com/brandonwamboldt/utilphp/issues/7) Added the `$trust_proxy_headers` parameter to `get_client_ip`
|
||||
* [Issue #6](https://github.com/brandonwamboldt/utilphp/issues/6) Removed `is_isset` as the function did not work as intended
|
||||
* [Issue #6](https://github.com/brandonwamboldt/utilphp/issues/6) Removed `is_empty` as it is redundant, use ! with function calls instead
|
||||
* Fixed a bug with `get_gravatar`
|
||||
|
||||
1.0.0
|
||||
-----
|
||||
|
||||
* Initial release of util.php.
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
# CONTRIBUTORS
|
||||
|
||||
Util.php is the combined effort of many people who contributed new functions and features, bug fixes, tests, and documentation.
|
||||
|
||||
# Maintainer / Lead
|
||||
|
||||
* Brandon Wamboldt (http://brandonwamboldt.ca)
|
||||
|
||||
## Third-Party Projects
|
||||
|
||||
The following projects were fully or partially incorporated into util.php (and properly attributed).
|
||||
|
||||
* IntToWords (https://github.com/hemant347/IntToWords)
|
||||
* LinkifyURL (https://github.com/jmrware/LinkifyURL)
|
||||
* URLify.php (https://github.com/jbroadway/urlify/)
|
||||
* Pure PHP http_build_url (https://github.com/jakeasmith/http_build_url)
|
||||
|
||||
## Methods
|
||||
|
||||
The following developers and/or companies helped contribute to building util.php.
|
||||
|
||||
* PHP Experts, Inc. (http://www.phpexperts.pro/)
|
||||
- `array_flatten()`
|
||||
- `fix_broken_serialization()`
|
||||
- Lots of unit tests.
|
||||
* Tony Ferrara (ircmaxwell, http://blog.ircmaxell.com/)
|
||||
- `seemsUtf8Regex()`: http://stackoverflow.com/a/11709412/430062
|
||||
* Askar ([@ARACOOOL](https://github.com/ARACOOOL))
|
||||
- `rmdir()`
|
||||
- `limit_characters()`
|
||||
- `limit_words()`
|
||||
* Anonymous (tmp1000@fastmail.fm)
|
||||
- `htmlspecialentities()`: http://php.timesoft.cc/manual/en/function.htmlentities.php
|
||||
- `htmlspecialchars()`
|
||||
* Laravel Project (https://github.com/laravel/laravel)
|
||||
- `secure_random_string()`: http://trac.allenjb.me.uk/php/browser/tagi/vendor/laravel/framework/src/Illuminate/Support/Str.php?rev=87#L127
|
||||
* Abhimanyu Sharma ([@abhimanyusharma003](https://github.com/abhimanyusharma003))
|
||||
- `limit_characters()`
|
||||
- `limit_words()`
|
||||
- `match_string()`
|
||||
* Scott Baker ([@scottchiefbaker](https://github.com/scottchiefbaker))
|
||||
* [@sergserg](https://github.com/sergserg)
|
||||
- `set_writable()`
|
||||
- `set_executable()`
|
||||
- `set_readable()`
|
||||
- `directory_size()`
|
||||
- `directory_contents()`
|
||||
- `get_user_dir()`
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
The MIT License (MIT)
|
||||
=====================
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 Brandon Wamboldt
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
# Util.php [](https://travis-ci.org/brandonwamboldt/utilphp) [](https://coveralls.io/r/brandonwamboldt/utilphp)
|
||||
|
||||
[UtilPHP](http://brandonwamboldt.github.com/utilphp/) (Aka util.php) is a
|
||||
collection of useful functions and snippets that you need or could use every
|
||||
day. It's implemented as a class with static methods, to avoid conflicts with
|
||||
your existing code-base. Just drop it in and start using it immediately.
|
||||
|
||||
Included are 55+ functions that provide you with the ability to do common
|
||||
tasks much easier and more efficiently, without having to find that one comment
|
||||
on php.net where you know it's been done already. Access superglobals without
|
||||
checking to see if certain indexes are set first and pass default values, use a
|
||||
nicely formatted var dump, validate emails, generate random strings, flatten an
|
||||
array, pull a single column out of a multidimensional array and much more.
|
||||
|
||||
Although it's implemented as one giant class, util.php has extensive
|
||||
documentation and a full suite of unit tests to avoid breaking
|
||||
backwards-compatibility unintentionally.
|
||||
|
||||
## Release Information
|
||||
|
||||
This repo contains in development code for future releases as well as the
|
||||
current stable branch. Development code is contained in the develop branch.
|
||||
|
||||
## Changelog and New Features
|
||||
|
||||
You can find a list of all changes for each release in the
|
||||
[official documentation](http://brandonwamboldt.github.com/utilphp/#changelog)
|
||||
|
||||
## Installation
|
||||
|
||||
### Server Requirements
|
||||
|
||||
* PHP version 5.3.3 or higher.
|
||||
|
||||
### Standalone File
|
||||
|
||||
Simply drop `util.php` in any project and call `include 'util.php';` in your
|
||||
project. You can then access the `Util` class.
|
||||
|
||||
### Composer
|
||||
|
||||
Add the following dependency to your composer.json:
|
||||
|
||||
```
|
||||
"brandonwamboldt/utilphp": "1.0.*"
|
||||
```
|
||||
|
||||
When used with composer, the class is namespaced (`\utilphp\util`) instead of
|
||||
just `util`.
|
||||
|
||||
## Contributing
|
||||
|
||||
UtilPHP is a community driven project and accepts contributions of code and
|
||||
documentation from the community. These contributions are made in the form of
|
||||
Issues or [Pull Requests](http://help.github.com/send-pull-requests/) on the
|
||||
[UtilityPHP repository](https://github.com/brandonwamboldt/utilphp) on GitHub.
|
||||
|
||||
Issues are a quick way to point out a bug. If you find a bug or documentation
|
||||
error in UtilityPHP then please check a few things first:
|
||||
|
||||
* There is not already an open Issue
|
||||
* The issue has already been fixed (check the develop branch, or look for closed Issues)
|
||||
* Is it something really obvious that you fix it yourself?
|
||||
|
||||
Reporting issues is helpful but an even better approach is to send a Pull
|
||||
Request, which is done by "Forking" the main repository and committing to your
|
||||
own copy. This will require you to use the version control system called Git.
|
||||
|
||||
## Guidelines
|
||||
|
||||
Before we look into how, here are the guidelines. If your Pull Requests fail to
|
||||
pass these guidelines it will be declined and you will need to re-submit when
|
||||
you’ve made the changes. This might sound a bit tough, but it is required for
|
||||
me to maintain quality of the code-base.
|
||||
|
||||
### PHP Style
|
||||
|
||||
Please ensure all new contributions match the [PSR-2](http://www.php-fig.org/psr/psr-2/)
|
||||
coding style guide.
|
||||
|
||||
### Documentation
|
||||
|
||||
If you change anything that requires a change to documentation then you will
|
||||
need to add it. New methods, parameters, changing default values, adding
|
||||
constants, etc are all things that will require a change to documentation. The
|
||||
change-log must also be updated for every change. Also PHPDoc blocks must be
|
||||
maintained.
|
||||
|
||||
### PHP Version Compatibility
|
||||
|
||||
UtilityPHP is compatible with PHP 5.3.3 so all code supplied must stick to this
|
||||
requirement.
|
||||
|
||||
Of particular note is avoiding short array notation like this:
|
||||
|
||||
```
|
||||
$var = [];
|
||||
```
|
||||
|
||||
Please use the old notation instead:
|
||||
|
||||
```
|
||||
$var = array();
|
||||
```
|
||||
|
||||
I know it's uglier, but PHP 5.3 while EOL'd, still isn't that old.
|
||||
|
||||
### Branching
|
||||
|
||||
One thing at a time: A pull request should only contain one change. That does
|
||||
not mean only one commit, but one change - however many commits it took. The
|
||||
reason for this is that if you change X and Y but send a pull request for both
|
||||
at the same time, we might really want X but disagree with Y, meaning we cannot
|
||||
merge the request. Using the Git-Flow branching model you can create new
|
||||
branches for both of these features and send two requests.
|
||||
|
||||
## License
|
||||
|
||||
UtilPHP is licensed under the MIT license.
|
||||
|
||||
## Resources
|
||||
|
||||
* [Documentation](http://brandonwamboldt.github.com/utilphp/)
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "brandonwamboldt/utilphp",
|
||||
"type": "library",
|
||||
"version": "1.1.0",
|
||||
"description": "util.php is a collection of useful functions and snippets that you need or could use every day, designed to avoid conflicts with existing projects",
|
||||
"keywords": ["php", "utility", "collection", "helpers"],
|
||||
"homepage": "https://github.com/brandonwamboldt/utilphp",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Brandon Wamboldt",
|
||||
"email": "brandon.wamboldt@gmail.com"
|
||||
}
|
||||
],
|
||||
"autoload": {
|
||||
"psr-0": { "utilphp\\": "src/" }
|
||||
},
|
||||
"require-dev": {
|
||||
"satooshi/php-coveralls": "dev-master"
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
}
|
||||
}
|
||||
+168
@@ -0,0 +1,168 @@
|
||||
body {
|
||||
background: #f4f4f4 url('../images/background.png');
|
||||
color: #333;
|
||||
font: 18px/30px "Droid Serif", "Helvetica Neue", Helvetica, Arial;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #f00;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
background: #277585;
|
||||
color: #fff;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 40px;
|
||||
font-weight: normal;
|
||||
margin: 0 0 15px;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 20px 0;
|
||||
min-width: 550px;
|
||||
max-width: 900px;
|
||||
}
|
||||
|
||||
table, tr, td {
|
||||
margin: 0; padding: 0;
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 2px 12px 2px 0;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style-type: circle;
|
||||
padding: 0 0 0 20px;
|
||||
}
|
||||
|
||||
li {
|
||||
width: 500px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
code, pre, tt {
|
||||
font-family: Monaco, Consolas, "Lucida Console", monospace;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
tt {
|
||||
padding: 0px 3px;
|
||||
background: #fff;
|
||||
border: 1px solid #ddd;
|
||||
zoom: 1;
|
||||
}
|
||||
|
||||
code {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
pre {
|
||||
font-size: 12px;
|
||||
padding: 12px;
|
||||
background: #fff;
|
||||
margin: 0px 0 30px;
|
||||
border-radius: 0 0 2px 2px;
|
||||
box-shadow: inset 0 0 0 1px rgba(0,0,0,.15);
|
||||
}
|
||||
|
||||
span.header {
|
||||
font-size: 24px;
|
||||
line-height: 30px;
|
||||
border-left: 10px solid #ddd;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.desc-text code {
|
||||
margin-left: 0;
|
||||
font-size: 18px;
|
||||
color: #0E04C8;
|
||||
}
|
||||
|
||||
#sidebar {
|
||||
background: #fff;
|
||||
position: fixed;
|
||||
top: 0; left: 0; bottom: 0;
|
||||
width: 220px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
padding: 5px 0 30px 10px;
|
||||
border-right: 1px solid #bbb;
|
||||
|
||||
box-shadow: 0 0 20px #ccc;
|
||||
-webkit-box-shadow: 0 0 20px #ccc;
|
||||
-moz-box-shadow: 0 0 20px #ccc;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.toc_title, .toc_title:visited {
|
||||
display: block;
|
||||
color: #000;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.toc_title:hover {
|
||||
background: none;
|
||||
color: #f00;
|
||||
}
|
||||
|
||||
.toc_title .version {
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.toc_section {
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
margin: 5px 0 0 0;
|
||||
padding-left: 10px;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.toc_section li {
|
||||
cursor: pointer;
|
||||
margin: 0 0 3px 0;
|
||||
}
|
||||
|
||||
.toc_section li a {
|
||||
text-decoration: none;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.toc_section li a:hover {
|
||||
background: none;
|
||||
color: #f00;
|
||||
}
|
||||
|
||||
.container {
|
||||
min-width: 550px;
|
||||
max-width: 1000px;
|
||||
margin: 40px 0 50px 260px;
|
||||
}
|
||||
|
||||
#documentation section > article > p > code {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
#documentation section > article > p > code > .util_class {
|
||||
color: #bbb;
|
||||
}
|
||||
|
||||
#documentation section > article > p > code > .func_name {
|
||||
color: #0E04C8;
|
||||
}
|
||||
|
||||
#documentation section > article > p > code > .param {
|
||||
color: #DA72F3;
|
||||
}
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 803 B |
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.0 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 83 KiB |
+1234
@@ -0,0 +1,1234 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="chrome=1" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
|
||||
<link rel="canonical" href="http://includephp.brandonwamboldt.ca/" />
|
||||
<link rel="shortcut icon" href="favicon.png" type="image/png" />
|
||||
|
||||
<link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Droid+Serif:400,700,400italic" />
|
||||
<link rel="stylesheet" href="css/docs.css" />
|
||||
|
||||
<title>util.php - The PHP programmers best friend - UtilityPHP</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="sidebar" class="interface">
|
||||
<a class="toc_title" href="#">util.php <span class="version">(1.1.0)</span></a>
|
||||
|
||||
<a class="toc_title" href="#debug_functions">Debugging</a>
|
||||
|
||||
<ul class="toc_section">
|
||||
<li>- <a href="#var_dump">var_dump</a></li>
|
||||
</ul>
|
||||
|
||||
<a class="toc_title" href="#arrays">Arrays & Objects</a>
|
||||
|
||||
<ul class="toc_section">
|
||||
<li>- <a href="#array_first">array_first</a></li>
|
||||
<li>- <a href="#array_first_key">array_first_key</a></li>
|
||||
<li>- <a href="#array_flatten">array_flatten</a></li>
|
||||
<li>- <a href="#array_get">array_get</a></li>
|
||||
<li>- <a href="#array_last">array_last</a></li>
|
||||
<li>- <a href="#array_last_key">array_last_key</a></li>
|
||||
<li>- <a href="#array_map_deep">array_map_deep</a></li>
|
||||
<li>- <a href="#array_pluck">array_pluck</a></li>
|
||||
<li>- <a href="#array_search_deep">array_search_deep</a></li>
|
||||
<li>- <a href="#array_clean">array_clean</a></li>
|
||||
</ul>
|
||||
|
||||
<a class="toc_title" href="#urls">URLs</a>
|
||||
|
||||
<ul class="toc_section">
|
||||
<li>- <a href="#add_query_arg">add_query_arg</a></li>
|
||||
<li>- <a href="#get_current_url">get_current_url</a></li>
|
||||
<li>- <a href="#http_build_url">http_build_url</a></li>
|
||||
<li>- <a href="#is_https">is_https</a></li>
|
||||
<li>- <a href="#remove_query_arg">remove_query_arg</a></li>
|
||||
<li>- <a href="#slugify">slugify</a></li>
|
||||
</ul>
|
||||
|
||||
<a class="toc_title" href="#strings">Strings</a>
|
||||
|
||||
<ul class="toc_section">
|
||||
<li>- <a href="#htmlentities">htmlentities</a></li>
|
||||
<li>- <a href="#htmlspecialchars">htmlspecialchars</a></li>
|
||||
<li>- <a href="#linkify">linkify</a></li>
|
||||
<li>- <a href="#match_string">match_string</a></li>
|
||||
<li>- <a href="#random_string">random_string</a></li>
|
||||
<li>- <a href="#number_to_word">number_to_word</a></li>
|
||||
<li>- <a href="#ordinal">ordinal</a></li>
|
||||
<li>- <a href="#remove_accents">remove_accents</a></li>
|
||||
<li>- <a href="#secure_random_string">secure_random_string</a></li>
|
||||
<li>- <a href="#seems_utf8">seems_utf8</a></li>
|
||||
<li>- <a href="#safe_truncate">safe_truncate</a></li>
|
||||
<li>- <a href="#size_format">size_format</a></li>
|
||||
<li>- <a href="#str_to_bool">str_to_bool</a></li>
|
||||
<li>- <a href="#zero_pad">zero_pad</a></li>
|
||||
<li>- <a href="#strip_space">strip_space</a></li>
|
||||
<li>- <a href="#sanitize_string">sanitize_string</a></li>
|
||||
</ul>
|
||||
|
||||
|
||||
<a class="toc_title" href="#files">Files</a>
|
||||
|
||||
<ul class="toc_section">
|
||||
<li>- <a href="#full_permissions">full_permissions</a></li>
|
||||
<li>- <a href="#rmdir">rmdir</a></li>
|
||||
</ul>
|
||||
|
||||
<a class="toc_title" href="#serialization">Serialization</a>
|
||||
|
||||
<ul class="toc_section">
|
||||
<li>- <a href="#is_serialized">is_serialized</a></li>
|
||||
<li>- <a href="#maybe_serialize">maybe_serialize</a></li>
|
||||
<li>- <a href="#maybe_unserialize">maybe_unserialize</a></li>
|
||||
<li>- <a href="#fix_broken_serialization">fix_broken_serialization</a></li>
|
||||
</ul>
|
||||
|
||||
<a class="toc_title" href="#other">Other</a>
|
||||
|
||||
<ul class="toc_section">
|
||||
<li>- <a href="#force_download">force_download</a></li>
|
||||
<li>- <a href="#get_client_ip">get_client_ip</a></li>
|
||||
<li>- <a href="#get_gravatar">get_gravatar</a></li>
|
||||
<li>- <a href="#human_time_diff">human_time_diff</a></li>
|
||||
<li>- <a href="#nocache_headers">nocache_headers</a></li>
|
||||
<li>- <a href="#utf8_headers">utf8_headers</a></li>
|
||||
<li>- <a href="#validate_email">validate_email</a></li>
|
||||
</ul>
|
||||
|
||||
<a class="toc_title" href="#constants">Constants</a>
|
||||
|
||||
<ul class="toc_section">
|
||||
<li>- <a href="#SECONDS_IN_A_MINUTE">SECONDS_IN_A_MINUTE</a></li>
|
||||
<li>- <a href="#SECONDS_IN_AN_HOUR">SECONDS_IN_AN_HOUR</a></li>
|
||||
<li>- <a href="#SECONDS_IN_A_DAY">SECONDS_IN_A_DAY</a></li>
|
||||
<li>- <a href="#SECONDS_IN_A_WEEK">SECONDS_IN_A_WEEK</a></li>
|
||||
<li>- <a href="#SECONDS_IN_A_MONTH">SECONDS_IN_A_MONTH</a></li>
|
||||
<li>- <a href="#SECONDS_IN_A_YEAR">SECONDS_IN_A_YEAR</a></li>
|
||||
</ul>
|
||||
|
||||
<a class="toc_title" href="#changelog">Change Log</a>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<p id="introduction">
|
||||
<img id="logo" src="images/utility_logo.png" alt="Util.php" />
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="http://github.com/brandonwamboldt/utilphp/">util.php</a> is a collection of useful functions and snippets
|
||||
that you need or could use every day. It's implemented as a class with static methods, to avoid conflicts with your
|
||||
existing code-base. Just drop it in and start using it immediately.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Included are 60+ functions that provide you with the ability to do common tasks much easier and more efficiently,
|
||||
without having to find that one comment on php.net where you know its been done already. Access superglobals
|
||||
without checking to see if certain indexes are set first and pass default values, use a nicely formatted var dump,
|
||||
validate emails, generate random strings, flatten an array, pull a single column out of a multidimensional array
|
||||
and much more.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Although it's implemented as one giant class, util.php has extensive documentation and a full suite of unit tests
|
||||
to avoid breaking backwards-compatibility unintentionally.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The project is <a href="http://github.com/brandonwamboldt/utilphp/">hosted on GitHub</a>.
|
||||
You can report bugs and discuss features on the
|
||||
<a href="https://github.com/brandonwamboldt/utilphp/issues">issues page</a>,
|
||||
or send tweets to <a href="http://twitter.com/brandonwamboldt">@brandonwamboldt</a>.
|
||||
</p>
|
||||
|
||||
<h2>Downloads <i style="padding-left: 12px; font-size:12px;">(Right-click, and use "Save As")</i></h2>
|
||||
|
||||
<p>
|
||||
<a href="https://github.com/brandonwamboldt/utilphp/archive/1.1.0.zip">Stable Version (1.1.0)</a><br>
|
||||
<a href="https://github.com/brandonwamboldt/utilphp/zipball/master">Unstable Version (master)</a>
|
||||
</p>
|
||||
|
||||
<h2>Installation</h2>
|
||||
|
||||
<span class="header">Server Requirements</span><br>
|
||||
|
||||
<ul>
|
||||
<li>PHP 5.3.3+</li>
|
||||
</ul>
|
||||
|
||||
<span class="header">Standalone File</span><br>
|
||||
|
||||
<p class="desc-text">
|
||||
Simply drop <code>util.php</code> in any project and call <code>include 'util.php';</code> in your project.
|
||||
You can then access the <code>Util</code> class.
|
||||
</p>
|
||||
|
||||
<span class="header">Composer</span><br>
|
||||
|
||||
<p class="desc-text">
|
||||
Add the following dependency to your composer.json:
|
||||
|
||||
<pre>"brandonwamboldt/utilphp": "1.1.*"</pre>
|
||||
|
||||
When used with composer, the class is namespaced (<code>\utilphp\util</code>) instead of
|
||||
just <code>util</code>.
|
||||
</p>
|
||||
|
||||
<div id="documentation">
|
||||
<h2 id="debug_functions">Debugging Functions</h2>
|
||||
|
||||
<section>
|
||||
<article id="var_dump">
|
||||
<p>
|
||||
<span class="header">var_dump</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">var_dump</span>(mixed <span class="param">$var</span>[, bool <span class="param">$return</span> = FALSE])
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Nicely prints out the contents of a passed variable. Booleans are properly displayed as 'true' or 'false',
|
||||
null values are shown as 'NULL', variable types are displayed, and arrays and objects are displayed as a
|
||||
collapsible tree powered by JavaScript.
|
||||
</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre class="usage-example">util::var_dump($var);</pre>
|
||||
|
||||
<img src="images/awesome_var_dump.jpg" style="border: 1px solid #ccc;" />
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<h2 id="arrays">Array/Object Functions</h2>
|
||||
|
||||
<section>
|
||||
<article id="array_first">
|
||||
<p>
|
||||
<span class="header">array_first</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">array_first</span>(array <span class="param">$array</span>)
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Retrieve the first value from an array. Can be run on function callbacks, and it will not modify the pointer
|
||||
of the source array unlike most other methods of doing this.
|
||||
</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::array_first( ['a', 'b', 'c'] );<br />=> Returns 'a'</pre>
|
||||
</article>
|
||||
|
||||
<article id="array_first_key">
|
||||
<p>
|
||||
<span class="header">array_first_key</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">array_first_key</span>(array <span class="param">$array</span>)
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Retrieve the first key from an array. Can be run on function callbacks, and it will not modify the pointer of
|
||||
the source array unlike most other methods of doing this.
|
||||
</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::array_first_key( $users );<br />=> Returns 'brandon'</pre>
|
||||
</article>
|
||||
|
||||
<article id="array_flatten">
|
||||
<p>
|
||||
<span class="header">array_flatten</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">array_flatten</span>(array <span class="param">$array</span>[, bool <span class="param">$preserve_keys</span> = TRUE])
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>Flattens a multi-dimensional array into a one dimensional array</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::array_flatten( [ 'a', 'b', [ 'c', 'd', 'e', [ 'f', 'g', [ [ [ [ 'h', 'i', 'j' ] ] ] ] ] ] ] );
|
||||
=> Returns [ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' ]</pre>
|
||||
</article>
|
||||
|
||||
<article id="array_get">
|
||||
<p>
|
||||
<span class="header">array_get</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">array_get</span>(<span class="param">$var</span>[, mixed <span class="param">$default</span> = NULL])
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>Retrieve a value from an array, or return a given default if the index isn't set</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::array_get($_POST['action'], 'index');
|
||||
=> If $_POST['action'] is set, returns its value, otherwise returns 'index'
|
||||
util::array_get($_POST['action']['do'], 'index');
|
||||
=> Returns the value of $_POST['action']['do'] or 'index'</pre>
|
||||
</article>
|
||||
|
||||
<article id="array_last">
|
||||
<p>
|
||||
<span class="header">array_last</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">array_last</span>(array <span class="param">$array</span>)
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Retrieve the last value from an array. Can be run on function callbacks, and it will not modify the pointer
|
||||
of the source array unlike most other methods of doing this.
|
||||
</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::array_last( [ 'a', 'b', 'c'] );
|
||||
=> Returns 'c'</pre>
|
||||
</article>
|
||||
|
||||
<article id="array_last_key">
|
||||
<p>
|
||||
<span class="header">array_last_key</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">array_last_key</span>(array <span class="param">$array</span>)
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Retrieve the last key from an array. Can be run on function callbacks, and it will not modify the pointer of
|
||||
the source array unlike most other methods of doing this.
|
||||
</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::array_last_key( $users );
|
||||
=> Returns 'zane'</pre>
|
||||
</article>
|
||||
|
||||
<article id="array_map_deep">
|
||||
<p>
|
||||
<span class="header">array_map_deep</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">array_map_deep</span>(array <span class="param">$array</span>, callable <span class="param">$callback</span>[, bool <span class="param">$on_nonscalar</span> = FALSE])
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Returns an array containing all the elements of $array after applying the callback function to each one recursively.
|
||||
Particularly useful for avoiding errors when calling functions that only accept scalar values on an array that could
|
||||
contain nested arrays, such as $_GET or $_POST.
|
||||
</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::array_map_deep($_POST, 'htmlentities');
|
||||
=> Recursively escapes each scalar value in $_POST
|
||||
util::array_map_deep($_POST, 'htmlentities', TRUE);
|
||||
=> Recursively escapes each value in $_POST regardless of its type</pre>
|
||||
</article>
|
||||
|
||||
<article id="array_pluck">
|
||||
<p>
|
||||
<span class="header">array_pluck</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">array_pluck</span>(array <span class="param">$array</span>, string <span class="param">$field</span>[, bool <span class="param">$preserve_keys</span>, bool <span class="param">$remove_nomatches</span>])
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Replaces each value in an array with the specified field of the array or object that used to be the value. Very
|
||||
useful when you have an array of objects or arrays from a database, and you only want one specific field. For
|
||||
example, you want an array of emails from an array of users.
|
||||
</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::array_pluck([['val' => 1], ['val' => 2], ['val' => 3]], 'val');
|
||||
=> Returns [1, 2, 3]
|
||||
util::array_pluck($users, 'email');
|
||||
=> Returns an array of email addresses for each user</pre>
|
||||
</article>
|
||||
|
||||
<article id="array_search_deep">
|
||||
<p>
|
||||
<span class="header">array_search_deep</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">array_search_deep</span>(array <span class="param">$array</span>, mixed <span class="param">$search</span>[, string <span class="param">$field</span> = FALSE])
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Allows you to search for a value in an array of arrays or an array of objects, and return the key of the value
|
||||
that matches the search criteria. If $field is unspecified, the entire array/object is searched.
|
||||
</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::array_search_deep($_POST, 'delete_post');
|
||||
=> Might return 'do' if $_POST['do']['action'] = 'delete_post'
|
||||
util::array_search_deep($users, 'rogue_coder', 'username');
|
||||
=> Might return 5 if $users[5]->username = 'rogue_coder'</pre>
|
||||
</article>
|
||||
|
||||
<article id="array_clean">
|
||||
<p>
|
||||
<span class="header">array_clean</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">array_clean</span>(array <span class="param">$array</span>)
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Remove all null/empty/false values from the given array.
|
||||
</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::array_clean( array( 'a', 'b', '', null, false, 0) );<br />=> Returns array('a', 'b');</pre>
|
||||
</article>
|
||||
|
||||
</section>
|
||||
|
||||
<h2 id="urls">URL Functions</h2>
|
||||
|
||||
<section>
|
||||
<article id="add_query_arg">
|
||||
<p>
|
||||
<span class="header">add_query_arg</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">add_query_arg</span>()
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>Adds one ore more query args to the query string of the current URL or a given URL</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::add_query_arg( 'user', '5', '/admin/users?action=edit' );
|
||||
=> Returns '/admin/users?action=edit&user=5'
|
||||
util::add_query_arg( [ 'user' => 5, 'action' => 'edit' ], '/admin/users' );
|
||||
=> Returns '/admin/users?user=5&action=edit'</pre>
|
||||
</article>
|
||||
|
||||
<article id="get_current_url">
|
||||
<p>
|
||||
<span class="header">get_current_url</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">get_current_url</span>()
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>Returns the current URL with hostname</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::get_current_url();
|
||||
=> Returns 'http://brandonwamboldt.ca/utilphp/'</pre>
|
||||
</article>
|
||||
|
||||
<article id="is_https">
|
||||
<p>
|
||||
<span class="header">is_https</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">is_https</span>()
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>Returns true if the current page is being loaded over https, false if it isn't</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::is_https();
|
||||
=> Returns false</pre>
|
||||
</article>
|
||||
|
||||
<article id="http_build_url">
|
||||
<p>
|
||||
<span class="header">http_build_url</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">http_build_url</span>([mixed $url[, mixed $parts[, int $flags = HTTP_URL_REPLACE[, array &amo;$new_url]]]])
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Pure PHP implementation/polyfill for <a href="http://php.net/http_build_url">http_build_url</a>
|
||||
which requires pecl_http to be installed.
|
||||
</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>echo util::http_build_url("http://user@www.example.com/pub/index.php?a=b#files",
|
||||
array(
|
||||
"scheme" => "ftp",
|
||||
"host" => "ftp.example.com",
|
||||
"path" => "files/current/",
|
||||
"query" => "a=c"
|
||||
),
|
||||
HTTP_URL_STRIP_AUTH | HTTP_URL_JOIN_PATH | HTTP_URL_JOIN_QUERY | HTTP_URL_STRIP_FRAGMENT
|
||||
);</pre>
|
||||
|
||||
<p>The above example will output:</p>
|
||||
|
||||
<pre>ftp://ftp.example.com/pub/files/current/?a=c</pre>
|
||||
</article>
|
||||
|
||||
<article id="is_https">
|
||||
<p>
|
||||
<span class="header">is_https</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">is_https</span>()
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>Returns true if the current page is being loaded over https, false if it isn't</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::is_https();
|
||||
=> Returns false</pre>
|
||||
</article>
|
||||
|
||||
<article id="remove_query_arg">
|
||||
<p>
|
||||
<span class="header">remove_query_arg</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">remove_query_arg</span>( array|string <span class="param">$query_args</span>[, string <span class="param">$url</span>])
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>Removes one ore more query args from the query string of the current URL or a given URL</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::remove_query_arg( 'action', '/admin/users?action=edit&user=5' );
|
||||
=> Returns '/admin/users?user=5'
|
||||
util::remove_query_arg( [ 'user', 'action'], '/admin/users?action=edit&user=5' );
|
||||
=> Returns '/admin/users'</pre>
|
||||
</article>
|
||||
|
||||
<article id="slugify">
|
||||
<p>
|
||||
<span class="header">slugify</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">slugify</span>(string <span class="param">$string</span>[, string <span class="param">$separator</span> = "-", bool <span class="param">$css_mode</span> = FALSE])
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Generate a string safe for use in URLs from any given string. Converts any accent characters
|
||||
to their equivalent normal characters and converts any other non-alphanumeric characters to
|
||||
dashes, then converts any sequence of two or more dashes to a single dash. This function
|
||||
generates slugs safe for use as URLs, and if you pass TRUE as the second parameter, it will
|
||||
create strings safe for use as CSS classes or IDs.
|
||||
</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::slugify('This is a random --string with an Ãccent');
|
||||
=> Returns 'this-is-a-random-string-with-an-accent'
|
||||
util::slugify('Another String', '.');
|
||||
=> Returns 'another.string'</pre>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<h2 id="strings">String Functions</h2>
|
||||
|
||||
<section>
|
||||
<article id="htmlentities">
|
||||
<p>
|
||||
<span class="header">htmlentities</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">htmlentities</span>(string <span class="param">$string</span>[, bool <span class="param">$preserve_encoded_entities</span> = FALSE])
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Executes htmlentities with ENT_QUOTES set by default. However, if you pass TRUE as
|
||||
the second parameter, it will not re-encode entities that are already encoded.
|
||||
</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::htmlentities('this string < this string', TRUE);
|
||||
=> Returns 'this string < this string'</pre>
|
||||
</article>
|
||||
|
||||
<article id="htmlspecialchars">
|
||||
<p>
|
||||
<span class="header">htmlspecialchars</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">htmlspecialchars</span>(string <span class="param">$string</span>[, bool <span class="param">$preserve_encoded_entities</span> = FALSE])
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Executes htmlspecialchars with ENT_QUOTES set by default. However, if you pass TRUE as
|
||||
the second parameter, it will not re-encode entities that are already encoded.
|
||||
</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::htmlspecialchars('this string < this string', TRUE);
|
||||
=> Returns 'this string < this string'</pre>
|
||||
</article>
|
||||
|
||||
<article id="linkify">
|
||||
<p>
|
||||
<span class="header">linkify</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">linkify</span>(string <span class="param">$text</span>)
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>Find's any URLs in the specified text and wraps them with HTML anchor tags</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::linkify('this string has a link to www.google.com');
|
||||
=> Returns 'this string has a link to <a href="http://wwww.google.com/">www.google.com</a>'</pre>
|
||||
</article>
|
||||
|
||||
<article id="match_string">
|
||||
<p>
|
||||
<span class="header">match_string</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">match_string</span>(string <span class="param">$pattern</span>, string <span class="param">$string</span>[, bool <span class="param">$caseSensitive</span> = true])
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Check if a string matches a given pattern. You can use '*' as a wildcard character.
|
||||
</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::match_string("test/*", "test/my/test");
|
||||
=> Returns true
|
||||
util::match_string("test/", "test/my/test");
|
||||
=> Returns false</pre>
|
||||
</article>
|
||||
|
||||
<article id="random_string">
|
||||
<p>
|
||||
<span class="header">random_string</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">random_string</span>(int <span class="param">$length</span>[, bool <span class="param">$human_friendly</span> = TRUE, bool <span class="param">$include_symbols</span> = FALSE, bool <span class="param">$no_duplicate_chars</span> = FALSE])
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Generates a random string of the specified length. Human friendly mode
|
||||
will exclude characters that can be confused with other characters, such
|
||||
as 0 (zero) and O (capital o), 1 (one) and l (lowercase L).
|
||||
</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::random_string(8);
|
||||
=> Returns 'a6BiF4UW'</pre>
|
||||
</article>
|
||||
|
||||
<article id="number_to_word">
|
||||
<p>
|
||||
<span class="header">number_to_word</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">number_to_word</span>(int|float <span class="param">$number</span>)
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>Converts a number into its text equivalent. For example, 56 becomes fifty-six.</p>
|
||||
|
||||
<pre>util::number_to_word(512.5);
|
||||
=> Returns 'five hundred and twelve point five'</pre>
|
||||
</article>
|
||||
|
||||
<article id="ordinal">
|
||||
<p>
|
||||
<span class="header">ordinal</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">ordinal</span>(int <span class="param">$number</span>)
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>Returns the ordinal version of a number (appends th, st, nd, rd)</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::ordinal(22);
|
||||
=> Returns '22nd'</pre>
|
||||
</article>
|
||||
|
||||
<article id="remove_accents">
|
||||
<p>
|
||||
<span class="header">remove_accents</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">remove_accents</span>(string <span class="param">$string</span>)
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>Converts all accent characters to their ASCII equivalents</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::remove_accents('Àccent');
|
||||
=> Returns 'Accent'</pre>
|
||||
</article>
|
||||
|
||||
<article id="secure_random_string">
|
||||
<p>
|
||||
<span class="header">secure_random_string</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">secure_random_string</span>(int <span class="param">$length</span>)
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>Generate a random string of characters. Will attempt to use a secure source (openssl).</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::secure_random_string(16);
|
||||
=> Returns '5bB1RJH0cQhNjviT'</pre>
|
||||
</article>
|
||||
|
||||
<article id="seems_utf8">
|
||||
<p>
|
||||
<span class="header">seems_utf8</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">seems_utf8</span>(string <span class="param">$string</span>)
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>Checks to see if a given string is UTF-8 encoded/safe</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::seems_utf8('This is some random string user input');
|
||||
=> Returns true</pre>
|
||||
</article>
|
||||
|
||||
<article id="safe_truncate">
|
||||
<p>
|
||||
<span class="header">safe_truncate</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">safe_truncate</span>(string <span class="param">$string</span>, int <span class="param">$length</span>[, string <span class="param">$append</span> = '...'])
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>Truncate a string to a specified length without cutting a word off</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::safe_truncate('The quick brown fox jumps over the lazy dog', 24);
|
||||
=> Returns 'The quick brown fox...'</pre>
|
||||
</article>
|
||||
|
||||
<article id="size_format">
|
||||
<p>
|
||||
<span class="header">size_format</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">size_format</span>(int <span class="param">$bytes</span>[, int <span class="param">$decimals</span> = 0])
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>Formats an integer as a human friendly size string, such as 4 KiB.</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::size_format( 25151251, 2 );
|
||||
=> Returns '23.99 MiB'</pre>
|
||||
</article>
|
||||
|
||||
<article id="str_to_bool">
|
||||
<p>
|
||||
<span class="header">str_to_bool</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">str_to_bool</span>(string <span class="param">$string</span>)
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>Converts a string to boolean, looking for yes/no words like 'yes', 'no', 'true', 'false', 'y', 'n', etc</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::str_to_bool('yes');
|
||||
=> Returns true</pre>
|
||||
</article>
|
||||
|
||||
<article id="zero_pad">
|
||||
<p>
|
||||
<span class="header">zero_pad</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">zero_pad</span>(int <span class="param">$number</span>, int <span class="param">$length</span>)
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>Pads a given number with zeroes on the left</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::zero_pad(341, 8);
|
||||
=> Returns '00000341'</pre>
|
||||
</article>
|
||||
|
||||
<article id="strip_space">
|
||||
<p>
|
||||
<span class="header">strip_space</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">strip_space</span>(string <span class="param">$string</span>)
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>Strip all withspace from the given string</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::strip_space(' The quick brown fox jumps over the lazy dog ');
|
||||
=> Returns 'Thequickbrownfoxjumpsoverthelazydog'</pre>
|
||||
</article>
|
||||
|
||||
<article id="sanitize_string">
|
||||
<p>
|
||||
<span class="header">sanitize_string</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">sanitize_string</span>(string <span class="param">$string</span>)
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Sanitize a string by performing the following operation :
|
||||
<ul>
|
||||
<li>Remove accents</li>
|
||||
<li>Lower the string</li>
|
||||
<li>Remove punctuation characters</li>
|
||||
<li>Strip whitespaces</li>
|
||||
</ul>
|
||||
|
||||
</p>
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::sanitize_string(' Benoit! à New-York? j’ai perçu 1 % : Qu’as-tu "gagné" chez M. V. Noël? Dix francs.');
|
||||
=> Returns 'benoitanewyorkjaipercu1quastugagnechezmvnoeldixfrancs'</pre>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<h2 id="files">Files</h2>
|
||||
|
||||
<section>
|
||||
<article id="full_permissions">
|
||||
<p>
|
||||
<span class="header">full_permissions</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">full_permissions</span>(string <span class="param">$file</span>)
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>Returns the file permissions as a nice string, like -rw-r--r--</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::full_permissions('/etc/passwd');
|
||||
=> Returns '-rw-r--r--'</pre>
|
||||
</article>
|
||||
|
||||
<article id="rmdir">
|
||||
<p>
|
||||
<span class="header">rmdir</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">rmdir</span>(string <span class="param">$dir</span>[, bool <span class="param">$traverseSymlinks</span> = false])
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>Recursively deletes a directories (including all contents).</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::rmdir('/tmp/working/dir');
|
||||
=> Returns true</pre>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<h2 id="serialization">Serialization</h2>
|
||||
|
||||
<section>
|
||||
<article id="is_serialized">
|
||||
<p>
|
||||
<span class="header">is_serialized</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">is_serialized</span>(mixed <span class="param">$data</span>)
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>Checks to see if a given variable is a seralized data structure</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::is_serialized( 'a:0:{}' );
|
||||
=> Returns true</pre>
|
||||
</article>
|
||||
|
||||
<article id="maybe_serialize">
|
||||
<p>
|
||||
<span class="header">maybe_serialize</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">maybe_serialize</span>(mixed <span class="param">$data</span>)
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>Serialize data, if needed to store in plaintext (Arrays or objects)</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::maybe_serialize( 5 );
|
||||
=> Returns 5
|
||||
util::maybe_serialize( array() );
|
||||
=> Returns 'a:0:{}'</pre>
|
||||
</article>
|
||||
|
||||
<article id="maybe_unserialize">
|
||||
<p>
|
||||
<span class="header">maybe_unserialize</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">maybe_unserialize</span>(mixed <span class="param">$data</span>)
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>Unserialize data, if it's a serialized string</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::maybe_unserialize(5);
|
||||
=> Returns 5
|
||||
util::maybe_unserialize("a:0:{}");
|
||||
=> Returns array()</pre>
|
||||
</article>
|
||||
|
||||
<article id="fix_broken_serialization">
|
||||
<p>
|
||||
<span class="header">fix_broken_serialization</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">fix_broken_serialization</span>(mixed <span class="param">$data</span>)
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Attempt to fix a broken serialization string (e.g. where string offsets are incorrect). Can fix
|
||||
errors that frequently occur with mismatched character sets or higher-than-ASCII characters.
|
||||
</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::fix_broken_serialization('a:1:{s:4:"test";s:4:"abc";}');
|
||||
=> Returns 'a:1:{s:4:"test";s:3:"abc";}'</pre>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<h2 id="other">Other</h2>
|
||||
|
||||
<section>
|
||||
<article id="force_download">
|
||||
<p>
|
||||
<span class="header">force_download</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">force_download</span>(string <span class="param">$filename</span>, string <span class="param">$content</span> = FALSE)
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Transmit headers that force a browser to display the download file dialog. Cross
|
||||
browser compatible. Only fires if headers have not already been sent.
|
||||
</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::force_download( 'export.csv', file_get_contents( 'securefile.csv' ) );
|
||||
=> The user will be prompted to download the file</pre>
|
||||
</article>
|
||||
|
||||
<article id="get_client_ip">
|
||||
<p>
|
||||
<span class="header">get_client_ip</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">get_client_ip</span>(bool <span class="param">$trust_proxy_headers</span> = FALSE)
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Returns the IP address of the client. Only enable $trust_proxy_headers if your server is behind a proxy
|
||||
that sets the HTTP_CLIENT_IP and HTTP_X_FORWARDED_FOR headers.
|
||||
</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::get_client_ip();
|
||||
=> Returns '12.123.12.100'</pre>
|
||||
</article>
|
||||
|
||||
<article id="get_gravatar">
|
||||
<p>
|
||||
<span class="header">get_gravatar</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">get_gravatar</span>(string <span class="param">$email</span>, int <span class="param">$size</span> = 32)
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>Return the URL to a user's gravatar</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::get_gravatar('brandon.wamboldt@gmail.com');
|
||||
=> Returns 'http://www.gravatar.com/avatar/46679faeb6780ecb1ea57527fdc66eb3?s=32'</pre>
|
||||
</article>
|
||||
|
||||
<article id="human_time_diff">
|
||||
<p>
|
||||
<span class="header">human_time_diff</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">human_time_diff</span>(int <span class="param">$from</span>, int <span class="param">$to</span> = '', int <span class="param">$as_text</span> = FALSE, string <span class="param">$suffix</span> = ' ago')
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>Converts a unix timestamp to a relative time string, such as "3 days ago" or "2 weeks ago"</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::human_time_diff(time() - 7400);
|
||||
=> Returns '2 hours ago'
|
||||
util::human_time_diff(time() - 7400, '', TRUE);
|
||||
=> Returns 'two hours ago'</pre>
|
||||
</article>
|
||||
|
||||
<article id="nocache_headers">
|
||||
<p>
|
||||
<span class="header">nocache_headers</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">nocache_headers</span>(mixed <span class="param">$data</span>)
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>Sets the headers to prevent caching for the different browsers</p>
|
||||
|
||||
<p>
|
||||
Different browsers support different nocache headers, so several headers must be sent
|
||||
so that all of them get the point that no caching should occur
|
||||
</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::nocache_headers();</pre>
|
||||
</article>
|
||||
|
||||
<article id="utf8_headers">
|
||||
<p>
|
||||
<span class="header">utf8_headers</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">utf8_headers</span>(mixed <span class="param">$content_type</span> = 'text/html')
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>Transmit UTF-8 content headers if the headers haven't already been sent</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::utf8_headers();</pre>
|
||||
</article>
|
||||
|
||||
<article id="validate_email">
|
||||
<p>
|
||||
<span class="header">validate_email</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">validate_email</span>(string <span class="param">$possible_email</span>)
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>Validate an email address</p>
|
||||
|
||||
<p><strong>Usage:</strong></p>
|
||||
|
||||
<pre>util::validate_email( 'brandon.wamboldt@gmail.com' );
|
||||
=> Returns true
|
||||
util::validate_email( 'not an email' );
|
||||
=> Returns false</pre>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<h2 id="constants">Constants</h2>
|
||||
|
||||
<section>
|
||||
<article id="SECONDS_IN_A_MINUTE">
|
||||
<p>
|
||||
<span class="header">SECONDS_IN_A_MINUTE</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">SECONDS_IN_A_MINUTE</span>
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>The number of seconds in a minute, useful for making code more verbose</p>
|
||||
</article>
|
||||
|
||||
<article id="SECONDS_IN_AN_HOUR">
|
||||
<p>
|
||||
<span class="header">SECONDS_IN_AN_HOUR</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">SECONDS_IN_AN_HOUR</span>
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>The number of seconds in an hour, useful for making code more verbose</p>
|
||||
</article>
|
||||
|
||||
<article id="SECONDS_IN_A_DAY">
|
||||
<p>
|
||||
<span class="header">SECONDS_IN_A_DAY</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">SECONDS_IN_A_DAY</span>
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>The number of seconds in a day, useful for making code more verbose</p>
|
||||
</article>
|
||||
|
||||
<article id="SECONDS_IN_A_WEEK">
|
||||
<p>
|
||||
<span class="header">SECONDS_IN_A_WEEK</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">SECONDS_IN_A_WEEK</span>
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>The number of seconds in a week (7 days), useful for making code more verbose</p>
|
||||
</article>
|
||||
|
||||
<article id="SECONDS_IN_A_MONTH">
|
||||
<p>
|
||||
<span class="header">SECONDS_IN_A_MONTH</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">SECONDS_IN_A_MONTH</span>
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>The number of seconds in a month (30 days), useful for making code more verbose</p>
|
||||
</article>
|
||||
|
||||
<article id="SECONDS_IN_A_YEAR">
|
||||
<p>
|
||||
<span class="header">SECONDS_IN_A_YEAR</span>
|
||||
<code>
|
||||
<span class="util_class">util::</span><span class="func_name">SECONDS_IN_A_YEAR</span>
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>The number of seconds in a year (365 days), useful for making code more verbose</p>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<h2 id="changelog">Change Log</h2>
|
||||
|
||||
<!--
|
||||
Find: `(.*?)`
|
||||
Replace: <code>\1<\/code>
|
||||
|
||||
Find: \[(.*?)\]\((.*?)\)
|
||||
Replace: <a href="\2">\1</a>
|
||||
-->
|
||||
|
||||
<p class="desc-text">
|
||||
<span class="header">1.1.0</span><br>
|
||||
|
||||
This release introduces a deprecation notice for <code>slugify()</code>, please update your code.<br><br>
|
||||
|
||||
- Added a cryptographically secure random string function <code>secure_random_string</code>. Thanks to @abhimanyusharma003 via <a href="https://github.com/brandonwamboldt/utilphp/pull/53">Pull Request #53</a><br>
|
||||
- Added <code>limit_characters</code> and <code>limit_words</code> functions. Thanks to @abhimanyusharma003 via <a href="https://github.com/brandonwamboldt/utilphp/pull/55">Pull Request #55</a><br>
|
||||
- Added <code>rmdir</code> method to recursively delete a directory. Thanks to @ARACOOOL via <a href="https://github.com/brandonwamboldt/utilphp/pull/56">Pull Request #56</a><br>
|
||||
- Added <code>set_executable</code>, <code>set_readable</code>, <code>set_writable</code>, <code>directory_size</code>, <code>directory_contents</code> and <code>get_user_dir</code> functions. Thanks to @sergserg via <a href="https://github.com/brandonwamboldt/utilphp/pull/70">Pull Request #70</a><br>
|
||||
- Changed parameter ordering for <code>slugify</code>, <code>$css_mode</code> is now the third argument. For backwards compatibility, the old order will still work but it will generate an <code>E_USER_DEPRECATED</code> warning. Thanks to @abhimanyusharma003 via <a href="https://github.com/brandonwamboldt/utilphp/pull/71">Pull Request #71</a><br>
|
||||
- Added <code>match_string</code> method. Thanks to @abhimanyusharma003 via <a href="https://github.com/brandonwamboldt/utilphp/pull/72">Pull Request #72</a><br>
|
||||
- Renamed internal methods (protected ones) for PSR-2 compliance<br>
|
||||
- General performance improvements, code quality improvements, and increased unit test coverage (special thanks to @hopeseekr for getting us near 100% coverage)<br>
|
||||
</p>
|
||||
|
||||
<p class="desc-text">
|
||||
<span class="header">1.0.7</span><br>
|
||||
- Added <code>fix_broken_serialization</code> to fix broken serialized strings (Thanks to @hopeseekr via <a href="https://github.com/brandonwamboldt/utilphp/pull/48">Pull Request #48</a>)<br>
|
||||
- Fixed <code>get_current_url</code> appending port 80 or 443 when not needed (Thanks to @scottchiefbaker via <a href="https://github.com/brandonwamboldt/utilphp/pull/49">Pull Request #49</a>)<br>
|
||||
- <code>var_dump</code> can now handle recursive data structures without crashing<br>
|
||||
- <code>var_dump</code> code was minified and cleaned up<br>
|
||||
- <code>array_flatten</code> was optimized (thanks to @hopeseekr via <a href="https://github.com/brandonwamboldt/utilphp/pull/47">Pull Request #47</a>)<br>
|
||||
- <code>remove_accents</code> was completely rewritten and is now ~4x faster<br>
|
||||
</p>
|
||||
|
||||
<p class="desc-text">
|
||||
<span class="header">1.0.6</span><br>
|
||||
- Added <code>start_with</code> function<br>
|
||||
- Added <code>ends_with</code> function<br>
|
||||
- Added <code>str_contains</code> function<br>
|
||||
- Added <code>str_icontains</code> function<br>
|
||||
- Added <code>get_file_ext</code> function<br>
|
||||
- Fixing permissions on the files & directories<br>
|
||||
- Fixing a bug with the include path of util.php<br>
|
||||
</p>
|
||||
|
||||
<p class="desc-text">
|
||||
<span class="header">1.0.5</span><br>
|
||||
- <a href="https://github.com/brandonwamboldt/utilphp/issues/29">Issue #29</a> Fixed error in <code>var_dump</code> if mbstring extension wasn't present<br>
|
||||
- Adding Composer support<br>
|
||||
- Updating license from GPL to MIT<br>
|
||||
- Adding Changelog to project<br>
|
||||
- Bumping minimum version to PHP 5.3.3<br>
|
||||
</p>
|
||||
|
||||
<p class="desc-text">
|
||||
<span class="header">1.0.4</span><br />
|
||||
- <a href="https://github.com/brandonwamboldt/utilphp/issues/22">Issue #22</a> Removed all superglobal *_get functions, you can use the modified <code>array_get</code> now<br />
|
||||
- <a href="https://github.com/brandonwamboldt/utilphp/issues/22">Issue #22</a> Modifed the behaviour of <code>array_get</code>, see documentation<br />
|
||||
- <a href="https://github.com/brandonwamboldt/utilphp/pull/21">Pull Request #21</a> Added multibyte support to html* functions<br />
|
||||
- <a href="https://github.com/brandonwamboldt/utilphp/issues/9">Issue #9</a> Removed the <code>str_to_utf8</code> function<br />
|
||||
- <a href="https://github.com/brandonwamboldt/utilphp/issues/3">Issue #3</a> Removed the absint function<br />
|
||||
- Removed declare() from util.php to avoid errors<br />
|
||||
- Updated PHPUnit tests to use PHPUnit 3.6
|
||||
</p>
|
||||
|
||||
<p class="desc-text">
|
||||
<span class="header">1.0.3</span><br />
|
||||
- <a href="https://github.com/brandonwamboldt/utilphp/issues/16">Issue #16</a> Improved performance of <code>slugify</code><br />
|
||||
- <a href="https://github.com/brandonwamboldt/utilphp/issues/14">Issue #14</a> Modified the regex for <code>seems_utf8</code> to be more accurate<br />
|
||||
- <a href="https://github.com/brandonwamboldt/utilphp/issues/13">Issue #13</a> Changed <code>validate_email</code> to be wrapper for <code>filter_var</code><br />
|
||||
- Added 'ok' to the list of yes words for <code>str_to_bool</code><br />
|
||||
- <code>str_to_bool</code> matches no followed by any number of 'o's
|
||||
</p>
|
||||
|
||||
<p class="desc-text">
|
||||
<span class="header">1.0.2</span><br />
|
||||
- <a href="https://github.com/brandonwamboldt/utilphp/issues/12">Issue #12</a> <code>get_current_url</code> now includes the port and user/password if required<br />
|
||||
- <a href="https://github.com/brandonwamboldt/utilphp/issues/11">Issue #11</a> <code>human_time_diff</code> now uses the DateTime functions<br />
|
||||
- <a href="https://github.com/brandonwamboldt/utilphp/issues/10">Issue #10</a> <code>is_https</code> no longer checks the port as well
|
||||
</p>
|
||||
|
||||
<p class="desc-text">
|
||||
<span class="header">1.0.1</span><br />
|
||||
- <a href="https://github.com/brandonwamboldt/utilphp/issues/7">Issue #7</a> Added the <code style="color:#DA72F3">$trust_proxy_headers</code> parameter to <code>get_client_ip</code><br />
|
||||
- <a href="https://github.com/brandonwamboldt/utilphp/issues/6">Issue #6</a> Removed <code>is_isset</code> as the function did not work as intended<br />
|
||||
- <a href="https://github.com/brandonwamboldt/utilphp/issues/6">Issue #6</a> Removed <code>is_empty</code> as it is redundant, use ! with function calls instead<br />
|
||||
- Fixed a bug with <code>get_gravatar</code>
|
||||
</p>
|
||||
|
||||
<p class="desc-text">
|
||||
<span class="header">1.0.0</span><br />
|
||||
Initial release of util.php.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit backupGlobals="false"
|
||||
backupStaticAttributes="false"
|
||||
colors="true"
|
||||
convertErrorsToExceptions="true"
|
||||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
processIsolation="false"
|
||||
stopOnFailure="false"
|
||||
syntaxCheck="false"
|
||||
>
|
||||
<testsuites>
|
||||
<testsuite name="Tests suite">
|
||||
<directory>./tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<filter>
|
||||
<whitelist>
|
||||
<directory>./src</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
<logging>
|
||||
<log type="coverage-clover" target="build/logs/clover.xml"/>
|
||||
</logging>
|
||||
</phpunit>
|
||||
+2535
@@ -0,0 +1,2535 @@
|
||||
<?php
|
||||
|
||||
namespace utilphp;
|
||||
|
||||
/**
|
||||
* util.php
|
||||
*
|
||||
* util.php is a library of helper functions for common tasks such as
|
||||
* formatting bytes as a string or displaying a date in terms of how long ago
|
||||
* it was in human readable terms (E.g. 4 minutes ago). The library is entirely
|
||||
* contained within a single file and hosts no dependencies. The library is
|
||||
* designed to avoid any possible conflicts.
|
||||
*
|
||||
* @author Brandon Wamboldt <brandon.wamboldt@gmail.com>
|
||||
* @link http://github.com/brandonwamboldt/utilphp/ Official Documentation
|
||||
*/
|
||||
class util
|
||||
{
|
||||
/**
|
||||
* A constant representing the number of seconds in a minute, for
|
||||
* making code more verbose
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
const SECONDS_IN_A_MINUTE = 60;
|
||||
|
||||
/**
|
||||
* A constant representing the number of seconds in an hour, for making
|
||||
* code more verbose
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
const SECONDS_IN_A_HOUR = 3600;
|
||||
const SECONDS_IN_AN_HOUR = 3600;
|
||||
|
||||
/**
|
||||
* A constant representing the number of seconds in a day, for making
|
||||
* code more verbose
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
const SECONDS_IN_A_DAY = 86400;
|
||||
|
||||
/**
|
||||
* A constant representing the number of seconds in a week, for making
|
||||
* code more verbose
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
const SECONDS_IN_A_WEEK = 604800;
|
||||
|
||||
/**
|
||||
* A constant representing the number of seconds in a month (30 days),
|
||||
* for making code more verbose
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
const SECONDS_IN_A_MONTH = 2592000;
|
||||
|
||||
/**
|
||||
* A constant representing the number of seconds in a year (365 days),
|
||||
* for making code more verbose
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
const SECONDS_IN_A_YEAR = 31536000;
|
||||
|
||||
/**
|
||||
* URL constants as defined in the PHP Manual under "Constants usable with
|
||||
* http_build_url()".
|
||||
*
|
||||
* @see http://us2.php.net/manual/en/http.constants.php#http.constants.url
|
||||
*/
|
||||
const HTTP_URL_REPLACE = 1;
|
||||
const HTTP_URL_JOIN_PATH = 2;
|
||||
const HTTP_URL_JOIN_QUERY = 4;
|
||||
const HTTP_URL_STRIP_USER = 8;
|
||||
const HTTP_URL_STRIP_PASS = 16;
|
||||
const HTTP_URL_STRIP_AUTH = 32;
|
||||
const HTTP_URL_STRIP_PORT = 64;
|
||||
const HTTP_URL_STRIP_PATH = 128;
|
||||
const HTTP_URL_STRIP_QUERY = 256;
|
||||
const HTTP_URL_STRIP_FRAGMENT = 512;
|
||||
const HTTP_URL_STRIP_ALL = 1024;
|
||||
|
||||
/**
|
||||
* A collapse icon, using in the dump_var function to allow collapsing
|
||||
* an array or object
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $icon_collapse = 'iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAMAAADXT/YiAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2RpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo3MjlFRjQ2NkM5QzJFMTExOTA0MzkwRkI0M0ZCODY4RCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpFNzFDNDQyNEMyQzkxMUUxOTU4MEM4M0UxRDA0MUVGNSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpFNzFDNDQyM0MyQzkxMUUxOTU4MEM4M0UxRDA0MUVGNSIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3NDlFRjQ2NkM5QzJFMTExOTA0MzkwRkI0M0ZCODY4RCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3MjlFRjQ2NkM5QzJFMTExOTA0MzkwRkI0M0ZCODY4RCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PuF4AWkAAAA2UExURU9t2DBStczM/1h16DNmzHiW7iNFrypMvrnD52yJ4ezs7Onp6ejo6P///+Tk5GSG7D9h5SRGq0Q2K74AAAA/SURBVHjaLMhZDsAgDANRY3ZISnP/y1ZWeV+jAeuRSky6cKL4ryDdSggP8UC7r6GvR1YHxjazPQDmVzI/AQYAnFQDdVSJ80EAAAAASUV
Line truncated
|
||||
|
||||
/**
|
||||
* A collapse icon, using in the dump_var function to allow collapsing
|
||||
* an array or object
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $icon_expand = 'iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAMAAADXT/YiAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2RpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo3MTlFRjQ2NkM5QzJFMTExOTA0MzkwRkI0M0ZCODY4RCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpFQzZERTJDNEMyQzkxMUUxODRCQzgyRUNDMzZEQkZFQiIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpFQzZERTJDM0MyQzkxMUUxODRCQzgyRUNDMzZEQkZFQiIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3MzlFRjQ2NkM5QzJFMTExOTA0MzkwRkI0M0ZCODY4RCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3MTlFRjQ2NkM5QzJFMTExOTA0MzkwRkI0M0ZCODY4RCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PkmDvWIAAABIUExURU9t2MzM/3iW7ubm59/f5urq85mZzOvr6////9ra38zMzObm5rfB8FZz5myJ4SNFrypMvjBStTNmzOvr+mSG7OXl8T9h5SRGq/OfqCEAAABKSURBVHjaFMlbEoAwCEPRULXF2jdW9r9T4czcyUdA4XWB0IgdNSybxU9amMzHzDlPKKu7Fd1e6+wY195jW
Line truncated
|
||||
|
||||
private static $hasArray = false;
|
||||
|
||||
/**
|
||||
* Map of special non-ASCII characters and suitable ASCII replacement
|
||||
* characters.
|
||||
*
|
||||
* Part of the URLify.php Project <https://github.com/jbroadway/urlify/>
|
||||
*
|
||||
* @see https://github.com/jbroadway/urlify/blob/master/URLify.php
|
||||
*/
|
||||
public static $maps = array(
|
||||
'de' => array(/* German */
|
||||
'Ä' => 'Ae', 'Ö' => 'Oe', 'Ü' => 'Ue', 'ä' => 'ae', 'ö' => 'oe', 'ü' => 'ue', 'ß' => 'ss',
|
||||
'ẞ' => 'SS'
|
||||
),
|
||||
'latin' => array(
|
||||
'À' => 'A', 'Á' => 'A', 'Â' => 'A', 'Ã' => 'A', 'Ä' => 'A', 'Å' => 'A','Ă' => 'A', 'Æ' => 'AE', 'Ç' =>
|
||||
'C', 'È' => 'E', 'É' => 'E', 'Ê' => 'E', 'Ë' => 'E', 'Ì' => 'I', 'Í' => 'I', 'Î' => 'I',
|
||||
'Ï' => 'I', 'Ð' => 'D', 'Ñ' => 'N', 'Ò' => 'O', 'Ó' => 'O', 'Ô' => 'O', 'Õ' => 'O', 'Ö' =>
|
||||
'O', 'Ő' => 'O', 'Ø' => 'O','Ș' => 'S','Ț' => 'T', 'Ù' => 'U', 'Ú' => 'U', 'Û' => 'U', 'Ü' => 'U', 'Ű' => 'U',
|
||||
'Ý' => 'Y', 'Þ' => 'TH', 'ß' => 'ss', 'à' => 'a', 'á' => 'a', 'â' => 'a', 'ã' => 'a', 'ä' =>
|
||||
'a', 'å' => 'a', 'ă' => 'a', 'æ' => 'ae', 'ç' => 'c', 'è' => 'e', 'é' => 'e', 'ê' => 'e', 'ë' => 'e',
|
||||
'ì' => 'i', 'í' => 'i', 'î' => 'i', 'ï' => 'i', 'ð' => 'd', 'ñ' => 'n', 'ò' => 'o', 'ó' =>
|
||||
'o', 'ô' => 'o', 'õ' => 'o', 'ö' => 'o', 'ő' => 'o', 'ø' => 'o', 'ș' => 's', 'ț' => 't', 'ù' => 'u', 'ú' => 'u',
|
||||
'û' => 'u', 'ü' => 'u', 'ű' => 'u', 'ý' => 'y', 'þ' => 'th', 'ÿ' => 'y'
|
||||
),
|
||||
'latin_symbols' => array(
|
||||
'©' => '(c)'
|
||||
),
|
||||
'el' => array(/* Greek */
|
||||
'α' => 'a', 'β' => 'b', 'γ' => 'g', 'δ' => 'd', 'ε' => 'e', 'ζ' => 'z', 'η' => 'h', 'θ' => '8',
|
||||
'ι' => 'i', 'κ' => 'k', 'λ' => 'l', 'μ' => 'm', 'ν' => 'n', 'ξ' => '3', 'ο' => 'o', 'π' => 'p',
|
||||
'ρ' => 'r', 'σ' => 's', 'τ' => 't', 'υ' => 'y', 'φ' => 'f', 'χ' => 'x', 'ψ' => 'ps', 'ω' => 'w',
|
||||
'ά' => 'a', 'έ' => 'e', 'ί' => 'i', 'ό' => 'o', 'ύ' => 'y', 'ή' => 'h', 'ώ' => 'w', 'ς' => 's',
|
||||
'ϊ' => 'i', 'ΰ' => 'y', 'ϋ' => 'y', 'ΐ' => 'i',
|
||||
'Α' => 'A', 'Β' => 'B', 'Γ' => 'G', 'Δ' => 'D', 'Ε' => 'E', 'Ζ' => 'Z', 'Η' => 'H', 'Θ' => '8',
|
||||
'Ι' => 'I', 'Κ' => 'K', 'Λ' => 'L', 'Μ' => 'M', 'Ν' => 'N', 'Ξ' => '3', 'Ο' => 'O', 'Π' => 'P',
|
||||
'Ρ' => 'R', 'Σ' => 'S', 'Τ' => 'T', 'Υ' => 'Y', 'Φ' => 'F', 'Χ' => 'X', 'Ψ' => 'PS', 'Ω' => 'W',
|
||||
'Ά' => 'A', 'Έ' => 'E', 'Ί' => 'I', 'Ό' => 'O', 'Ύ' => 'Y', 'Ή' => 'H', 'Ώ' => 'W', 'Ϊ' => 'I',
|
||||
'Ϋ' => 'Y'
|
||||
),
|
||||
'tr' => array(/* Turkish */
|
||||
'ş' => 's', 'Ş' => 'S', 'ı' => 'i', 'İ' => 'I', 'ç' => 'c', 'Ç' => 'C', 'ü' => 'u', 'Ü' => 'U',
|
||||
'ö' => 'o', 'Ö' => 'O', 'ğ' => 'g', 'Ğ' => 'G'
|
||||
),
|
||||
'ru' => array(/* Russian */
|
||||
'а' => 'a', 'б' => 'b', 'в' => 'v', 'г' => 'g', 'д' => 'd', 'е' => 'e', 'ё' => 'yo', 'ж' => 'zh',
|
||||
'з' => 'z', 'и' => 'i', 'й' => 'j', 'к' => 'k', 'л' => 'l', 'м' => 'm', 'н' => 'n', 'о' => 'o',
|
||||
'п' => 'p', 'р' => 'r', 'с' => 's', 'т' => 't', 'у' => 'u', 'ф' => 'f', 'х' => 'h', 'ц' => 'c',
|
||||
'ч' => 'ch', 'ш' => 'sh', 'щ' => 'sh', 'ъ' => '', 'ы' => 'y', 'ь' => '', 'э' => 'e', 'ю' => 'yu',
|
||||
'я' => 'ya',
|
||||
'А' => 'A', 'Б' => 'B', 'В' => 'V', 'Г' => 'G', 'Д' => 'D', 'Е' => 'E', 'Ё' => 'Yo', 'Ж' => 'Zh',
|
||||
'З' => 'Z', 'И' => 'I', 'Й' => 'J', 'К' => 'K', 'Л' => 'L', 'М' => 'M', 'Н' => 'N', 'О' => 'O',
|
||||
'П' => 'P', 'Р' => 'R', 'С' => 'S', 'Т' => 'T', 'У' => 'U', 'Ф' => 'F', 'Х' => 'H', 'Ц' => 'C',
|
||||
'Ч' => 'Ch', 'Ш' => 'Sh', 'Щ' => 'Sh', 'Ъ' => '', 'Ы' => 'Y', 'Ь' => '', 'Э' => 'E', 'Ю' => 'Yu',
|
||||
'Я' => 'Ya',
|
||||
'№' => ''
|
||||
),
|
||||
'uk' => array(/* Ukrainian */
|
||||
'Є' => 'Ye', 'І' => 'I', 'Ї' => 'Yi', 'Ґ' => 'G', 'є' => 'ye', 'і' => 'i', 'ї' => 'yi', 'ґ' => 'g'
|
||||
),
|
||||
'cs' => array(/* Czech */
|
||||
'č' => 'c', 'ď' => 'd', 'ě' => 'e', 'ň' => 'n', 'ř' => 'r', 'š' => 's', 'ť' => 't', 'ů' => 'u',
|
||||
'ž' => 'z', 'Č' => 'C', 'Ď' => 'D', 'Ě' => 'E', 'Ň' => 'N', 'Ř' => 'R', 'Š' => 'S', 'Ť' => 'T',
|
||||
'Ů' => 'U', 'Ž' => 'Z'
|
||||
),
|
||||
'pl' => array(/* Polish */
|
||||
'ą' => 'a', 'ć' => 'c', 'ę' => 'e', 'ł' => 'l', 'ń' => 'n', 'ó' => 'o', 'ś' => 's', 'ź' => 'z',
|
||||
'ż' => 'z', 'Ą' => 'A', 'Ć' => 'C', 'Ę' => 'e', 'Ł' => 'L', 'Ń' => 'N', 'Ó' => 'O', 'Ś' => 'S',
|
||||
'Ź' => 'Z', 'Ż' => 'Z'
|
||||
),
|
||||
'ro' => array(/* Romanian */
|
||||
'ă' => 'a', 'â' => 'a', 'î' => 'i', 'ș' => 's', 'ț' => 't', 'Ţ' => 'T', 'ţ' => 't'
|
||||
),
|
||||
'lv' => array(/* Latvian */
|
||||
'ā' => 'a', 'č' => 'c', 'ē' => 'e', 'ģ' => 'g', 'ī' => 'i', 'ķ' => 'k', 'ļ' => 'l', 'ņ' => 'n',
|
||||
'š' => 's', 'ū' => 'u', 'ž' => 'z', 'Ā' => 'A', 'Č' => 'C', 'Ē' => 'E', 'Ģ' => 'G', 'Ī' => 'i',
|
||||
'Ķ' => 'k', 'Ļ' => 'L', 'Ņ' => 'N', 'Š' => 'S', 'Ū' => 'u', 'Ž' => 'Z'
|
||||
),
|
||||
'lt' => array(/* Lithuanian */
|
||||
'ą' => 'a', 'č' => 'c', 'ę' => 'e', 'ė' => 'e', 'į' => 'i', 'š' => 's', 'ų' => 'u', 'ū' => 'u', 'ž' => 'z',
|
||||
'Ą' => 'A', 'Č' => 'C', 'Ę' => 'E', 'Ė' => 'E', 'Į' => 'I', 'Š' => 'S', 'Ų' => 'U', 'Ū' => 'U', 'Ž' => 'Z'
|
||||
),
|
||||
'vn' => array(/* Vietnamese */
|
||||
'Á' => 'A', 'À' => 'A', 'Ả' => 'A', 'Ã' => 'A', 'Ạ' => 'A', 'Ă' => 'A', 'Ắ' => 'A', 'Ằ' => 'A', 'Ẳ' => 'A', 'Ẵ' => 'A', 'Ặ' => 'A', 'Â' => 'A', 'Ấ' => 'A', 'Ầ' => 'A', 'Ẩ' => 'A', 'Ẫ' => 'A', 'Ậ' => 'A',
|
||||
'á' => 'a', 'à' => 'a', 'ả' => 'a', 'ã' => 'a', 'ạ' => 'a', 'ă' => 'a', 'ắ' => 'a', 'ằ' => 'a', 'ẳ' => 'a', 'ẵ' => 'a', 'ặ' => 'a', 'â' => 'a', 'ấ' => 'a', 'ầ' => 'a', 'ẩ' => 'a', 'ẫ' => 'a', 'ậ' => 'a',
|
||||
'É' => 'E', 'È' => 'E', 'Ẻ' => 'E', 'Ẽ' => 'E', 'Ẹ' => 'E', 'Ê' => 'E', 'Ế' => 'E', 'Ề' => 'E', 'Ể' => 'E', 'Ễ' => 'E', 'Ệ' => 'E',
|
||||
'é' => 'e', 'è' => 'e', 'ẻ' => 'e', 'ẽ' => 'e', 'ẹ' => 'e', 'ê' => 'e', 'ế' => 'e', 'ề' => 'e', 'ể' => 'e', 'ễ' => 'e', 'ệ' => 'e',
|
||||
'Í' => 'I', 'Ì' => 'I', 'Ỉ' => 'I', 'Ĩ' => 'I', 'Ị' => 'I', 'í' => 'i', 'ì' => 'i', 'ỉ' => 'i', 'ĩ' => 'i', 'ị' => 'i',
|
||||
'Ó' => 'O', 'Ò' => 'O', 'Ỏ' => 'O', 'Õ' => 'O', 'Ọ' => 'O', 'Ô' => 'O', 'Ố' => 'O', 'Ồ' => 'O', 'Ổ' => 'O', 'Ỗ' => 'O', 'Ộ' => 'O', 'Ơ' => 'O', 'Ớ' => 'O', 'Ờ' => 'O', 'Ở' => 'O', 'Ỡ' => 'O', 'Ợ' => 'O',
|
||||
'ó' => 'o', 'ò' => 'o', 'ỏ' => 'o', 'õ' => 'o', 'ọ' => 'o', 'ô' => 'o', 'ố' => 'o', 'ồ' => 'o', 'ổ' => 'o', 'ỗ' => 'o', 'ộ' => 'o', 'ơ' => 'o', 'ớ' => 'o', 'ờ' => 'o', 'ở' => 'o', 'ỡ' => 'o', 'ợ' => 'o',
|
||||
'Ú' => 'U', 'Ù' => 'U', 'Ủ' => 'U', 'Ũ' => 'U', 'Ụ' => 'U', 'Ư' => 'U', 'Ứ' => 'U', 'Ừ' => 'U', 'Ử' => 'U', 'Ữ' => 'U', 'Ự' => 'U',
|
||||
'ú' => 'u', 'ù' => 'u', 'ủ' => 'u', 'ũ' => 'u', 'ụ' => 'u', 'ư' => 'u', 'ứ' => 'u', 'ừ' => 'u', 'ử' => 'u', 'ữ' => 'u', 'ự' => 'u',
|
||||
'Ý' => 'Y', 'Ỳ' => 'Y', 'Ỷ' => 'Y', 'Ỹ' => 'Y', 'Ỵ' => 'Y', 'ý' => 'y', 'ỳ' => 'y', 'ỷ' => 'y', 'ỹ' => 'y', 'ỵ' => 'y',
|
||||
'Đ' => 'D', 'đ' => 'd'
|
||||
),
|
||||
'ar' => array(/* Arabic */
|
||||
'أ' => 'a', 'ب' => 'b', 'ت' => 't', 'ث' => 'th', 'ج' => 'g', 'ح' => 'h', 'خ' => 'kh', 'د' => 'd',
|
||||
'ذ' => 'th', 'ر' => 'r', 'ز' => 'z', 'س' => 's', 'ش' => 'sh', 'ص' => 's', 'ض' => 'd', 'ط' => 't',
|
||||
'ظ' => 'th', 'ع' => 'aa', 'غ' => 'gh', 'ف' => 'f', 'ق' => 'k', 'ك' => 'k', 'ل' => 'l', 'م' => 'm',
|
||||
'ن' => 'n', 'ه' => 'h', 'و' => 'o', 'ي' => 'y'
|
||||
),
|
||||
'sr' => array(/* Serbian */
|
||||
'ђ' => 'dj', 'ј' => 'j', 'љ' => 'lj', 'њ' => 'nj', 'ћ' => 'c', 'џ' => 'dz', 'đ' => 'dj',
|
||||
'Ђ' => 'Dj', 'Ј' => 'j', 'Љ' => 'Lj', 'Њ' => 'Nj', 'Ћ' => 'C', 'Џ' => 'Dz', 'Đ' => 'Dj'
|
||||
),
|
||||
'az' => array(/* Azerbaijani */
|
||||
'ç' => 'c', 'ə' => 'e', 'ğ' => 'g', 'ı' => 'i', 'ö' => 'o', 'ş' => 's', 'ü' => 'u',
|
||||
'Ç' => 'C', 'Ə' => 'E', 'Ğ' => 'G', 'İ' => 'I', 'Ö' => 'O', 'Ş' => 'S', 'Ü' => 'U'
|
||||
),
|
||||
);
|
||||
|
||||
/**
|
||||
* The character map for the designated language
|
||||
*
|
||||
* @see https://github.com/jbroadway/urlify/blob/master/URLify.php
|
||||
*/
|
||||
private static $map = array();
|
||||
|
||||
/**
|
||||
* The character list as a string.
|
||||
*
|
||||
* @see https://github.com/jbroadway/urlify/blob/master/URLify.php
|
||||
*/
|
||||
private static $chars = '';
|
||||
|
||||
/**
|
||||
* The character list as a regular expression.
|
||||
*
|
||||
* @see https://github.com/jbroadway/urlify/blob/master/URLify.php
|
||||
*/
|
||||
private static $regex = '';
|
||||
|
||||
/**
|
||||
* The current language
|
||||
*
|
||||
* @see https://github.com/jbroadway/urlify/blob/master/URLify.php
|
||||
*/
|
||||
private static $language = '';
|
||||
|
||||
/**
|
||||
* Initializes the character map.
|
||||
*
|
||||
* Part of the URLify.php Project <https://github.com/jbroadway/urlify/>
|
||||
*
|
||||
* @see https://github.com/jbroadway/urlify/blob/master/URLify.php
|
||||
*/
|
||||
private static function initLanguageMap($language = '')
|
||||
{
|
||||
if (count(self::$map) > 0 && (($language == '') || ($language == self::$language))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Is a specific map associated with $language?
|
||||
if (isset(self::$maps[$language]) && is_array(self::$maps[$language])) {
|
||||
// Move this map to end. This means it will have priority over others
|
||||
$m = self::$maps[$language];
|
||||
unset(self::$maps[$language]);
|
||||
self::$maps[$language] = $m;
|
||||
}
|
||||
|
||||
// Reset static vars
|
||||
self::$language = $language;
|
||||
self::$map = array();
|
||||
self::$chars = '';
|
||||
|
||||
foreach (self::$maps as $map) {
|
||||
foreach ($map as $orig => $conv) {
|
||||
self::$map[$orig] = $conv;
|
||||
self::$chars .= $orig;
|
||||
}
|
||||
}
|
||||
|
||||
self::$regex = '/[' . self::$chars . ']/u';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Access an array index, retrieving the value stored there if it
|
||||
* exists or a default if it does not. This function allows you to
|
||||
* concisely access an index which may or may not exist without
|
||||
* raising a warning.
|
||||
*
|
||||
* @param array $var Array value to access
|
||||
* @param mixed $default Default value to return if the key is not
|
||||
* present in the array
|
||||
* @return mixed
|
||||
*/
|
||||
public static function array_get(&$var, $default = null)
|
||||
{
|
||||
if (isset($var)) {
|
||||
return $var;
|
||||
}
|
||||
|
||||
return $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a variable's contents using nice HTML formatting and will
|
||||
* properly display the value of booleans as true or false
|
||||
*
|
||||
* @see var_dump_plain()
|
||||
*
|
||||
* @param mixed $var The variable to dump
|
||||
* @return string
|
||||
*/
|
||||
public static function var_dump($var, $return = false, $expandLevel = 1)
|
||||
{
|
||||
self::$hasArray = false;
|
||||
$toggScript = 'var colToggle = function(toggID) {var img = document.getElementById(toggID);if (document.getElementById(toggID + "-collapsable").style.display == "none") {document.getElementById(toggID + "-collapsable").style.display = "inline";setImg(toggID, 0);var previousSibling = document.getElementById(toggID + "-collapsable").previousSibling;while (previousSibling != null && (previousSibling.nodeType != 1 || previousSibling.tagName.toLowerCase() != "br")) {previousSibling = previousSibling.previousSibling;}} else {document.getElementById(toggID + "-collapsable").style.display = "none";setImg(toggID, 1);var previousSibling = document.getElementById(toggID + "-collapsable").previousSibling; while (previousSibling != null && (previousSibling.nodeType != 1 || previousSibling.tagName.toLowerCase() != "br")) {previousSibling = previousSibling.previousSibling;}}};';
|
||||
$imgScript = 'var setImg = function(objID,imgID,addStyle) {var imgStore = ["data:image/png;base64,' . self::$icon_collapse . '", "data:image/png;base64,' . self::$icon_expand . '"];if (objID) {document.getElementById(objID).setAttribute("src", imgStore[imgID]);if (addStyle){document.getElementById(objID).setAttribute("style", "position:relative;left:-5px;top:-1px;cursor:pointer;");}}};';
|
||||
$jsCode = preg_replace('/ +/', ' ', '<script>' . $toggScript . $imgScript . '</script>');
|
||||
$html = '<pre style="margin-bottom: 18px;' .
|
||||
'background: #f7f7f9;' .
|
||||
'border: 1px solid #e1e1e8;' .
|
||||
'padding: 8px;' .
|
||||
'border-radius: 4px;' .
|
||||
'-moz-border-radius: 4px;' .
|
||||
'-webkit-border radius: 4px;' .
|
||||
'display: block;' .
|
||||
'font-size: 12.05px;' .
|
||||
'white-space: pre-wrap;' .
|
||||
'word-wrap: break-word;' .
|
||||
'color: #333;' .
|
||||
'font-family: Menlo,Monaco,Consolas,\'Courier New\',monospace;">';
|
||||
$done = array();
|
||||
$html .= self::var_dump_plain($var, intval($expandLevel), 0, $done);
|
||||
$html .= '</pre>';
|
||||
|
||||
if (self::$hasArray) {
|
||||
$html = $jsCode . $html;
|
||||
}
|
||||
|
||||
if (!$return) {
|
||||
echo $html;
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a variable's contents using nice HTML formatting (Without
|
||||
* the <pre> tag) and will properly display the values of variables
|
||||
* like booleans and resources. Supports collapsable arrays and objects
|
||||
* as well.
|
||||
*
|
||||
* @param mixed $var The variable to dump
|
||||
* @return string
|
||||
*/
|
||||
public static function var_dump_plain($var, $expLevel, $depth = 0, $done = array())
|
||||
{
|
||||
$html = '';
|
||||
|
||||
if ($expLevel > 0) {
|
||||
$expLevel--;
|
||||
$setImg = 0;
|
||||
$setStyle = 'display:inline;';
|
||||
} elseif ($expLevel == 0) {
|
||||
$setImg = 1;
|
||||
$setStyle='display:none;';
|
||||
} elseif ($expLevel < 0) {
|
||||
$setImg = 0;
|
||||
$setStyle = 'display:inline;';
|
||||
}
|
||||
|
||||
if (is_bool($var)) {
|
||||
$html .= '<span style="color:#588bff;">bool</span><span style="color:#999;">(</span><strong>' . (($var) ? 'true' : 'false') . '</strong><span style="color:#999;">)</span>';
|
||||
} elseif (is_int($var)) {
|
||||
$html .= '<span style="color:#588bff;">int</span><span style="color:#999;">(</span><strong>' . $var . '</strong><span style="color:#999;">)</span>';
|
||||
} elseif (is_float($var)) {
|
||||
$html .= '<span style="color:#588bff;">float</span><span style="color:#999;">(</span><strong>' . $var . '</strong><span style="color:#999;">)</span>';
|
||||
} elseif (is_string($var)) {
|
||||
$html .= '<span style="color:#588bff;">string</span><span style="color:#999;">(</span>' . strlen($var) . '<span style="color:#999;">)</span> <strong>"' . self::htmlentities($var) . '"</strong>';
|
||||
} elseif (is_null($var)) {
|
||||
$html .= '<strong>NULL</strong>';
|
||||
} elseif (is_resource($var)) {
|
||||
$html .= '<span style="color:#588bff;">resource</span>("' . get_resource_type($var) . '") <strong>"' . $var . '"</strong>';
|
||||
} elseif (is_array($var)) {
|
||||
// Check for recursion
|
||||
if ($depth > 0) {
|
||||
foreach ($done as $prev) {
|
||||
if ($prev === $var) {
|
||||
$html .= '<span style="color:#588bff;">array</span>(' . count($var) . ') *RECURSION DETECTED*';
|
||||
return $html;
|
||||
}
|
||||
}
|
||||
|
||||
// Keep track of variables we have already processed to detect recursion
|
||||
$done[] = &$var;
|
||||
}
|
||||
|
||||
self::$hasArray = true;
|
||||
$uuid = 'include-php-' . uniqid() . mt_rand(1, 1000000);
|
||||
|
||||
$html .= (!empty($var) ? ' <img id="' . $uuid . '" src="data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs%3D" onclick="javascript:colToggle(this.id);" /><script>setImg("' . $uuid . '",'.$setImg.',1);</script>' : '') . '<span style="color:#588bff;">array</span>(' . count($var) . ')';
|
||||
if (!empty($var)) {
|
||||
$html .= ' <span id="' . $uuid . '-collapsable" style="'.$setStyle.'"><br />[<br />';
|
||||
|
||||
$indent = 4;
|
||||
$longest_key = 0;
|
||||
|
||||
foreach ($var as $key => $value) {
|
||||
if (is_string($key)) {
|
||||
$longest_key = max($longest_key, strlen($key) + 2);
|
||||
} else {
|
||||
$longest_key = max($longest_key, strlen($key));
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($var as $key => $value) {
|
||||
if (is_numeric($key)) {
|
||||
$html .= str_repeat(' ', $indent) . str_pad($key, $longest_key, ' ');
|
||||
} else {
|
||||
$html .= str_repeat(' ', $indent) . str_pad('"' . self::htmlentities($key) . '"', $longest_key, ' ');
|
||||
}
|
||||
|
||||
$html .= ' => ';
|
||||
|
||||
$value = explode('<br />', self::var_dump_plain($value, $expLevel, $depth + 1, $done));
|
||||
|
||||
foreach ($value as $line => $val) {
|
||||
if ($line != 0) {
|
||||
$value[$line] = str_repeat(' ', $indent * 2) . $val;
|
||||
}
|
||||
}
|
||||
|
||||
$html .= implode('<br />', $value) . '<br />';
|
||||
}
|
||||
|
||||
$html .= ']</span>';
|
||||
}
|
||||
} elseif (is_object($var)) {
|
||||
// Check for recursion
|
||||
foreach ($done as $prev) {
|
||||
if ($prev === $var) {
|
||||
$html .= '<span style="color:#588bff;">object</span>(' . get_class($var) . ') *RECURSION DETECTED*';
|
||||
return $html;
|
||||
}
|
||||
}
|
||||
|
||||
// Keep track of variables we have already processed to detect recursion
|
||||
$done[] = &$var;
|
||||
|
||||
self::$hasArray=true;
|
||||
$uuid = 'include-php-' . uniqid() . mt_rand(1, 1000000);
|
||||
|
||||
$html .= ' <img id="' . $uuid . '" src="data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs%3D" onclick="javascript:colToggle(this.id);" /><script>setImg("' . $uuid . '",'.$setImg.',1);</script><span style="color:#588bff;">object</span>(' . get_class($var) . ') <span id="' . $uuid . '-collapsable" style="'.$setStyle.'"><br />[<br />';
|
||||
|
||||
$varArray = (array) $var;
|
||||
|
||||
$indent = 4;
|
||||
$longest_key = 0;
|
||||
|
||||
foreach ($varArray as $key => $value) {
|
||||
if (substr($key, 0, 2) == "\0*") {
|
||||
unset($varArray[$key]);
|
||||
$key = 'protected:' . substr($key, 3);
|
||||
$varArray[$key] = $value;
|
||||
} elseif (substr($key, 0, 1) == "\0") {
|
||||
unset($varArray[$key]);
|
||||
$key = 'private:' . substr($key, 1, strpos(substr($key, 1), "\0")) . ':' . substr($key, strpos(substr($key, 1), "\0") + 2);
|
||||
$varArray[$key] = $value;
|
||||
}
|
||||
|
||||
if (is_string($key)) {
|
||||
$longest_key = max($longest_key, strlen($key) + 2);
|
||||
} else {
|
||||
$longest_key = max($longest_key, strlen($key));
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($varArray as $key => $value) {
|
||||
if (is_numeric($key)) {
|
||||
$html .= str_repeat(' ', $indent) . str_pad($key, $longest_key, ' ');
|
||||
} else {
|
||||
$html .= str_repeat(' ', $indent) . str_pad('"' . self::htmlentities($key) . '"', $longest_key, ' ');
|
||||
}
|
||||
|
||||
$html .= ' => ';
|
||||
|
||||
$value = explode('<br />', self::var_dump_plain($value, $expLevel, $depth + 1, $done));
|
||||
|
||||
foreach ($value as $line => $val) {
|
||||
if ($line != 0) {
|
||||
$value[$line] = str_repeat(' ', $indent * 2) . $val;
|
||||
}
|
||||
}
|
||||
|
||||
$html .= implode('<br />', $value) . '<br />';
|
||||
}
|
||||
|
||||
$html .= ']</span>';
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts any accent characters to their equivalent normal characters
|
||||
* and converts any other non-alphanumeric characters to dashes, then
|
||||
* converts any sequence of two or more dashes to a single dash. This
|
||||
* function generates slugs safe for use as URLs, and if you pass true
|
||||
* as the second parameter, it will create strings safe for use as CSS
|
||||
* classes or IDs.
|
||||
*
|
||||
* @param string $string A string to convert to a slug
|
||||
* @param string $separator The string to separate words with
|
||||
* @param boolean $css_mode Whether or not to generate strings safe for
|
||||
* CSS classes/IDs (Default to false)
|
||||
* @return string
|
||||
*/
|
||||
public static function slugify($string, $separator = '-', $css_mode = false)
|
||||
{
|
||||
// Compatibility with 1.0.* parameter ordering for semvar
|
||||
if ($separator === true || $separator === false) {
|
||||
$css_mode = $separator;
|
||||
$separator = '-';
|
||||
|
||||
// Raise deprecation error
|
||||
trigger_error(
|
||||
'util::slugify() now takes $css_mode as the third parameter, please update your code',
|
||||
E_USER_DEPRECATED
|
||||
);
|
||||
}
|
||||
|
||||
$slug = preg_replace('/([^a-z0-9]+)/', $separator, strtolower(self::remove_accents($string)));
|
||||
|
||||
if ($css_mode) {
|
||||
$digits = array('zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine');
|
||||
|
||||
if (is_numeric(substr($slug, 0, 1))) {
|
||||
$slug = $digits[substr($slug, 0, 1)] . substr($slug, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return $slug;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if a string is utf8 encoded.
|
||||
*
|
||||
* NOTE: This function checks for 5-Byte sequences, UTF8
|
||||
* has Bytes Sequences with a maximum length of 4.
|
||||
*
|
||||
* Written by Tony Ferrara <http://blog.ircmaxwell.com>
|
||||
*
|
||||
* @param string $string The string to be checked
|
||||
* @return boolean
|
||||
*/
|
||||
public static function seems_utf8($string)
|
||||
{
|
||||
if (function_exists('mb_check_encoding')) {
|
||||
// If mbstring is available, this is significantly faster than
|
||||
// using PHP regexps.
|
||||
return mb_check_encoding($string, 'UTF-8');
|
||||
}
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
return self::seemsUtf8Regex($string);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
/**
|
||||
* A non-Mbstring UTF-8 checker.
|
||||
*
|
||||
* @param $string
|
||||
* @return bool
|
||||
*/
|
||||
protected static function seemsUtf8Regex($string)
|
||||
{
|
||||
// Obtained from http://stackoverflow.com/a/11709412/430062 with permission.
|
||||
$regex = '/(
|
||||
[\xC0-\xC1] # Invalid UTF-8 Bytes
|
||||
| [\xF5-\xFF] # Invalid UTF-8 Bytes
|
||||
| \xE0[\x80-\x9F] # Overlong encoding of prior code point
|
||||
| \xF0[\x80-\x8F] # Overlong encoding of prior code point
|
||||
| [\xC2-\xDF](?![\x80-\xBF]) # Invalid UTF-8 Sequence Start
|
||||
| [\xE0-\xEF](?![\x80-\xBF]{2}) # Invalid UTF-8 Sequence Start
|
||||
| [\xF0-\xF4](?![\x80-\xBF]{3}) # Invalid UTF-8 Sequence Start
|
||||
| (?<=[\x0-\x7F\xF5-\xFF])[\x80-\xBF] # Invalid UTF-8 Sequence Middle
|
||||
| (?<![\xC2-\xDF]|[\xE0-\xEF]|[\xE0-\xEF][\x80-\xBF]|[\xF0-\xF4]|[\xF0-\xF4][\x80-\xBF]|[\xF0-\xF4][\x80-\xBF]{2})[\x80-\xBF] # Overlong Sequence
|
||||
| (?<=[\xE0-\xEF])[\x80-\xBF](?![\x80-\xBF]) # Short 3 byte sequence
|
||||
| (?<=[\xF0-\xF4])[\x80-\xBF](?![\x80-\xBF]{2}) # Short 4 byte sequence
|
||||
| (?<=[\xF0-\xF4][\x80-\xBF])[\x80-\xBF](?![\x80-\xBF]) # Short 4 byte sequence (2)
|
||||
)/x';
|
||||
|
||||
return ! preg_match($regex, $string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Nice formatting for computer sizes (Bytes).
|
||||
*
|
||||
* @param integer $bytes The number in bytes to format
|
||||
* @param integer $decimals The number of decimal points to include
|
||||
* @return string
|
||||
*/
|
||||
public static function size_format($bytes, $decimals = 0)
|
||||
{
|
||||
$bytes = floatval($bytes);
|
||||
|
||||
if ($bytes < 1024) {
|
||||
return $bytes . ' B';
|
||||
} elseif ($bytes < pow(1024, 2)) {
|
||||
return number_format($bytes / 1024, $decimals, '.', '') . ' KiB';
|
||||
} elseif ($bytes < pow(1024, 3)) {
|
||||
return number_format($bytes / pow(1024, 2), $decimals, '.', '') . ' MiB';
|
||||
} elseif ($bytes < pow(1024, 4)) {
|
||||
return number_format($bytes / pow(1024, 3), $decimals, '.', '') . ' GiB';
|
||||
} elseif ($bytes < pow(1024, 5)) {
|
||||
return number_format($bytes / pow(1024, 4), $decimals, '.', '') . ' TiB';
|
||||
} elseif ($bytes < pow(1024, 6)) {
|
||||
return number_format($bytes / pow(1024, 5), $decimals, '.', '') . ' PiB';
|
||||
} else {
|
||||
return number_format($bytes / pow(1024, 5), $decimals, '.', '') . ' PiB';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize data, if needed.
|
||||
*
|
||||
* @param mixed $data Data that might need to be serialized
|
||||
* @return mixed
|
||||
*/
|
||||
public static function maybe_serialize($data)
|
||||
{
|
||||
if (is_array($data) || is_object($data)) {
|
||||
return serialize($data);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unserialize value only if it is serialized.
|
||||
*
|
||||
* @param string $data A variable that may or may not be serialized
|
||||
* @return mixed
|
||||
*/
|
||||
public static function maybe_unserialize($data)
|
||||
{
|
||||
// If it isn't a string, it isn't serialized
|
||||
if (!is_string($data)) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
$data = trim($data);
|
||||
|
||||
// Is it the serialized NULL value?
|
||||
if ($data === 'N;') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$length = strlen($data);
|
||||
|
||||
// Check some basic requirements of all serialized strings
|
||||
if ($length < 4 || $data[1] !== ':' || ($data[$length - 1] !== ';' && $data[$length - 1] !== '}')) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
// $data is the serialized false value
|
||||
if ($data === 'b:0;') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't attempt to unserialize data that isn't serialized
|
||||
$uns = @unserialize($data);
|
||||
|
||||
// Data failed to unserialize?
|
||||
if ($uns === false) {
|
||||
$uns = @unserialize(self::fix_broken_serialization($data));
|
||||
|
||||
if ($uns === false) {
|
||||
return $data;
|
||||
} else {
|
||||
return $uns;
|
||||
}
|
||||
} else {
|
||||
return $uns;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check value to find if it was serialized.
|
||||
*
|
||||
* If $data is not an string, then returned value will always be false.
|
||||
* Serialized data is always a string.
|
||||
*
|
||||
* @param mixed $data Value to check to see if was serialized
|
||||
* @return boolean
|
||||
*/
|
||||
public static function is_serialized($data)
|
||||
{
|
||||
// If it isn't a string, it isn't serialized
|
||||
if (!is_string($data)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$data = trim($data);
|
||||
|
||||
// Is it the serialized NULL value?
|
||||
if ($data === 'N;') {
|
||||
return true;
|
||||
}
|
||||
// Is it a serialized boolean?
|
||||
elseif ($data === 'b:0;' || $data === 'b:1;') {
|
||||
return true;
|
||||
}
|
||||
|
||||
$length = strlen($data);
|
||||
|
||||
// Check some basic requirements of all serialized strings
|
||||
if ($length < 4 || $data[1] !== ':' || ($data[$length - 1] !== ';' && $data[$length - 1] !== '}')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return @unserialize($data) !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unserializes partially-corrupted arrays that occur sometimes. Addresses
|
||||
* specifically the `unserialize(): Error at offset xxx of yyy bytes` error.
|
||||
*
|
||||
* NOTE: This error can *frequently* occur with mismatched character sets
|
||||
* and higher-than-ASCII characters.
|
||||
*
|
||||
* Contributed by Theodore R. Smith of PHP Experts, Inc. <http://www.phpexperts.pro/>
|
||||
*
|
||||
* @param string $brokenSerializedData
|
||||
* @return string
|
||||
*/
|
||||
public static function fix_broken_serialization($brokenSerializedData)
|
||||
{
|
||||
$fixdSerializedData = preg_replace_callback('!s:(\d+):"(.*?)";!', function($matches) {
|
||||
$snip = $matches[2];
|
||||
return 's:' . strlen($snip) . ':"' . $snip . '";';
|
||||
}, $brokenSerializedData);
|
||||
|
||||
return $fixdSerializedData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if the page is being server over SSL or not
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function is_https()
|
||||
{
|
||||
return isset($_SERVER['HTTPS']) && !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off';
|
||||
}
|
||||
|
||||
/**
|
||||
* Add or remove query arguments to the URL.
|
||||
*
|
||||
* @param mixed $newKey Either newkey or an associative array
|
||||
* @param mixed $newValue Either newvalue or oldquery or uri
|
||||
* @param mixed $uri URI or URL to append the queru/queries to.
|
||||
* @return string
|
||||
*/
|
||||
public static function add_query_arg($newKey, $newValue = null, $uri = null)
|
||||
{
|
||||
// Was an associative array of key => value pairs passed?
|
||||
if (is_array($newKey)) {
|
||||
$newParams = $newKey;
|
||||
|
||||
// Was the URL passed as an argument?
|
||||
if (!is_null($newValue)) {
|
||||
$uri = $newValue;
|
||||
} elseif (!is_null($uri)) {
|
||||
$uri = $uri;
|
||||
} else {
|
||||
$uri = self::array_get($_SERVER['REQUEST_URI'], '');
|
||||
}
|
||||
} else {
|
||||
$newParams = array($newKey => $newValue);
|
||||
|
||||
// Was the URL passed as an argument?
|
||||
$uri = is_null($uri) ? self::array_get($_SERVER['REQUEST_URI'], '') : $uri;
|
||||
}
|
||||
|
||||
// Parse the URI into it's components
|
||||
$puri = parse_url($uri);
|
||||
|
||||
if (isset($puri['query'])) {
|
||||
parse_str($puri['query'], $queryParams);
|
||||
$queryParams = array_merge($queryParams, $newParams);
|
||||
} elseif (isset($puri['path']) && strstr($puri['path'], '=') !== false) {
|
||||
$puri['query'] = $puri['path'];
|
||||
unset($puri['path']);
|
||||
parse_str($puri['query'], $queryParams);
|
||||
$queryParams = array_merge($queryParams, $newParams);
|
||||
} else {
|
||||
$queryParams = $newParams;
|
||||
}
|
||||
|
||||
// Strip out any query params that are set to false
|
||||
foreach ($queryParams as $param => $value) {
|
||||
if ($value === false) {
|
||||
unset($queryParams[$param]);
|
||||
}
|
||||
}
|
||||
|
||||
// Re-construct the query string
|
||||
$puri['query'] = http_build_query($queryParams);
|
||||
|
||||
// Re-construct the entire URL
|
||||
$nuri = self::http_build_url($puri);
|
||||
|
||||
// Make the URI consistent with our input
|
||||
if ($nuri[0] === '/' && strstr($uri, '/') === false) {
|
||||
$nuri = substr($nuri, 1);
|
||||
}
|
||||
|
||||
if ($nuri[0] === '?' && strstr($uri, '?') === false) {
|
||||
$nuri = substr($nuri, 1);
|
||||
}
|
||||
|
||||
return rtrim($nuri, '?');
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an item or list from the query string.
|
||||
*
|
||||
* @param string|array $keys Query key or keys to remove.
|
||||
* @param bool $uri When false uses the $_SERVER value
|
||||
* @return string
|
||||
*/
|
||||
public static function remove_query_arg($keys, $uri = null)
|
||||
{
|
||||
if (is_array($keys)) {
|
||||
return self::add_query_arg(array_combine($keys, array_fill(0, count($keys), null)), $uri);
|
||||
}
|
||||
|
||||
return self::add_query_arg(array($keys => null), $uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a URL.
|
||||
*
|
||||
* The parts of the second URL will be merged into the first according to
|
||||
* the flags argument.
|
||||
*
|
||||
* @author Jake Smith <theman@jakeasmith.com>
|
||||
* @see https://github.com/jakeasmith/http_build_url/
|
||||
*
|
||||
* @param mixed $url (part(s) of) an URL in form of a string or
|
||||
* associative array like parse_url() returns
|
||||
* @param mixed $parts same as the first argument
|
||||
* @param int $flags a bitmask of binary or'ed HTTP_URL constants;
|
||||
* HTTP_URL_REPLACE is the default
|
||||
* @param array $new_url if set, it will be filled with the parts of the
|
||||
* composed url like parse_url() would return
|
||||
* @return string
|
||||
*/
|
||||
public static function http_build_url($url, $parts = array(), $flags = self::HTTP_URL_REPLACE, &$new_url = array())
|
||||
{
|
||||
is_array($url) || $url = parse_url($url);
|
||||
is_array($parts) || $parts = parse_url($parts);
|
||||
|
||||
isset($url['query']) && is_string($url['query']) || $url['query'] = null;
|
||||
isset($parts['query']) && is_string($parts['query']) || $parts['query'] = null;
|
||||
|
||||
$keys = array('user', 'pass', 'port', 'path', 'query', 'fragment');
|
||||
|
||||
// HTTP_URL_STRIP_ALL and HTTP_URL_STRIP_AUTH cover several other flags.
|
||||
if ($flags & self::HTTP_URL_STRIP_ALL) {
|
||||
$flags |= self::HTTP_URL_STRIP_USER | self::HTTP_URL_STRIP_PASS
|
||||
| self::HTTP_URL_STRIP_PORT | self::HTTP_URL_STRIP_PATH
|
||||
| self::HTTP_URL_STRIP_QUERY | self::HTTP_URL_STRIP_FRAGMENT;
|
||||
} elseif ($flags & self::HTTP_URL_STRIP_AUTH) {
|
||||
$flags |= self::HTTP_URL_STRIP_USER | self::HTTP_URL_STRIP_PASS;
|
||||
}
|
||||
|
||||
// Schema and host are alwasy replaced
|
||||
foreach (array('scheme', 'host') as $part) {
|
||||
if (isset($parts[$part])) {
|
||||
$url[$part] = $parts[$part];
|
||||
}
|
||||
}
|
||||
|
||||
if ($flags & self::HTTP_URL_REPLACE) {
|
||||
foreach ($keys as $key) {
|
||||
if (isset($parts[$key])) {
|
||||
$url[$key] = $parts[$key];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (isset($parts['path']) && ($flags & self::HTTP_URL_JOIN_PATH)) {
|
||||
if (isset($url['path']) && substr($parts['path'], 0, 1) !== '/') {
|
||||
$url['path'] = rtrim(
|
||||
str_replace(basename($url['path']), '', $url['path']),
|
||||
'/'
|
||||
) . '/' . ltrim($parts['path'], '/');
|
||||
} else {
|
||||
$url['path'] = $parts['path'];
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($parts['query']) && ($flags & self::HTTP_URL_JOIN_QUERY)) {
|
||||
if (isset($url['query'])) {
|
||||
parse_str($url['query'], $url_query);
|
||||
parse_str($parts['query'], $parts_query);
|
||||
|
||||
$url['query'] = http_build_query(
|
||||
array_replace_recursive(
|
||||
$url_query,
|
||||
$parts_query
|
||||
)
|
||||
);
|
||||
} else {
|
||||
$url['query'] = $parts['query'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($url['path']) && substr($url['path'], 0, 1) !== '/') {
|
||||
$url['path'] = '/' . $url['path'];
|
||||
}
|
||||
|
||||
foreach ($keys as $key) {
|
||||
$strip = 'HTTP_URL_STRIP_' . strtoupper($key);
|
||||
if ($flags & constant('utilphp\\util::' . $strip)) {
|
||||
unset($url[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
$parsed_string = '';
|
||||
|
||||
if (isset($url['scheme'])) {
|
||||
$parsed_string .= $url['scheme'] . '://';
|
||||
}
|
||||
|
||||
if (isset($url['user'])) {
|
||||
$parsed_string .= $url['user'];
|
||||
|
||||
if (isset($url['pass'])) {
|
||||
$parsed_string .= ':' . $url['pass'];
|
||||
}
|
||||
|
||||
$parsed_string .= '@';
|
||||
}
|
||||
|
||||
if (isset($url['host'])) {
|
||||
$parsed_string .= $url['host'];
|
||||
}
|
||||
|
||||
if (isset($url['port'])) {
|
||||
$parsed_string .= ':' . $url['port'];
|
||||
}
|
||||
|
||||
if (!empty($url['path'])) {
|
||||
$parsed_string .= $url['path'];
|
||||
} else {
|
||||
$parsed_string .= '/';
|
||||
}
|
||||
|
||||
if (isset($url['query'])) {
|
||||
$parsed_string .= '?' . $url['query'];
|
||||
}
|
||||
|
||||
if (isset($url['fragment'])) {
|
||||
$parsed_string .= '#' . $url['fragment'];
|
||||
}
|
||||
|
||||
$new_url = $url;
|
||||
|
||||
return $parsed_string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts many english words that equate to true or false to boolean.
|
||||
*
|
||||
* Supports 'y', 'n', 'yes', 'no' and a few other variations.
|
||||
*
|
||||
* @param string $string The string to convert to boolean
|
||||
* @param bool $default The value to return if we can't match any
|
||||
* yes/no words
|
||||
* @return boolean
|
||||
*/
|
||||
public static function str_to_bool($string, $default = false)
|
||||
{
|
||||
$yes_words = 'affirmative|all right|aye|indubitably|most assuredly|ok|of course|okay|sure thing|y|yes+|yea|yep|sure|yeah|true|t|on|1|oui|vrai';
|
||||
$no_words = 'no*|no way|nope|nah|na|never|absolutely not|by no means|negative|never ever|false|f|off|0|non|faux';
|
||||
|
||||
if (preg_match('/^(' . $yes_words . ')$/i', $string)) {
|
||||
return true;
|
||||
} elseif (preg_match('/^(' . $no_words . ')$/i', $string)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a string starts with the given string.
|
||||
*
|
||||
* @param string $string
|
||||
* @param string $starts_with
|
||||
* @return boolean
|
||||
*/
|
||||
public static function starts_with($string, $starts_with)
|
||||
{
|
||||
return strpos($string, $starts_with) === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a string ends with the given string.
|
||||
*
|
||||
* @param string $string
|
||||
* @param string $starts_with
|
||||
* @return boolean
|
||||
*/
|
||||
public static function ends_with($string, $ends_with)
|
||||
{
|
||||
return substr($string, -strlen($ends_with)) === $ends_with;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a string contains another string.
|
||||
*
|
||||
* @param string $haystack
|
||||
* @param string $needle
|
||||
* @return boolean
|
||||
*/
|
||||
public static function str_contains($haystack, $needle)
|
||||
{
|
||||
return strpos($haystack, $needle) !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a string contains another string. This version is case
|
||||
* insensitive.
|
||||
*
|
||||
* @param string $haystack
|
||||
* @param string $needle
|
||||
* @return boolean
|
||||
*/
|
||||
public static function str_icontains($haystack, $needle)
|
||||
{
|
||||
return stripos($haystack, $needle) !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the file extension of the given filename.
|
||||
*
|
||||
* @param string $filename
|
||||
* @return string
|
||||
*/
|
||||
public static function get_file_ext($filename)
|
||||
{
|
||||
return pathinfo($filename, PATHINFO_EXTENSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a directory (and its contents) recursively.
|
||||
*
|
||||
* Contributed by Askar (ARACOOL) <https://github.com/ARACOOOL>
|
||||
*
|
||||
* @param string $dir The directory to be deleted recursively
|
||||
* @param bool $traverseSymlinks Delete contents of symlinks recursively
|
||||
* @return bool
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public static function rmdir($dir, $traverseSymlinks = false)
|
||||
{
|
||||
if (!file_exists($dir)) {
|
||||
return true;
|
||||
} elseif (!is_dir($dir)) {
|
||||
throw new \RuntimeException('Given path is not a directory');
|
||||
}
|
||||
|
||||
if (!is_link($dir) || $traverseSymlinks) {
|
||||
foreach (scandir($dir) as $file) {
|
||||
if ($file === '.' || $file === '..') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$currentPath = $dir . '/' . $file;
|
||||
|
||||
if (is_dir($currentPath)) {
|
||||
self::rmdir($currentPath, $traverseSymlinks);
|
||||
} elseif (!unlink($currentPath)) {
|
||||
// @codeCoverageIgnoreStart
|
||||
throw new \RuntimeException('Unable to delete ' . $currentPath);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Windows treats removing directory symlinks identically to removing directories.
|
||||
if (is_link($dir) && !defined('PHP_WINDOWS_VERSION_MAJOR')) {
|
||||
if (!unlink($dir)) {
|
||||
// @codeCoverageIgnoreStart
|
||||
throw new \RuntimeException('Unable to delete ' . $dir);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
} else {
|
||||
if (!rmdir($dir)) {
|
||||
// @codeCoverageIgnoreStart
|
||||
throw new \RuntimeException('Unable to delete ' . $dir);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert entities, while preserving already-encoded entities.
|
||||
*
|
||||
* @param string $string The text to be converted
|
||||
* @return string
|
||||
*/
|
||||
public static function htmlentities($string, $preserve_encoded_entities = false)
|
||||
{
|
||||
if ($preserve_encoded_entities) {
|
||||
// @codeCoverageIgnoreStart
|
||||
if (defined('HHVM_VERSION')) {
|
||||
$translation_table = get_html_translation_table(HTML_ENTITIES, ENT_QUOTES);
|
||||
} else {
|
||||
$translation_table = get_html_translation_table(HTML_ENTITIES, ENT_QUOTES, self::mbInternalEncoding());
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
$translation_table[chr(38)] = '&';
|
||||
return preg_replace('/&(?![A-Za-z]{0,4}\w{2,3};|#[0-9]{2,3};)/', '&', strtr($string, $translation_table));
|
||||
}
|
||||
|
||||
return htmlentities($string, ENT_QUOTES, self::mbInternalEncoding());
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert >, <, ', " and & to html entities, but preserves entities that
|
||||
* are already encoded.
|
||||
*
|
||||
* @param string $string The text to be converted
|
||||
* @return string
|
||||
*/
|
||||
public static function htmlspecialchars($string, $preserve_encoded_entities = false)
|
||||
{
|
||||
if ($preserve_encoded_entities) {
|
||||
// @codeCoverageIgnoreStart
|
||||
if (defined('HHVM_VERSION')) {
|
||||
$translation_table = get_html_translation_table(HTML_SPECIALCHARS, ENT_QUOTES);
|
||||
} else {
|
||||
$translation_table = get_html_translation_table(HTML_SPECIALCHARS, ENT_QUOTES, self::mbInternalEncoding());
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
$translation_table[chr(38)] = '&';
|
||||
|
||||
return preg_replace('/&(?![A-Za-z]{0,4}\w{2,3};|#[0-9]{2,3};)/', '&', strtr($string, $translation_table));
|
||||
}
|
||||
|
||||
return htmlentities($string, ENT_QUOTES, self::mbInternalEncoding());
|
||||
}
|
||||
|
||||
/**
|
||||
* Transliterates characters to their ASCII equivalents.
|
||||
*
|
||||
* Part of the URLify.php Project <https://github.com/jbroadway/urlify/>
|
||||
*
|
||||
* @see https://github.com/jbroadway/urlify/blob/master/URLify.php
|
||||
*
|
||||
* @param string $text Text that might have not-ASCII characters
|
||||
* @param string $language Specifies a priority for a specific language.
|
||||
* @return string Filtered string with replaced "nice" characters
|
||||
*/
|
||||
public static function downcode($text, $language = '')
|
||||
{
|
||||
self::initLanguageMap($language);
|
||||
|
||||
if (self::seems_utf8($text)) {
|
||||
if (preg_match_all(self::$regex, $text, $matches)) {
|
||||
for ($i = 0; $i < count($matches[0]); $i++) {
|
||||
$char = $matches[0][$i];
|
||||
if (isset(self::$map[$char])) {
|
||||
$text = str_replace($char, self::$map[$char], $text);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Not a UTF-8 string so we assume its ISO-8859-1
|
||||
$search = "\x80\x83\x8a\x8e\x9a\x9e\x9f\xa2\xa5\xb5\xc0\xc1\xc2\xc3\xc4\xc5\xc7\xc8\xc9\xca\xcb\xcc\xcd";
|
||||
$search .= "\xce\xcf\xd1\xd2\xd3\xd4\xd5\xd6\xd8\xd9\xda\xdb\xdc\xdd\xe0\xe1\xe2\xe3\xe4\xe5\xe7\xe8\xe9";
|
||||
$search .= "\xea\xeb\xec\xed\xee\xef\xf1\xf2\xf3\xf4\xf5\xf6\xf8\xf9\xfa\xfb\xfc\xfd\xff";
|
||||
$text = strtr($text, $search, 'EfSZszYcYuAAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiiinoooooouuuuyy');
|
||||
|
||||
// These latin characters should be represented by two characters so
|
||||
// we can't use strtr
|
||||
$complexSearch = array("\x8c", "\x9c", "\xc6", "\xd0", "\xde", "\xdf", "\xe6", "\xf0", "\xfe");
|
||||
$complexReplace = array('OE', 'oe', 'AE', 'DH', 'TH', 'ss', 'ae', 'dh', 'th');
|
||||
$text = str_replace($complexSearch, $complexReplace, $text);
|
||||
}
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts all accent characters to ASCII characters.
|
||||
*
|
||||
* If there are no accent characters, then the string given is just
|
||||
* returned.
|
||||
*
|
||||
* @param string $string Text that might have accent characters
|
||||
* @param string $language Specifies a priority for a specific language.
|
||||
* @return string Filtered string with replaced "nice" characters
|
||||
*/
|
||||
public static function remove_accents($string, $language = '')
|
||||
{
|
||||
if (!preg_match('/[\x80-\xff]/', $string)) {
|
||||
return $string;
|
||||
}
|
||||
|
||||
return self::downcode($string, $language);
|
||||
}
|
||||
|
||||
/**
|
||||
* Strip all witespaces from the given string.
|
||||
*
|
||||
* @param string $string The string to strip
|
||||
* @return string
|
||||
*/
|
||||
public static function strip_space($string)
|
||||
{
|
||||
return preg_replace('/\s+/', '', $string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize a string by performing the following operation :
|
||||
* - Remove accents
|
||||
* - Lower the string
|
||||
* - Remove punctuation characters
|
||||
* - Strip whitespaces
|
||||
*
|
||||
* @param string $string the string to sanitize
|
||||
* @return string
|
||||
*/
|
||||
public static function sanitize_string($string)
|
||||
{
|
||||
$string = self::remove_accents($string);
|
||||
$string = strtolower($string);
|
||||
$string = preg_replace('/[^a-zA-Z 0-9]+/', '', $string);
|
||||
$string = self::strip_space($string);
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pads a given string with zeroes on the left.
|
||||
*
|
||||
* @param int $number The number to pad
|
||||
* @param int $length The total length of the desired string
|
||||
* @return string
|
||||
*/
|
||||
public static function zero_pad($number, $length)
|
||||
{
|
||||
return str_pad($number, $length, '0', STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a unix timestamp to a relative time string, such as "3 days ago"
|
||||
* or "2 weeks ago".
|
||||
*
|
||||
* @param int $from The date to use as a starting point
|
||||
* @param int $to The date to compare to, defaults to now
|
||||
* @param string $suffix The string to add to the end, defaults to " ago"
|
||||
* @return string
|
||||
*/
|
||||
public static function human_time_diff($from, $to = '', $as_text = false, $suffix = ' ago')
|
||||
{
|
||||
if ($to == '') {
|
||||
$to = time();
|
||||
}
|
||||
|
||||
$from = new \DateTime(date('Y-m-d H:i:s', $from));
|
||||
$to = new \DateTime(date('Y-m-d H:i:s', $to));
|
||||
$diff = $from->diff($to);
|
||||
|
||||
if ($diff->y > 1) {
|
||||
$text = $diff->y . ' years';
|
||||
} elseif ($diff->y == 1) {
|
||||
$text = '1 year';
|
||||
} elseif ($diff->m > 1) {
|
||||
$text = $diff->m . ' months';
|
||||
} elseif ($diff->m == 1) {
|
||||
$text = '1 month';
|
||||
} elseif ($diff->d > 7) {
|
||||
$text = ceil($diff->d / 7) . ' weeks';
|
||||
} elseif ($diff->d == 7) {
|
||||
$text = '1 week';
|
||||
} elseif ($diff->d > 1) {
|
||||
$text = $diff->d . ' days';
|
||||
} elseif ($diff->d == 1) {
|
||||
$text = '1 day';
|
||||
} elseif ($diff->h > 1) {
|
||||
$text = $diff->h . ' hours';
|
||||
} elseif ($diff->h == 1) {
|
||||
$text = ' 1 hour';
|
||||
} elseif ($diff->i > 1) {
|
||||
$text = $diff->i . ' minutes';
|
||||
} elseif ($diff->i == 1) {
|
||||
$text = '1 minute';
|
||||
} elseif ($diff->s > 1) {
|
||||
$text = $diff->s . ' seconds';
|
||||
} else {
|
||||
$text = '1 second';
|
||||
}
|
||||
|
||||
if ($as_text) {
|
||||
$text = explode(' ', $text, 2);
|
||||
$text = self::number_to_word($text[0]) . ' ' . $text[1];
|
||||
}
|
||||
|
||||
return trim($text) . $suffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a number into the text equivalent. For example, 456 becomes four
|
||||
* hundred and fifty-six.
|
||||
*
|
||||
* Part of the IntToWords Project.
|
||||
*
|
||||
* @param int|float $number The number to convert into text
|
||||
* @return string
|
||||
*/
|
||||
public static function number_to_word($number)
|
||||
{
|
||||
$number = (string) $number;
|
||||
|
||||
if (strpos($number, '.') !== false) {
|
||||
list($number, $decimal) = explode('.', $number);
|
||||
} else {
|
||||
$decimal = false;
|
||||
}
|
||||
|
||||
$output = '';
|
||||
|
||||
if ($number[0] == '-') {
|
||||
$output = 'negative ';
|
||||
$number = ltrim($number, '-');
|
||||
} elseif ($number[0] == '+') {
|
||||
$output = 'positive ';
|
||||
$number = ltrim($number, '+');
|
||||
}
|
||||
|
||||
if ($number[0] == '0') {
|
||||
$output .= 'zero';
|
||||
} else {
|
||||
$length = 19;
|
||||
$number = str_pad($number, 60, '0', STR_PAD_LEFT);
|
||||
$group = rtrim(chunk_split($number, 3, ' '), ' ');
|
||||
$groups = explode(' ', $group);
|
||||
$groups2 = array();
|
||||
|
||||
foreach ($groups as $group) {
|
||||
$group[1] = isset($group[1]) ? $group[1] : null;
|
||||
$group[2] = isset($group[2]) ? $group[2] : null;
|
||||
$groups2[] = self::numberToWordThreeDigits($group[0], $group[1], $group[2]);
|
||||
}
|
||||
|
||||
for ($z = 0; $z < count($groups2); $z++) {
|
||||
if ($groups2[$z] != '') {
|
||||
$output .= $groups2[$z] . self::numberToWordConvertGroup($length - $z);
|
||||
$output .= ($z < $length && ! array_search('', array_slice($groups2, $z + 1, -1)) && $groups2[$length] != '' && $groups[$length][0] == '0' ? ' and ' : ', ');
|
||||
}
|
||||
}
|
||||
|
||||
$output = rtrim($output, ', ');
|
||||
}
|
||||
|
||||
if ($decimal > 0) {
|
||||
$output .= ' point';
|
||||
|
||||
for ($i = 0; $i < strlen($decimal); $i++) {
|
||||
$output .= ' ' . self::numberToWordConvertDigit($decimal[$i]);
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
protected static function numberToWordConvertGroup($index)
|
||||
{
|
||||
switch($index) {
|
||||
case 11:
|
||||
return ' decillion';
|
||||
case 10:
|
||||
return ' nonillion';
|
||||
case 9:
|
||||
return ' octillion';
|
||||
case 8:
|
||||
return ' septillion';
|
||||
case 7:
|
||||
return ' sextillion';
|
||||
case 6:
|
||||
return ' quintrillion';
|
||||
case 5:
|
||||
return ' quadrillion';
|
||||
case 4:
|
||||
return ' trillion';
|
||||
case 3:
|
||||
return ' billion';
|
||||
case 2:
|
||||
return ' million';
|
||||
case 1:
|
||||
return ' thousand';
|
||||
case 0:
|
||||
return '';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
protected static function numberToWordThreeDigits($digit1, $digit2, $digit3)
|
||||
{
|
||||
$output = '';
|
||||
|
||||
if ($digit1 == '0' && $digit2 == '0' && $digit3 == '0') {
|
||||
return '';
|
||||
}
|
||||
|
||||
if ($digit1 != '0') {
|
||||
$output .= self::numberToWordConvertDigit($digit1) . ' hundred';
|
||||
|
||||
if ($digit2 != '0' || $digit3 != '0') {
|
||||
$output .= ' and ';
|
||||
}
|
||||
}
|
||||
if ($digit2 != '0') {
|
||||
$output .= self::numberToWordTwoDigits($digit2, $digit3);
|
||||
} elseif ($digit3 != '0') {
|
||||
$output .= self::numberToWordConvertDigit($digit3);
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
protected static function numberToWordTwoDigits($digit1, $digit2)
|
||||
{
|
||||
if ($digit2 == '0') {
|
||||
switch ($digit1) {
|
||||
case '1':
|
||||
return 'ten';
|
||||
case '2':
|
||||
return 'twenty';
|
||||
case '3':
|
||||
return 'thirty';
|
||||
case '4':
|
||||
return 'forty';
|
||||
case '5':
|
||||
return 'fifty';
|
||||
case '6':
|
||||
return 'sixty';
|
||||
case '7':
|
||||
return 'seventy';
|
||||
case '8':
|
||||
return 'eighty';
|
||||
case '9':
|
||||
return 'ninety';
|
||||
}
|
||||
} elseif ($digit1 == '1') {
|
||||
switch ($digit2) {
|
||||
case '1':
|
||||
return 'eleven';
|
||||
case '2':
|
||||
return 'twelve';
|
||||
case '3':
|
||||
return 'thirteen';
|
||||
case '4':
|
||||
return 'fourteen';
|
||||
case '5':
|
||||
return 'fifteen';
|
||||
case '6':
|
||||
return 'sixteen';
|
||||
case '7':
|
||||
return 'seventeen';
|
||||
case '8':
|
||||
return 'eighteen';
|
||||
case '9':
|
||||
return 'nineteen';
|
||||
}
|
||||
} else {
|
||||
$second_digit = self::numberToWordConvertDigit($digit2);
|
||||
|
||||
switch ($digit1) {
|
||||
case '2':
|
||||
return "twenty-{$second_digit}";
|
||||
case '3':
|
||||
return "thirty-{$second_digit}";
|
||||
case '4':
|
||||
return "forty-{$second_digit}";
|
||||
case '5':
|
||||
return "fifty-{$second_digit}";
|
||||
case '6':
|
||||
return "sixty-{$second_digit}";
|
||||
case '7':
|
||||
return "seventy-{$second_digit}";
|
||||
case '8':
|
||||
return "eighty-{$second_digit}";
|
||||
case '9':
|
||||
return "ninety-{$second_digit}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $digit
|
||||
* @return string
|
||||
* @throws \LogicException
|
||||
*/
|
||||
protected static function numberToWordConvertDigit($digit)
|
||||
{
|
||||
switch ($digit) {
|
||||
case '0':
|
||||
return 'zero';
|
||||
case '1':
|
||||
return 'one';
|
||||
case '2':
|
||||
return 'two';
|
||||
case '3':
|
||||
return 'three';
|
||||
case '4':
|
||||
return 'four';
|
||||
case '5':
|
||||
return 'five';
|
||||
case '6':
|
||||
return 'six';
|
||||
case '7':
|
||||
return 'seven';
|
||||
case '8':
|
||||
return 'eight';
|
||||
case '9':
|
||||
return 'nine';
|
||||
default:
|
||||
throw new \LogicException('Not a number');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transmit UTF-8 content headers if the headers haven't already been sent.
|
||||
*
|
||||
* @param string $content_type The content type to send out
|
||||
* @return boolean
|
||||
*/
|
||||
public static function utf8_headers($content_type = 'text/html')
|
||||
{
|
||||
// @codeCoverageIgnoreStart
|
||||
if (!headers_sent()) {
|
||||
header('Content-type: ' . $content_type . '; charset=utf-8');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
/**
|
||||
* Transmit headers that force a browser to display the download file
|
||||
* dialog. Cross browser compatible. Only fires if headers have not
|
||||
* already been sent.
|
||||
*
|
||||
* @param string $filename The name of the filename to display to
|
||||
* browsers
|
||||
* @param string $content The content to output for the download.
|
||||
* If you don't specify this, just the
|
||||
* headers will be sent
|
||||
* @return boolean
|
||||
*/
|
||||
public static function force_download($filename, $content = false)
|
||||
{
|
||||
// @codeCoverageIgnoreStart
|
||||
if (!headers_sent()) {
|
||||
// Required for some browsers
|
||||
if (ini_get('zlib.output_compression')) {
|
||||
@ini_set('zlib.output_compression', 'Off');
|
||||
}
|
||||
|
||||
header('Pragma: public');
|
||||
header('Expires: 0');
|
||||
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
|
||||
|
||||
// Required for certain browsers
|
||||
header('Cache-Control: private', false);
|
||||
|
||||
header('Content-Disposition: attachment; filename="' . basename(str_replace('"', '', $filename)) . '";');
|
||||
header('Content-Type: application/force-download');
|
||||
header('Content-Transfer-Encoding: binary');
|
||||
|
||||
if ($content) {
|
||||
header('Content-Length: ' . strlen($content));
|
||||
}
|
||||
|
||||
ob_clean();
|
||||
flush();
|
||||
|
||||
if ($content) {
|
||||
echo $content;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the headers to prevent caching for the different browsers.
|
||||
*
|
||||
* Different browsers support different nocache headers, so several
|
||||
* headers must be sent so that all of them get the point that no
|
||||
* caching should occur
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function nocache_headers()
|
||||
{
|
||||
// @codeCoverageIgnoreStart
|
||||
if (!headers_sent()) {
|
||||
header('Expires: Wed, 11 Jan 1984 05:00:00 GMT');
|
||||
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
|
||||
header('Cache-Control: no-cache, must-revalidate, max-age=0');
|
||||
header('Pragma: no-cache');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a string of random characters.
|
||||
*
|
||||
* @throws LengthException If $length is bigger than the available
|
||||
* character pool and $no_duplicate_chars is
|
||||
* enabled
|
||||
*
|
||||
* @param integer $length The length of the string to
|
||||
* generate
|
||||
* @param boolean $human_friendly Whether or not to make the
|
||||
* string human friendly by
|
||||
* removing characters that can be
|
||||
* confused with other characters (
|
||||
* O and 0, l and 1, etc)
|
||||
* @param boolean $include_symbols Whether or not to include
|
||||
* symbols in the string. Can not
|
||||
* be enabled if $human_friendly is
|
||||
* true
|
||||
* @param boolean $no_duplicate_chars Whether or not to only use
|
||||
* characters once in the string.
|
||||
* @return string
|
||||
*/
|
||||
public static function random_string($length = 16, $human_friendly = true, $include_symbols = false, $no_duplicate_chars = false)
|
||||
{
|
||||
$nice_chars = 'ABCDEFGHJKLMNPQRSTUVWXYZabcdefhjkmnprstuvwxyz23456789';
|
||||
$all_an = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890';
|
||||
$symbols = '!@#$%^&*()~_-=+{}[]|:;<>,.?/"\'\\`';
|
||||
$string = '';
|
||||
|
||||
// Determine the pool of available characters based on the given parameters
|
||||
if ($human_friendly) {
|
||||
$pool = $nice_chars;
|
||||
} else {
|
||||
$pool = $all_an;
|
||||
|
||||
if ($include_symbols) {
|
||||
$pool .= $symbols;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$no_duplicate_chars) {
|
||||
return substr(str_shuffle(str_repeat($pool, $length)), 0, $length);
|
||||
}
|
||||
|
||||
// Don't allow duplicate letters to be disabled if the length is
|
||||
// longer than the available characters
|
||||
if ($no_duplicate_chars && strlen($pool) < $length) {
|
||||
throw new \LengthException('$length exceeds the size of the pool and $no_duplicate_chars is enabled');
|
||||
}
|
||||
|
||||
// Convert the pool of characters into an array of characters and
|
||||
// shuffle the array
|
||||
$pool = str_split($pool);
|
||||
$poolLength = count($pool);
|
||||
$rand = mt_rand(0, $poolLength - 1);
|
||||
|
||||
// Generate our string
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
$string .= $pool[$rand];
|
||||
|
||||
// Remove the character from the array to avoid duplicates
|
||||
array_splice($pool, $rand, 1);
|
||||
|
||||
// Generate a new number
|
||||
if (($poolLength - 2 - $i) > 0) {
|
||||
$rand = mt_rand(0, $poolLength - 2 - $i);
|
||||
} else {
|
||||
$rand = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate secure random string of given length
|
||||
* If 'openssl_random_pseudo_bytes' is not available
|
||||
* then generate random string using default function
|
||||
*
|
||||
* Part of the Laravel Project <https://github.com/laravel/laravel>
|
||||
*
|
||||
* @param int $length length of string
|
||||
* @return bool
|
||||
*/
|
||||
public static function secure_random_string($length = 16)
|
||||
{
|
||||
if (function_exists('openssl_random_pseudo_bytes')) {
|
||||
$bytes = openssl_random_pseudo_bytes($length * 2);
|
||||
|
||||
if ($bytes === false) {
|
||||
throw new \LengthException('$length is not accurate, unable to generate random string');
|
||||
}
|
||||
|
||||
return substr(str_replace(array('/', '+', '='), '', base64_encode($bytes)), 0, $length);
|
||||
}
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
return static::random_string($length);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given string matches a given pattern.
|
||||
*
|
||||
* Contributed by Abhimanyu Sharma <https://github.com/abhimanyusharma003>
|
||||
*
|
||||
* @param string $pattern Parttern of string exptected
|
||||
* @param string $string String that need to be matched
|
||||
* @return bool
|
||||
*/
|
||||
public static function match_string($pattern, $string, $caseSensitive = true)
|
||||
{
|
||||
if ($pattern == $string) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Preg flags
|
||||
$flags = $caseSensitive ? '' : 'i';
|
||||
|
||||
// Escape any regex special characters
|
||||
$pattern = preg_quote($pattern, '#');
|
||||
|
||||
// Unescape * which is our wildcard character and change it to .*
|
||||
$pattern = str_replace('\*', '.*', $pattern);
|
||||
|
||||
return (bool) preg_match('#^' . $pattern . '$#' . $flags, $string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate an email address.
|
||||
*
|
||||
* @param string $possible_email An email address to validate
|
||||
* @return bool
|
||||
*/
|
||||
public static function validate_email($possible_email)
|
||||
{
|
||||
return (bool) filter_var($possible_email, FILTER_VALIDATE_EMAIL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the URL to a user's gravatar.
|
||||
*
|
||||
* @param string $email The email of the user
|
||||
* @param integer $size The size of the gravatar
|
||||
* @return string
|
||||
*/
|
||||
public static function get_gravatar($email, $size = 32)
|
||||
{
|
||||
if (self::is_https()) {
|
||||
$url = 'https://secure.gravatar.com/';
|
||||
} else {
|
||||
$url = 'http://www.gravatar.com/';
|
||||
}
|
||||
|
||||
$url .= 'avatar/' . md5($email) . '?s=' . (int) abs($size);
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns all of the links in a string into HTML links.
|
||||
*
|
||||
* Part of the LinkifyURL Project <https://github.com/jmrware/LinkifyURL>
|
||||
*
|
||||
* @param string $text The string to parse
|
||||
* @return string
|
||||
*/
|
||||
public static function linkify($text)
|
||||
{
|
||||
$text = preg_replace('/'/', ''', $text); // IE does not handle ' entity!
|
||||
$section_html_pattern = '%# Rev:20100913_0900 github.com/jmrware/LinkifyURL
|
||||
# Section text into HTML <A> tags and everything else.
|
||||
( # $1: Everything not HTML <A> tag.
|
||||
[^<]+(?:(?!<a\b)<[^<]*)* # non A tag stuff starting with non-"<".
|
||||
| (?:(?!<a\b)<[^<]*)+ # non A tag stuff starting with "<".
|
||||
) # End $1.
|
||||
| ( # $2: HTML <A...>...</A> tag.
|
||||
<a\b[^>]*> # <A...> opening tag.
|
||||
[^<]*(?:(?!</a\b)<[^<]*)* # A tag contents.
|
||||
</a\s*> # </A> closing tag.
|
||||
) # End $2:
|
||||
%ix';
|
||||
|
||||
return preg_replace_callback($section_html_pattern, array(__CLASS__, 'linkifyCallback'), $text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for the preg_replace in the linkify() method.
|
||||
*
|
||||
* Part of the LinkifyURL Project <https://github.com/jmrware/LinkifyURL>
|
||||
*
|
||||
* @param array $matches Matches from the preg_ function
|
||||
* @return string
|
||||
*/
|
||||
protected static function linkifyRegex($text)
|
||||
{
|
||||
$url_pattern = '/# Rev:20100913_0900 github.com\/jmrware\/LinkifyURL
|
||||
# Match http & ftp URL that is not already linkified.
|
||||
# Alternative 1: URL delimited by (parentheses).
|
||||
(\() # $1 "(" start delimiter.
|
||||
((?:ht|f)tps?:\/\/[a-z0-9\-._~!$&\'()*+,;=:\/?#[\]@%]+) # $2: URL.
|
||||
(\)) # $3: ")" end delimiter.
|
||||
| # Alternative 2: URL delimited by [square brackets].
|
||||
(\[) # $4: "[" start delimiter.
|
||||
((?:ht|f)tps?:\/\/[a-z0-9\-._~!$&\'()*+,;=:\/?#[\]@%]+) # $5: URL.
|
||||
(\]) # $6: "]" end delimiter.
|
||||
| # Alternative 3: URL delimited by {curly braces}.
|
||||
(\{) # $7: "{" start delimiter.
|
||||
((?:ht|f)tps?:\/\/[a-z0-9\-._~!$&\'()*+,;=:\/?#[\]@%]+) # $8: URL.
|
||||
(\}) # $9: "}" end delimiter.
|
||||
| # Alternative 4: URL delimited by <angle brackets>.
|
||||
(<|&(?:lt|\#60|\#x3c);) # $10: "<" start delimiter (or HTML entity).
|
||||
((?:ht|f)tps?:\/\/[a-z0-9\-._~!$&\'()*+,;=:\/?#[\]@%]+) # $11: URL.
|
||||
(>|&(?:gt|\#62|\#x3e);) # $12: ">" end delimiter (or HTML entity).
|
||||
| # Alternative 5: URL not delimited by (), [], {} or <>.
|
||||
(# $13: Prefix proving URL not already linked.
|
||||
(?: ^ # Can be a beginning of line or string, or
|
||||
| [^=\s\'"\]] # a non-"=", non-quote, non-"]", followed by
|
||||
) \s*[\'"]? # optional whitespace and optional quote;
|
||||
| [^=\s]\s+ # or... a non-equals sign followed by whitespace.
|
||||
) # End $13. Non-prelinkified-proof prefix.
|
||||
(\b # $14: Other non-delimited URL.
|
||||
(?:ht|f)tps?:\/\/ # Required literal http, https, ftp or ftps prefix.
|
||||
[a-z0-9\-._~!$\'()*+,;=:\/?#[\]@%]+ # All URI chars except "&" (normal*).
|
||||
(?: # Either on a "&" or at the end of URI.
|
||||
(?! # Allow a "&" char only if not start of an...
|
||||
&(?:gt|\#0*62|\#x0*3e); # HTML ">" entity, or
|
||||
| &(?:amp|apos|quot|\#0*3[49]|\#x0*2[27]); # a [&\'"] entity if
|
||||
[.!&\',:?;]? # followed by optional punctuation then
|
||||
(?:[^a-z0-9\-._~!$&\'()*+,;=:\/?#[\]@%]|$) # a non-URI char or EOS.
|
||||
) & # If neg-assertion true, match "&" (special).
|
||||
[a-z0-9\-._~!$\'()*+,;=:\/?#[\]@%]* # More non-& URI chars (normal*).
|
||||
)* # Unroll-the-loop (special normal*)*.
|
||||
[a-z0-9\-_~$()*+=\/#[\]@%] # Last char can\'t be [.!&\',;:?]
|
||||
) # End $14. Other non-delimited URL.
|
||||
/imx';
|
||||
|
||||
$url_replace = '$1$4$7$10$13<a href="$2$5$8$11$14">$2$5$8$11$14</a>$3$6$9$12';
|
||||
|
||||
return preg_replace($url_pattern, $url_replace, $text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for the preg_replace in the linkify() method.
|
||||
*
|
||||
* Part of the LinkifyURL Project <https://github.com/jmrware/LinkifyURL>
|
||||
*
|
||||
* @param array $matches Matches from the preg_ function
|
||||
* @return string
|
||||
*/
|
||||
protected static function linkifyCallback($matches)
|
||||
{
|
||||
if (isset($matches[2])) {
|
||||
return $matches[2];
|
||||
}
|
||||
|
||||
return self::linkifyRegex($matches[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current URL.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_current_url()
|
||||
{
|
||||
$url = '';
|
||||
|
||||
// Check to see if it's over https
|
||||
$is_https = self::is_https();
|
||||
if ($is_https) {
|
||||
$url .= 'https://';
|
||||
} else {
|
||||
$url .= 'http://';
|
||||
}
|
||||
|
||||
// Was a username or password passed?
|
||||
if (isset($_SERVER['PHP_AUTH_USER'])) {
|
||||
$url .= $_SERVER['PHP_AUTH_USER'];
|
||||
|
||||
if (isset($_SERVER['PHP_AUTH_PW'])) {
|
||||
$url .= ':' . $_SERVER['PHP_AUTH_PW'];
|
||||
}
|
||||
|
||||
$url .= '@';
|
||||
}
|
||||
|
||||
|
||||
// We want the user to stay on the same host they are currently on,
|
||||
// but beware of security issues
|
||||
// see http://shiflett.org/blog/2006/mar/server-name-versus-http-host
|
||||
$url .= $_SERVER['HTTP_HOST'];
|
||||
|
||||
$port = $_SERVER['SERVER_PORT'];
|
||||
|
||||
// Is it on a non standard port?
|
||||
if ($is_https && ($port != 443)) {
|
||||
$url .= ':' . $_SERVER['SERVER_PORT'];
|
||||
} elseif (!$is_https && ($port != 80)) {
|
||||
$url .= ':' . $_SERVER['SERVER_PORT'];
|
||||
}
|
||||
|
||||
// Get the rest of the URL
|
||||
if (!isset($_SERVER['REQUEST_URI'])) {
|
||||
// Microsoft IIS doesn't set REQUEST_URI by default
|
||||
$url .= $_SERVER['PHP_SELF'];
|
||||
|
||||
if (isset($_SERVER['QUERY_STRING'])) {
|
||||
$url .= '?' . $_SERVER['QUERY_STRING'];
|
||||
}
|
||||
} else {
|
||||
$url .= $_SERVER['REQUEST_URI'];
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the IP address of the client.
|
||||
*
|
||||
* @param boolean $trust_proxy_headers Whether or not to trust the
|
||||
* proxy headers HTTP_CLIENT_IP
|
||||
* and HTTP_X_FORWARDED_FOR. ONLY
|
||||
* use if your server is behind a
|
||||
* proxy that sets these values
|
||||
* @return string
|
||||
*/
|
||||
public static function get_client_ip($trust_proxy_headers = false)
|
||||
{
|
||||
if (!$trust_proxy_headers) {
|
||||
return $_SERVER['REMOTE_ADDR'];
|
||||
}
|
||||
|
||||
if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
|
||||
$ip = $_SERVER['HTTP_CLIENT_IP'];
|
||||
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
|
||||
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
|
||||
} else {
|
||||
$ip = $_SERVER['REMOTE_ADDR'];
|
||||
}
|
||||
|
||||
return $ip;
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncate a string to a specified length without cutting a word off.
|
||||
*
|
||||
* @param string $string The string to truncate
|
||||
* @param integer $length The length to truncate the string to
|
||||
* @param string $append Text to append to the string IF it gets
|
||||
* truncated, defaults to '...'
|
||||
* @return string
|
||||
*/
|
||||
public static function safe_truncate($string, $length, $append = '...')
|
||||
{
|
||||
$ret = substr($string, 0, $length);
|
||||
$last_space = strrpos($ret, ' ');
|
||||
|
||||
if ($last_space !== false && $string != $ret) {
|
||||
$ret = substr($ret, 0, $last_space);
|
||||
}
|
||||
|
||||
if ($ret != $string) {
|
||||
$ret .= $append;
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Truncate the string to given length of charactes.
|
||||
*
|
||||
* @param $string
|
||||
* @param $limit
|
||||
* @param string $append
|
||||
* @return string
|
||||
*/
|
||||
public static function limit_characters($string, $limit = 100, $append = '...')
|
||||
{
|
||||
if (mb_strlen($string) <= $limit) {
|
||||
return $string;
|
||||
}
|
||||
|
||||
return rtrim(mb_substr($string, 0, $limit, 'UTF-8')) . $append;
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncate the string to given length of words.
|
||||
*
|
||||
* @param $string
|
||||
* @param $limit
|
||||
* @param string $append
|
||||
* @return string
|
||||
*/
|
||||
public static function limit_words($string, $limit = 100, $append = '...')
|
||||
{
|
||||
preg_match('/^\s*+(?:\S++\s*+){1,' . $limit . '}/u', $string, $matches);
|
||||
|
||||
if (!isset($matches[0]) || strlen($string) === strlen($matches[0])) {
|
||||
return $string;
|
||||
}
|
||||
|
||||
return rtrim($matches[0]).$append;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ordinal version of a number (appends th, st, nd, rd).
|
||||
*
|
||||
* @param string $number The number to append an ordinal suffix to
|
||||
* @return string
|
||||
*/
|
||||
public static function ordinal($number)
|
||||
{
|
||||
$test_c = abs($number) % 10;
|
||||
$ext = ((abs($number) % 100 < 21 && abs($number) % 100 > 4) ? 'th' : (($test_c < 4) ? ($test_c < 3) ? ($test_c < 2) ? ($test_c < 1) ? 'th' : 'st' : 'nd' : 'rd' : 'th'));
|
||||
|
||||
return $number . $ext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file permissions as a nice string, like -rw-r--r-- or false
|
||||
* if the file is not found.
|
||||
*
|
||||
* @param string $file The name of the file to get permissions form
|
||||
* @param int $perms Numerical value of permissions to display as text.
|
||||
* @return string
|
||||
*/
|
||||
public static function full_permissions($file, $perms = null)
|
||||
{
|
||||
if (is_null($perms)) {
|
||||
if (!file_exists($file)) {
|
||||
return false;
|
||||
}
|
||||
$perms = fileperms($file);
|
||||
}
|
||||
|
||||
if (($perms & 0xC000) == 0xC000) {
|
||||
// Socket
|
||||
$info = 's';
|
||||
} elseif (($perms & 0xA000) == 0xA000) {
|
||||
// Symbolic Link
|
||||
$info = 'l';
|
||||
} elseif (($perms & 0x8000) == 0x8000) {
|
||||
// Regular
|
||||
$info = '-';
|
||||
} elseif (($perms & 0x6000) == 0x6000) {
|
||||
// Block special
|
||||
$info = 'b';
|
||||
} elseif (($perms & 0x4000) == 0x4000) {
|
||||
// Directory
|
||||
$info = 'd';
|
||||
} elseif (($perms & 0x2000) == 0x2000) {
|
||||
// Character special
|
||||
$info = 'c';
|
||||
} elseif (($perms & 0x1000) == 0x1000) {
|
||||
// FIFO pipe
|
||||
$info = 'p';
|
||||
} else {
|
||||
// Unknown
|
||||
$info = 'u';
|
||||
}
|
||||
|
||||
// Owner
|
||||
$info .= (($perms & 0x0100) ? 'r' : '-');
|
||||
$info .= (($perms & 0x0080) ? 'w' : '-');
|
||||
$info .= (($perms & 0x0040) ?
|
||||
(($perms & 0x0800) ? 's' : 'x') :
|
||||
(($perms & 0x0800) ? 'S' : '-'));
|
||||
|
||||
// Group
|
||||
$info .= (($perms & 0x0020) ? 'r' : '-');
|
||||
$info .= (($perms & 0x0010) ? 'w' : '-');
|
||||
$info .= (($perms & 0x0008) ?
|
||||
(($perms & 0x0400) ? 's' : 'x') :
|
||||
(($perms & 0x0400) ? 'S' : '-'));
|
||||
|
||||
// World
|
||||
$info .= (($perms & 0x0004) ? 'r' : '-');
|
||||
$info .= (($perms & 0x0002) ? 'w' : '-');
|
||||
$info .= (($perms & 0x0001) ?
|
||||
(($perms & 0x0200) ? 't' : 'x') :
|
||||
(($perms & 0x0200) ? 'T' : '-'));
|
||||
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first element in an array.
|
||||
*
|
||||
* @param array $array
|
||||
* @return mixed
|
||||
*/
|
||||
public static function array_first(array $array)
|
||||
{
|
||||
return reset($array);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last element in an array.
|
||||
*
|
||||
* @param array $array
|
||||
* @return mixed
|
||||
*/
|
||||
public static function array_last(array $array)
|
||||
{
|
||||
return end($array);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first key in an array.
|
||||
*
|
||||
* @param array $array
|
||||
* @return int|string
|
||||
*/
|
||||
public static function array_first_key(array $array)
|
||||
{
|
||||
reset($array);
|
||||
|
||||
return key($array);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last key in an array.
|
||||
*
|
||||
* @param array $array
|
||||
* @return int|string
|
||||
*/
|
||||
public static function array_last_key(array $array)
|
||||
{
|
||||
end($array);
|
||||
|
||||
return key($array);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flatten a multi-dimensional array into a one dimensional array.
|
||||
*
|
||||
* Contributed by Theodore R. Smith of PHP Experts, Inc. <http://www.phpexperts.pro/>
|
||||
*
|
||||
* @param array $array The array to flatten
|
||||
* @param boolean $preserve_keys Whether or not to preserve array keys.
|
||||
* Keys from deeply nested arrays will
|
||||
* overwrite keys from shallowy nested arrays
|
||||
* @return array
|
||||
*/
|
||||
public static function array_flatten(array $array, $preserve_keys = true)
|
||||
{
|
||||
$flattened = array();
|
||||
|
||||
array_walk_recursive($array, function($value, $key) use (&$flattened, $preserve_keys) {
|
||||
if ($preserve_keys && !is_int($key)) {
|
||||
$flattened[$key] = $value;
|
||||
} else {
|
||||
$flattened[] = $value;
|
||||
}
|
||||
});
|
||||
|
||||
return $flattened;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts an array, and returns an array of values from that array as
|
||||
* specified by $field. For example, if the array is full of objects
|
||||
* and you call util::array_pluck($array, 'name'), the function will
|
||||
* return an array of values from $array[]->name.
|
||||
*
|
||||
* @param array $array An array
|
||||
* @param string $field The field to get values from
|
||||
* @param boolean $preserve_keys Whether or not to preserve the
|
||||
* array keys
|
||||
* @param boolean $remove_nomatches If the field doesn't appear to be set,
|
||||
* remove it from the array
|
||||
* @return array
|
||||
*/
|
||||
public static function array_pluck(array $array, $field, $preserve_keys = true, $remove_nomatches = true)
|
||||
{
|
||||
$new_list = array();
|
||||
|
||||
foreach ($array as $key => $value) {
|
||||
if (is_object($value)) {
|
||||
if (isset($value->{$field})) {
|
||||
if ($preserve_keys) {
|
||||
$new_list[$key] = $value->{$field};
|
||||
} else {
|
||||
$new_list[] = $value->{$field};
|
||||
}
|
||||
} elseif (!$remove_nomatches) {
|
||||
$new_list[$key] = $value;
|
||||
}
|
||||
} else {
|
||||
if (isset($value[$field])) {
|
||||
if ($preserve_keys) {
|
||||
$new_list[$key] = $value[$field];
|
||||
} else {
|
||||
$new_list[] = $value[$field];
|
||||
}
|
||||
} elseif (!$remove_nomatches) {
|
||||
$new_list[$key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $new_list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for a given value in an array of arrays, objects and scalar
|
||||
* values. You can optionally specify a field of the nested arrays and
|
||||
* objects to search in.
|
||||
*
|
||||
* @param array $array The array to search
|
||||
* @param scalar $search The value to search for
|
||||
* @param string $field The field to search in, if not specified
|
||||
* all fields will be searched
|
||||
* @return boolean|scalar False on failure or the array key on success
|
||||
*/
|
||||
public static function array_search_deep(array $array, $search, $field = false)
|
||||
{
|
||||
// *grumbles* stupid PHP type system
|
||||
$search = (string) $search;
|
||||
|
||||
foreach ($array as $key => $elem) {
|
||||
// *grumbles* stupid PHP type system
|
||||
$key = (string) $key;
|
||||
|
||||
if ($field) {
|
||||
if (is_object($elem) && $elem->{$field} === $search) {
|
||||
return $key;
|
||||
} elseif (is_array($elem) && $elem[$field] === $search) {
|
||||
return $key;
|
||||
} elseif (is_scalar($elem) && $elem === $search) {
|
||||
return $key;
|
||||
}
|
||||
} else {
|
||||
if (is_object($elem)) {
|
||||
$elem = (array) $elem;
|
||||
|
||||
if (in_array($search, $elem)) {
|
||||
return $key;
|
||||
}
|
||||
} elseif (is_array($elem) && in_array($search, $elem)) {
|
||||
return $key;
|
||||
} elseif (is_scalar($elem) && $elem === $search) {
|
||||
return $key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array containing all the elements of arr1 after applying
|
||||
* the callback function to each one.
|
||||
*
|
||||
* @param string $callback Callback function to run for each
|
||||
* element in each array
|
||||
* @param array $array An array to run through the callback
|
||||
* function
|
||||
* @param boolean $on_nonscalar Whether or not to call the callback
|
||||
* function on nonscalar values
|
||||
* (Objects, resources, etc)
|
||||
* @return array
|
||||
*/
|
||||
public static function array_map_deep(array $array, $callback, $on_nonscalar = false)
|
||||
{
|
||||
foreach ($array as $key => $value) {
|
||||
if (is_array($value)) {
|
||||
$args = array($value, $callback, $on_nonscalar);
|
||||
$array[$key] = call_user_func_array(array(__CLASS__, __FUNCTION__), $args);
|
||||
} elseif (is_scalar($value) || $on_nonscalar) {
|
||||
$array[$key] = call_user_func($callback, $value);
|
||||
}
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
public static function array_clean(array $array)
|
||||
{
|
||||
return array_filter($array);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper to prevent errors if the user doesn't have the mbstring
|
||||
* extension installed.
|
||||
*
|
||||
* @param string $encoding
|
||||
* @return string
|
||||
*/
|
||||
protected static function mbInternalEncoding($encoding = null)
|
||||
{
|
||||
if (function_exists('mb_internal_encoding')) {
|
||||
return $encoding ? mb_internal_encoding($encoding) : mb_internal_encoding();
|
||||
}
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
return 'UTF-8';
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the writable bit on a file to the minimum value that allows the user
|
||||
* running PHP to write to it.
|
||||
*
|
||||
* @param string $filename The filename to set the writable bit on
|
||||
* @param boolean $writable Whether to make the file writable or not
|
||||
* @return boolean
|
||||
*/
|
||||
public static function set_writable($filename, $writable = true)
|
||||
{
|
||||
$stat = @stat($filename);
|
||||
|
||||
if ($stat === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We're on Windows
|
||||
if (strncasecmp(PHP_OS, 'WIN', 3) === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
list($myuid, $mygid) = array(posix_geteuid(), posix_getgid());
|
||||
|
||||
if ($writable) {
|
||||
// Set only the user writable bit (file is owned by us)
|
||||
if ($stat['uid'] == $myuid) {
|
||||
return chmod($filename, fileperms($filename) | 0200);
|
||||
}
|
||||
|
||||
// Set only the group writable bit (file group is the same as us)
|
||||
if ($stat['gid'] == $mygid) {
|
||||
return chmod($filename, fileperms($filename) | 0220);
|
||||
}
|
||||
|
||||
// Set the world writable bit (file isn't owned or grouped by us)
|
||||
return chmod($filename, fileperms($filename) | 0222);
|
||||
} else {
|
||||
// Set only the user writable bit (file is owned by us)
|
||||
if ($stat['uid'] == $myuid) {
|
||||
return chmod($filename, (fileperms($filename) | 0222) ^ 0222);
|
||||
}
|
||||
|
||||
// Set only the group writable bit (file group is the same as us)
|
||||
if ($stat['gid'] == $mygid) {
|
||||
return chmod($filename, (fileperms($filename) | 0222) ^ 0022);
|
||||
}
|
||||
|
||||
// Set the world writable bit (file isn't owned or grouped by us)
|
||||
return chmod($filename, (fileperms($filename) | 0222) ^ 0002);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the readable bit on a file to the minimum value that allows the user
|
||||
* running PHP to read to it.
|
||||
*
|
||||
* @param string $filename The filename to set the readable bit on
|
||||
* @param boolean $readable Whether to make the file readable or not
|
||||
* @return boolean
|
||||
*/
|
||||
public static function set_readable($filename, $readable = true)
|
||||
{
|
||||
$stat = @stat($filename);
|
||||
|
||||
if ($stat === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We're on Windows
|
||||
if (strncasecmp(PHP_OS, 'WIN', 3) === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
list($myuid, $mygid) = array(posix_geteuid(), posix_getgid());
|
||||
|
||||
if ($readable) {
|
||||
// Set only the user readable bit (file is owned by us)
|
||||
if ($stat['uid'] == $myuid) {
|
||||
return chmod($filename, fileperms($filename) | 0400);
|
||||
}
|
||||
|
||||
// Set only the group readable bit (file group is the same as us)
|
||||
if ($stat['gid'] == $mygid) {
|
||||
return chmod($filename, fileperms($filename) | 0440);
|
||||
}
|
||||
|
||||
// Set the world readable bit (file isn't owned or grouped by us)
|
||||
return chmod($filename, fileperms($filename) | 0444);
|
||||
} else {
|
||||
// Set only the user readable bit (file is owned by us)
|
||||
if ($stat['uid'] == $myuid) {
|
||||
return chmod($filename, (fileperms($filename) | 0444) ^ 0444);
|
||||
}
|
||||
|
||||
// Set only the group readable bit (file group is the same as us)
|
||||
if ($stat['gid'] == $mygid) {
|
||||
return chmod($filename, (fileperms($filename) | 0444) ^ 0044);
|
||||
}
|
||||
|
||||
// Set the world readable bit (file isn't owned or grouped by us)
|
||||
return chmod($filename, (fileperms($filename) | 0444) ^ 0004);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the executable bit on a file to the minimum value that allows the
|
||||
* user running PHP to read to it.
|
||||
*
|
||||
* @param string $filename The filename to set the executable bit on
|
||||
* @param boolean $executable Whether to make the file executable or not
|
||||
* @return boolean
|
||||
*/
|
||||
public static function set_executable($filename, $executable = true)
|
||||
{
|
||||
$stat = @stat($filename);
|
||||
|
||||
if ($stat === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We're on Windows
|
||||
if (strncasecmp(PHP_OS, 'WIN', 3) === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
list($myuid, $mygid) = array(posix_geteuid(), posix_getgid());
|
||||
|
||||
if ($executable) {
|
||||
// Set only the user readable bit (file is owned by us)
|
||||
if ($stat['uid'] == $myuid) {
|
||||
return chmod($filename, fileperms($filename) | 0100);
|
||||
}
|
||||
|
||||
// Set only the group readable bit (file group is the same as us)
|
||||
if ($stat['gid'] == $mygid) {
|
||||
return chmod($filename, fileperms($filename) | 0110);
|
||||
}
|
||||
|
||||
// Set the world readable bit (file isn't owned or grouped by us)
|
||||
return chmod($filename, fileperms($filename) | 0111);
|
||||
} else {
|
||||
// Set only the user readable bit (file is owned by us)
|
||||
if ($stat['uid'] == $myuid) {
|
||||
return chmod($filename, (fileperms($filename) | 0111) ^ 0111);
|
||||
}
|
||||
|
||||
// Set only the group readable bit (file group is the same as us)
|
||||
if ($stat['gid'] == $mygid) {
|
||||
return chmod($filename, (fileperms($filename) | 0111) ^ 0011);
|
||||
}
|
||||
|
||||
// Set the world readable bit (file isn't owned or grouped by us)
|
||||
return chmod($filename, (fileperms($filename) | 0111) ^ 0001);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns size of a given directory in bytes.
|
||||
*
|
||||
* @param string $dir
|
||||
* @return integer
|
||||
*/
|
||||
public static function directory_size($dir)
|
||||
{
|
||||
$size = 0;
|
||||
foreach(new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($dir, \FilesystemIterator::CURRENT_AS_FILEINFO | \FilesystemIterator::SKIP_DOTS)) as $file => $key) {
|
||||
if ($key->isFile()) {
|
||||
$size += $key->getSize();
|
||||
}
|
||||
}
|
||||
return $size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a home directory of current user.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_user_directory()
|
||||
{
|
||||
if (isset($_SERVER['HOMEDRIVE'])) return $_SERVER['HOMEDRIVE'] . $_SERVER['HOMEPATH'];
|
||||
else return $_SERVER['HOME'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all paths inside a directory.
|
||||
*
|
||||
* @param string $dir
|
||||
* @return array
|
||||
*/
|
||||
public static function directory_contents($dir)
|
||||
{
|
||||
$contents = array();
|
||||
foreach(new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($dir, \FilesystemIterator::KEY_AS_PATHNAME | \FilesystemIterator::CURRENT_AS_FILEINFO | \FilesystemIterator::SKIP_DOTS)) as $pathname => $fi) {
|
||||
$contents[] = $pathname;
|
||||
}
|
||||
natsort($contents);
|
||||
return $contents;
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
# UtilityPHP Unit Tests #
|
||||
|
||||
### Introduction
|
||||
|
||||
This is the testing documentation for util.php. The unit tests require PHPUnit,
|
||||
and can be run in your web browser.
|
||||
|
||||
### Requirements
|
||||
|
||||
PHP Unit >= 3.5.6
|
||||
|
||||
#### Installation of PHPUnit
|
||||
|
||||
# Download the PHPUnit phar.
|
||||
wget https://phar.phpunit.de/phpunit.phar
|
||||
|
||||
# You can just run it locally. (Preferred for Windows)
|
||||
php phpunit.phar --version
|
||||
|
||||
# Or install it system-wide.
|
||||
mv phpunit.phar phpunit
|
||||
chmod +x phpunit
|
||||
sudo mv phpunit /usr/local/bin
|
||||
phpunit --version
|
||||
|
||||
## Test Suites:
|
||||
|
||||
util.php includes a phpunit config file, so just run `phpunit` from the working
|
||||
directory to run the test suite.
|
||||
|
||||
```
|
||||
phpunit
|
||||
```
|
||||
|
||||
If you want code coverage reports, use the following:
|
||||
|
||||
```
|
||||
phpunit --coverage-html ./report
|
||||
```
|
||||
+1183
@@ -0,0 +1,1183 @@
|
||||
<?php
|
||||
|
||||
date_default_timezone_set('UTC');
|
||||
|
||||
require_once dirname(__FILE__) . '/../util.php';
|
||||
|
||||
class VarDumpExperiment
|
||||
{
|
||||
public $public = 1;
|
||||
protected $protected = 2;
|
||||
private $private = 3;
|
||||
public $data;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->data = (object)array('a', 'b', 'c');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* PHPUnit test case for the util.php library
|
||||
*
|
||||
* @author Brandon Wamboldt <brandon.wamboldt@gmail.com>
|
||||
* @since 1.0.000
|
||||
*/
|
||||
class UtilityPHPTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* Allows for the testing of private and protected methods.
|
||||
*
|
||||
* @param $name
|
||||
* @return \ReflectionMethod
|
||||
*/
|
||||
protected static function getMethod($name)
|
||||
{
|
||||
$class = new \ReflectionClass('util');
|
||||
$method = $class->getMethod($name);
|
||||
$method->setAccessible(true);
|
||||
return $method;
|
||||
}
|
||||
|
||||
public function test_array_get()
|
||||
{
|
||||
$_GET = array();
|
||||
$_GET['abc'] = 'def';
|
||||
$_GET['nested'] = array( 'key1' => 'val1', 'key2' => 'val2', 'key3' => 'val3' );
|
||||
|
||||
// Looks for $array['abc']
|
||||
$this->assertEquals( 'def', util::array_get( $_GET['abc'] ) );
|
||||
|
||||
// Looks for $array['nested']['key2']
|
||||
$this->assertEquals( 'val2', util::array_get( $_GET['nested']['key2'] ) );
|
||||
|
||||
// Looks for $array['doesnotexist']
|
||||
$this->assertEquals( 'defaultval', util::array_get( $_GET['doesnotexist'], 'defaultval' ) );
|
||||
}
|
||||
|
||||
public function test_slugify()
|
||||
{
|
||||
$this->assertEquals( 'a-simple-title', util::slugify( 'A simple title' ) );
|
||||
$this->assertEquals( 'this-post-it-has-a-dash', util::slugify( 'This post -- it has a dash' ) );
|
||||
$this->assertEquals( '123-1251251', util::slugify( '123----1251251' ) );
|
||||
$this->assertEquals( 'one23-1251251', util::slugify( '123----1251251', '-', true ) );
|
||||
|
||||
$this->assertEquals( 'a-simple-title', util::slugify( 'A simple title', '-' ) );
|
||||
$this->assertEquals( 'this-post-it-has-a-dash', util::slugify( 'This post -- it has a dash', '-' ) );
|
||||
$this->assertEquals( '123-1251251', util::slugify( '123----1251251', '-' ) );
|
||||
$this->assertEquals( 'one23-1251251', util::slugify( '123----1251251', '-', true ) );
|
||||
|
||||
$this->assertEquals( 'a_simple_title', util::slugify( 'A simple title', '_' ) );
|
||||
$this->assertEquals( 'this_post_it_has_a_dash', util::slugify( 'This post -- it has a dash', '_' ) );
|
||||
$this->assertEquals( '123_1251251', util::slugify( '123----1251251', '_' ) );
|
||||
$this->assertEquals( 'one23_1251251', util::slugify( '123----1251251', '_', true ) );
|
||||
|
||||
// Blank seperator test
|
||||
$this->assertEquals( 'asimpletitle', util::slugify( 'A simple title', '' ) );
|
||||
$this->assertEquals( 'thispostithasadash', util::slugify( 'This post -- it has a dash', '' ) );
|
||||
$this->assertEquals( '1231251251', util::slugify( '123----1251251', '' ) );
|
||||
$this->assertEquals( 'one231251251', util::slugify( '123----1251251', '', true ) );
|
||||
|
||||
// Test old parameter ordering for backwards compatability
|
||||
error_reporting(E_ALL ^ E_USER_DEPRECATED);
|
||||
$this->assertEquals( 'one23-1251251', util::slugify( '123----1251251', true ) );
|
||||
$this->assertEquals( '123-1251251', util::slugify( '123----1251251', false ) );
|
||||
}
|
||||
|
||||
public function test_seems_utf8()
|
||||
{
|
||||
// Test a valid UTF-8 sequence: "ÜTF-8 Fµñ".
|
||||
$validUTF8 = "\xC3\x9CTF-8 F\xC2\xB5\xC3\xB1";
|
||||
$this->assertTrue( util::seems_utf8( $validUTF8 ) );
|
||||
|
||||
$this->assertTrue( util::seems_utf8( "\xEF\xBF\xBD this has \xEF\xBF\xBD\xEF\xBF\xBD some invalid utf8 \xEF\xBF\xBD" ) );
|
||||
|
||||
// Test invalid UTF-8 sequences
|
||||
$invalidUTF8 = "\xc3 this has \xe6\x9d some invalid utf8 \xe6";
|
||||
$this->assertFalse( util::seems_utf8( $invalidUTF8 ) );
|
||||
|
||||
// And test some plain ASCII
|
||||
$this->assertTrue( util::seems_utf8( 'The quick brown fox jumps over the lazy dog' ) );
|
||||
|
||||
// Test an invalid non-UTF-8 string.
|
||||
if (function_exists('mb_convert_encoding')) {
|
||||
mb_internal_encoding('UTF-8');
|
||||
// Converts the 'ç' UTF-8 character to UCS-2LE
|
||||
$utf8Char = pack('n', 50087);
|
||||
$ucsChar = mb_convert_encoding($utf8Char, 'UCS-2LE', 'UTF-8');
|
||||
|
||||
// Ensure that PHP's internal encoding system isn't malconfigured.
|
||||
$this->assertEquals( $utf8Char, 'ç', 'This PHP system\'s internal character set is not properly set as UTF-8.' );
|
||||
$this->assertEquals( $utf8Char, pack('n', 50087), 'Something is wrong with your ICU unicode library.' );
|
||||
|
||||
// Test for not UTF-8.
|
||||
$this->assertFalse( util::seems_utf8( $ucsChar) );
|
||||
|
||||
// Test the worker method.
|
||||
$method = self::getMethod('seemsUtf8Regex');
|
||||
$this->assertFalse($method->invoke(null, $invalidUTF8), 'util::seemsUtf8Regex did not properly detect invalid UTF-8.');
|
||||
$this->assertTrue($method->invoke(null, $validUTF8), 'util::seemsUtf8Regex did not properly detect valid UTF-8.');
|
||||
}
|
||||
}
|
||||
|
||||
public function test_size_format()
|
||||
{
|
||||
$size = util::size_format( 512, 0 );
|
||||
$this->assertEquals( '512 B', $size );
|
||||
|
||||
$size = util::size_format( 2048, 1 );
|
||||
$this->assertEquals( '2.0 KiB', $size );
|
||||
|
||||
$size = util::size_format( 25151251, 2 );
|
||||
$this->assertEquals( '23.99 MiB', $size );
|
||||
|
||||
$size = util::size_format( 19971597926, 2 );
|
||||
$this->assertEquals( '18.60 GiB', $size );
|
||||
|
||||
$size = util::size_format( 2748779069440, 1 );
|
||||
$this->assertEquals( '2.5 TiB', $size );
|
||||
|
||||
$size = util::size_format( 2.81475e15, 1 );
|
||||
$this->assertEquals( '2.5 PiB', $size );
|
||||
|
||||
$size = util::size_format( 2.81475e19, 1 );
|
||||
$this->assertEquals( '25000.0 PiB', $size );
|
||||
}
|
||||
|
||||
public function test_maybe_serialize()
|
||||
{
|
||||
$obj = new stdClass();
|
||||
$obj->prop1 = 'Hello';
|
||||
$obj->prop2 = 'World';
|
||||
|
||||
$this->assertEquals( 'This is a string', util::maybe_serialize( 'This is a string' ) );
|
||||
$this->assertEquals( 5.81, util::maybe_serialize( 5.81 ) );
|
||||
$this->assertEquals( 'a:0:{}', util::maybe_serialize( array() ) );
|
||||
$this->assertEquals( 'O:8:"stdClass":2:{s:5:"prop1";s:5:"Hello";s:5:"prop2";s:5:"World";}', util::maybe_serialize( $obj ) );
|
||||
$this->assertEquals( 'a:4:{i:0;s:4:"test";i:1;s:4:"blah";s:5:"hello";s:5:"world";s:5:"array";O:8:"stdClass":2:{s:5:"prop1";s:5:"Hello";s:5:"prop2";s:5:"World";}}', util::maybe_serialize( array( 'test', 'blah', 'hello' => 'world', 'array' => $obj ) ) );
|
||||
}
|
||||
|
||||
public function test_maybe_unserialize()
|
||||
{
|
||||
$obj = new stdClass();
|
||||
$obj->prop1 = 'Hello';
|
||||
$obj->prop2 = 'World';
|
||||
|
||||
$this->assertNull(util::maybe_unserialize(serialize(null)));
|
||||
$this->assertFalse(util::maybe_unserialize(serialize(false)));
|
||||
|
||||
$this->assertEquals( 'This is a string', util::maybe_unserialize( 'This is a string' ) );
|
||||
$this->assertEquals( 5.81, util::maybe_unserialize( 5.81 ) );
|
||||
$this->assertEquals( array(), util::maybe_unserialize( 'a:0:{}' ) );
|
||||
$this->assertEquals( $obj, util::maybe_unserialize( 'O:8:"stdClass":2:{s:5:"prop1";s:5:"Hello";s:5:"prop2";s:5:"World";}' ) );
|
||||
$this->assertEquals( array( 'test', 'blah', 'hello' => 'world', 'array' => $obj ), util::maybe_unserialize( 'a:4:{i:0;s:4:"test";i:1;s:4:"blah";s:5:"hello";s:5:"world";s:5:"array";O:8:"stdClass":2:{s:5:"prop1";s:5:"Hello";s:5:"prop2";s:5:"World";}}' ) );
|
||||
|
||||
// Test a broken serialization.
|
||||
$expectedData = array(
|
||||
'Normal',
|
||||
'High-value Char: '.chr(231).'a-va?', // High-value Char: ça-va? [in ISO-8859-1]
|
||||
);
|
||||
|
||||
$brokenSerialization = 'a:2:{i:0;s:6:"Normal";i:1;s:23:"High-value Char: ▒a-va?";}';
|
||||
|
||||
$unserializedData = util::maybe_unserialize($brokenSerialization);
|
||||
$this->assertEquals($expectedData[0], $unserializedData[0], 'Did not properly fix the broken serialized data.');
|
||||
$this->assertEquals(substr($expectedData[1], 0, 10), substr($unserializedData[1], 0, 10), 'Did not properly fix the broken serialized data.');
|
||||
|
||||
// Test unfixable serialization.
|
||||
$unfixableSerialization = 'a:2:{i:0;s:6:"Normal";}';
|
||||
$this->assertEquals($unfixableSerialization, util::maybe_unserialize($unfixableSerialization), 'Somehow the [previously?] impossible happened and utilphp thinks it has unserialized an unfixable serialization.');
|
||||
}
|
||||
|
||||
public function test_is_serialized()
|
||||
{
|
||||
$this->assertFalse( util::is_serialized(1) );
|
||||
$this->assertFalse( util::is_serialized(null) );
|
||||
$this->assertFalse( util::is_serialized( 's:4:"test;' ) );
|
||||
$this->assertFalse( util::is_serialized( 'a:0:{}!' ) );
|
||||
$this->assertFalse( util::is_serialized( 'a:0' ) );
|
||||
$this->assertFalse( util::is_serialized( 'This is a string' ) );
|
||||
$this->assertFalse( util::is_serialized( 'a string' ) );
|
||||
$this->assertFalse( util::is_serialized( 'z:0;' ) );
|
||||
$this->assertTrue( util::is_serialized( 'N;' ) );
|
||||
$this->assertTrue( util::is_serialized( 'b:1;' ) );
|
||||
$this->assertTrue( util::is_serialized( 'a:0:{}' ) );
|
||||
$this->assertTrue( util::is_serialized( 'O:8:"stdClass":2:{s:5:"prop1";s:5:"Hello";s:5:"prop2";s:5:"World";}' ) );
|
||||
}
|
||||
|
||||
public function test_fix_broken_serialization()
|
||||
{
|
||||
$expectedData = array(
|
||||
'Normal',
|
||||
'High-value Char: '.chr(231).'a-va?', // High-value Char: ça-va? [in ISO-8859-1]
|
||||
);
|
||||
|
||||
$brokenSerialization = 'a:2:{i:0;s:6:"Normal";i:1;s:23:"High-value Char: ▒a-va?";}';
|
||||
|
||||
// Temporarily override error handling to ensure that this is, in fact, [still] a broken serialization.
|
||||
{
|
||||
$expectedError = array(
|
||||
'errno' => 8,
|
||||
'errstr' => 'unserialize(): Error at offset 55 of 60 bytes'
|
||||
);
|
||||
|
||||
$reportedError = array();
|
||||
set_error_handler(function ($errno, $errstr, $errfile, $errline, $errcontext) use (&$reportedError) {
|
||||
$reportedError = compact('errno', 'errstr');
|
||||
});
|
||||
|
||||
unserialize($brokenSerialization);
|
||||
|
||||
$this->assertEquals($expectedError['errno'], $reportedError['errno']);
|
||||
// Because HHVM's unserialize() error message does not contain enough info to properly test.
|
||||
if (!defined('HHVM_VERSION')) {
|
||||
$this->assertEquals($expectedError['errstr'], $reportedError['errstr']);
|
||||
}
|
||||
restore_error_handler();
|
||||
}
|
||||
|
||||
$fixedSerialization = util::fix_broken_serialization($brokenSerialization);
|
||||
$unserializedData = unserialize($fixedSerialization);
|
||||
$this->assertEquals($expectedData[0], $unserializedData[0], 'Did not properly fix the broken serialized data.');
|
||||
|
||||
$this->assertEquals(substr($expectedData[1], 0, 10), substr($unserializedData[1], 0, 10), 'Did not properly fix the broken serialized data.');
|
||||
}
|
||||
|
||||
public function test_is_https()
|
||||
{
|
||||
$_SERVER['HTTPS'] = null;
|
||||
|
||||
$this->assertFalse( util::is_https() );
|
||||
|
||||
$_SERVER['HTTPS'] = 'on';
|
||||
|
||||
$this->assertTrue( util::is_https() );
|
||||
}
|
||||
|
||||
public function test_add_query_arg()
|
||||
{
|
||||
// Regular tests
|
||||
$this->assertEquals( '/app/admin/users?user=5', util::add_query_arg( 'user', 5, '/app/admin/users' ) );
|
||||
$this->assertEquals( '/app/admin/users?user=5', util::add_query_arg( array( 'user' => 5 ), '/app/admin/users' ) );
|
||||
$this->assertEquals( '/app/admin/users?user=5', util::add_query_arg( array( 'user' => 5 ), null, '/app/admin/users' ) );
|
||||
$this->assertEquals( '/app/admin/users?action=edit&user=5', util::add_query_arg( 'user', 5, '/app/admin/users?action=edit' ) );
|
||||
$this->assertEquals( '/app/admin/users?action=edit&user=5', util::add_query_arg( array( 'user' => 5 ), '/app/admin/users?action=edit' ) );
|
||||
$this->assertEquals( '/app/admin/users?action=edit&tab=personal&user=5', util::add_query_arg( 'user', 5, '/app/admin/users?action=edit&tab=personal' ) );
|
||||
$this->assertEquals( '/app/admin/users?action=edit&tab=personal&user=5', util::add_query_arg( array( 'user' => 5 ), '/app/admin/users?action=edit&tab=personal' ) );
|
||||
|
||||
// Ensure strips false.
|
||||
$this->assertEquals('/index.php', util::add_query_arg('debug', false, '/index.php'));
|
||||
|
||||
// With a URL fragment
|
||||
$this->assertEquals( '/app/admin/users?user=5#test', util::add_query_arg( 'user', 5, '/app/admin/users#test' ) );
|
||||
|
||||
// Full URL
|
||||
$this->assertEquals( 'http://example.com/?a=b', util::add_query_arg( 'a', 'b', 'http://example.com' ) );
|
||||
|
||||
// Only the query string
|
||||
$this->assertEquals( '?a=b&c=d', util::add_query_arg( 'c', 'd', '?a=b' ) );
|
||||
$this->assertEquals( 'a=b&c=d', util::add_query_arg( 'c', 'd', 'a=b' ) );
|
||||
|
||||
// Url encoding test
|
||||
$this->assertEquals( '/app/admin/users?param=containsa%26sym', util::add_query_arg( 'param', 'containsa&sym', '/app/admin/users' ) );
|
||||
|
||||
// If not provided, grab the URI from the server.
|
||||
$_SERVER['REQUEST_URI'] = '/app/admin/users';
|
||||
$this->assertEquals( '/app/admin/users?user=6', util::add_query_arg( array( 'user' => 6 ) ) );
|
||||
$this->assertEquals( '/app/admin/users?user=7', util::add_query_arg( 'user', 7 ) );
|
||||
}
|
||||
|
||||
public function test_remove_query_arg()
|
||||
{
|
||||
$this->assertEquals( '/app/admin/users', util::remove_query_arg( 'user', '/app/admin/users?user=5' ) );
|
||||
$this->assertEquals( '/app/admin/users?action=edit', util::remove_query_arg( 'user', '/app/admin/users?action=edit&user=5' ) );
|
||||
$this->assertEquals( '/app/admin/users?user=5', util::remove_query_arg( array( 'tab', 'action' ), '/app/admin/users?action=edit&tab=personal&user=5' ) );
|
||||
}
|
||||
|
||||
public function test_http_build_url()
|
||||
{
|
||||
$url = 'http://user:pass@example.com:8080/path/?query#fragment';
|
||||
|
||||
$expected = 'http://example.com/';
|
||||
$actual = util::http_build_url($url, array(), util::HTTP_URL_STRIP_ALL);
|
||||
$this->assertEquals($expected, $actual);
|
||||
|
||||
$expected = 'http://example.com:8080/path/?query#fragment';
|
||||
$actual = util::http_build_url($url, array(), util::HTTP_URL_STRIP_AUTH);
|
||||
$this->assertEquals($expected, $actual);
|
||||
|
||||
$this->assertEquals('https://dev.example.com/', util::http_build_url('http://example.com/', array('scheme' => 'https', 'host' => 'dev.example.com')));
|
||||
$this->assertEquals('http://example.com/#hi', util::http_build_url('http://example.com/', array('fragment' => 'hi'), util::HTTP_URL_REPLACE));
|
||||
$this->assertEquals('http://example.com/page', util::http_build_url('http://example.com/', array('path' => 'page'), util::HTTP_URL_JOIN_PATH));
|
||||
$this->assertEquals('http://example.com/page', util::http_build_url('http://example.com', array('path' => 'page'), util::HTTP_URL_JOIN_PATH));
|
||||
$this->assertEquals('http://example.com/?hi=Bro', util::http_build_url('http://example.com/', array('query' => 'hi=Bro'), util::HTTP_URL_JOIN_QUERY));
|
||||
$this->assertEquals('http://example.com/?show=1&hi=Bro', util::http_build_url('http://example.com/?show=1', array('query' => 'hi=Bro'), util::HTTP_URL_JOIN_QUERY));
|
||||
|
||||
$this->assertEquals('http://admin@example.com/', util::http_build_url('http://example.com/', array('user' => 'admin')));
|
||||
$this->assertEquals('http://admin:1@example.com/', util::http_build_url('http://example.com/', array('user' => 'admin', 'pass' => '1')));
|
||||
}
|
||||
|
||||
public function test_str_to_bool()
|
||||
{
|
||||
$this->assertTrue( util::str_to_bool( 'true' ) );
|
||||
$this->assertTrue( util::str_to_bool( 'yes' ) );
|
||||
$this->assertTrue( util::str_to_bool( 'y' ) );
|
||||
$this->assertTrue( util::str_to_bool( 'oui' ) );
|
||||
$this->assertTrue( util::str_to_bool( 'vrai' ) );
|
||||
|
||||
$this->assertFalse( util::str_to_bool( 'false' ) );
|
||||
$this->assertFalse( util::str_to_bool( 'no' ) );
|
||||
$this->assertFalse( util::str_to_bool( 'n' ) );
|
||||
$this->assertFalse( util::str_to_bool( 'non' ) );
|
||||
$this->assertFalse( util::str_to_bool( 'faux' ) );
|
||||
|
||||
$this->assertFalse( util::str_to_bool( 'test' , false) );
|
||||
|
||||
}
|
||||
|
||||
public function test_array_pluck()
|
||||
{
|
||||
$array = array(
|
||||
array(
|
||||
'name' => 'Bob',
|
||||
'age' => 37
|
||||
),
|
||||
array(
|
||||
'name' => 'Fred',
|
||||
'age' => 37
|
||||
),
|
||||
array(
|
||||
'name' => 'Jane',
|
||||
'age' => 29
|
||||
),
|
||||
array(
|
||||
'name' => 'Brandon',
|
||||
'age' => 20
|
||||
),
|
||||
array(
|
||||
'age' => 41
|
||||
)
|
||||
);
|
||||
|
||||
$obj_array = array(
|
||||
'bob' => (object) array(
|
||||
'name' => 'Bob',
|
||||
'age' => 37
|
||||
),
|
||||
'fred' => (object) array(
|
||||
'name' => 'Fred',
|
||||
'age' => 37
|
||||
),
|
||||
'jane' => (object) array(
|
||||
'name' => 'Jane',
|
||||
'age' => 29
|
||||
),
|
||||
'brandon' => (object) array(
|
||||
'name' => 'Brandon',
|
||||
'age' => 20
|
||||
),
|
||||
'invalid' => (object) array(
|
||||
'age' => 41
|
||||
)
|
||||
);
|
||||
|
||||
$obj_array_expect = array(
|
||||
'bob' => 'Bob',
|
||||
'fred' => 'Fred',
|
||||
'jane' => 'Jane',
|
||||
'brandon' => 'Brandon'
|
||||
);
|
||||
|
||||
$this->assertEquals( array( 'Bob', 'Fred', 'Jane', 'Brandon' ), util::array_pluck( $array, 'name' ) );
|
||||
$this->assertEquals( array( 'Bob', 'Fred', 'Jane', 'Brandon', array( 'age' => 41 ) ), util::array_pluck( $array, 'name', TRUE, FALSE ) );
|
||||
$this->assertEquals( $obj_array_expect, util::array_pluck( $obj_array, 'name' ) );
|
||||
$this->assertEquals( array( 'Bob', 'Fred', 'Jane', 'Brandon' ), util::array_pluck( $obj_array, 'name', FALSE ) );
|
||||
|
||||
$expected = array('Bob', 'Fred', 'Jane', 'Brandon', 'invalid' => (object)array('age' => 41));
|
||||
$this->assertEquals($expected, util::array_pluck($obj_array, 'name', FALSE, FALSE));
|
||||
$expected = array('Bob', 'Fred', 'Jane', 'Brandon', array('age' => 41));
|
||||
$this->assertEquals($expected, util::array_pluck($array, 'name', false, false));
|
||||
}
|
||||
|
||||
public function test_htmlentities()
|
||||
{
|
||||
$this->assertEquals( 'One & Two', util::htmlentities( 'One & Two' ) );
|
||||
$this->assertEquals( 'One & Two', util::htmlentities( 'One & Two', TRUE ) );
|
||||
}
|
||||
|
||||
public function test_htmlspecialchars()
|
||||
{
|
||||
$this->assertEquals( 'One & Two', util::htmlspecialchars( 'One & Two' ) );
|
||||
$this->assertEquals( 'One & Two', util::htmlspecialchars( 'One & Two', TRUE ) );
|
||||
}
|
||||
|
||||
public function test_remove_accents()
|
||||
{
|
||||
$this->assertEquals( 'A', util::remove_accents( "\xC3\x81" ) );
|
||||
$this->assertEquals( 'e', util::remove_accents( "\xC4\x97" ) );
|
||||
$this->assertEquals( 'U', util::remove_accents( "\xC3\x9C" ) );
|
||||
$this->assertEquals( 'Ae', util::remove_accents( "Ä", 'de' ) );
|
||||
$this->assertEquals( 'OEoeAEDHTHssaedhth', util::remove_accents(chr(140) . chr(156) . chr(198) . chr(208) . chr(222) . chr(223) . chr(230) . chr(240) . chr(254)));
|
||||
}
|
||||
|
||||
public function test_zero_pad()
|
||||
{
|
||||
$this->assertEquals( '00000341', util::zero_pad( 341, 8 ) );
|
||||
$this->assertEquals( '341', util::zero_pad( 341, 1 ) );
|
||||
}
|
||||
|
||||
public function test_human_time_diff()
|
||||
{
|
||||
$this->assertEquals( '1 second ago', util::human_time_diff( time() - 1 ) );
|
||||
$this->assertEquals( '30 seconds ago', util::human_time_diff( time() - 30 ) );
|
||||
$this->assertEquals( '1 minute ago', util::human_time_diff( time() - ( util::SECONDS_IN_A_MINUTE * 1.4 ) ) );
|
||||
$this->assertEquals( '5 minutes ago', util::human_time_diff( time() - ( util::SECONDS_IN_A_MINUTE * 5 ) ) );
|
||||
$this->assertEquals( '1 hour ago', util::human_time_diff( time() - ( util::SECONDS_IN_AN_HOUR ) ) );
|
||||
$this->assertEquals( '2 hours ago', util::human_time_diff( time() - ( util::SECONDS_IN_AN_HOUR * 2 ) ) );
|
||||
$this->assertEquals( '1 day ago', util::human_time_diff( time() - ( util::SECONDS_IN_AN_HOUR * 24 ) ) );
|
||||
$this->assertEquals( '5 days ago', util::human_time_diff( time() - ( util::SECONDS_IN_AN_HOUR * 24 * 5 ) ) );
|
||||
$this->assertEquals( '1 week ago', util::human_time_diff( time() - ( util::SECONDS_IN_AN_HOUR * 24 * 7 ) ) );
|
||||
$this->assertEquals( '2 weeks ago', util::human_time_diff( time() - ( util::SECONDS_IN_AN_HOUR * 24 * 14 ) ) );
|
||||
$this->assertEquals( '1 month ago', util::human_time_diff( time() - ( util::SECONDS_IN_A_WEEK * 5 ) ) );
|
||||
$this->assertEquals( '2 months ago', util::human_time_diff( time() - ( util::SECONDS_IN_A_WEEK * 10 ) ) );
|
||||
$this->assertEquals( '1 year ago', util::human_time_diff( time() - ( util::SECONDS_IN_A_MONTH * 15 ) ) );
|
||||
$this->assertEquals( '2 years ago', util::human_time_diff( time() - ( util::SECONDS_IN_A_MONTH * 36 ) ) );
|
||||
$this->assertEquals( '11 years ago', util::human_time_diff( time() - ( util::SECONDS_IN_A_MONTH * 140 ) ) );
|
||||
|
||||
$this->assertEquals( 'fifteen minutes ago', util::human_time_diff( time() - ( util::SECONDS_IN_A_MINUTE * 15 ), '', TRUE ) );
|
||||
}
|
||||
|
||||
public function test_number_to_word()
|
||||
{
|
||||
try {
|
||||
util::number_to_word('junk data');
|
||||
$this->fail('Accepted junk data');
|
||||
} catch(\LogicException $e) {
|
||||
$this->assertEquals('Not a number', $e->getMessage());
|
||||
}
|
||||
|
||||
// Partially numeric.
|
||||
$this->assertEquals('', util::number_to_word('1a'));
|
||||
|
||||
// Decimals
|
||||
$this->assertEquals( 'five point zero five', util::number_to_word('5.05') );
|
||||
$this->assertEquals( 'zero point eight', util::number_to_word( 0.8 ) );
|
||||
|
||||
// Integers
|
||||
$this->assertEquals( 'positive one', util::number_to_word( '+1' ) );
|
||||
$this->assertEquals( 'negative twelve', util::number_to_word( -12 ) );
|
||||
$this->assertEquals( 'one', util::number_to_word( 1 ) );
|
||||
$this->assertEquals( 'five', util::number_to_word( 5 ) );
|
||||
$this->assertEquals( 'fifteen', util::number_to_word( 15 ) );
|
||||
$this->assertEquals( 'twenty-one', util::number_to_word( 21 ) );
|
||||
$this->assertEquals( 'thirty-two', util::number_to_word( 32 ) );
|
||||
$this->assertEquals( 'forty-three', util::number_to_word( 43 ) );
|
||||
$this->assertEquals( 'fifty-four', util::number_to_word( 54 ) );
|
||||
$this->assertEquals( 'sixty-six', util::number_to_word( 66 ) );
|
||||
$this->assertEquals( 'seventy-seven', util::number_to_word( 77 ) );
|
||||
$this->assertEquals( 'eighty-eight', util::number_to_word( 88 ) );
|
||||
$this->assertEquals( 'ninety-nine', util::number_to_word( 99 ) );
|
||||
$this->assertEquals( 'one hundred and thirty-six', util::number_to_word( 136 ) );
|
||||
$this->assertEquals( 'ten', util::number_to_word( 10 ) );
|
||||
$this->assertEquals( 'twenty', util::number_to_word( 20 ) );
|
||||
$this->assertEquals( 'thirty', util::number_to_word( 30 ) );
|
||||
$this->assertEquals( 'forty', util::number_to_word( 40 ) );
|
||||
$this->assertEquals( 'fifty', util::number_to_word( 50 ) );
|
||||
$this->assertEquals( 'sixty', util::number_to_word( 60 ) );
|
||||
$this->assertEquals( 'seventy', util::number_to_word( 70 ) );
|
||||
$this->assertEquals( 'eighty', util::number_to_word( 80 ) );
|
||||
$this->assertEquals( 'ninety', util::number_to_word( 90 ) );
|
||||
$this->assertEquals( 'eleven', util::number_to_word( 11 ) );
|
||||
$this->assertEquals( 'thirteen', util::number_to_word( 13 ) );
|
||||
$this->assertEquals( 'fourteen', util::number_to_word( 14 ) );
|
||||
$this->assertEquals( 'fifteen', util::number_to_word( 15 ) );
|
||||
$this->assertEquals( 'sixteen', util::number_to_word( 16 ) );
|
||||
$this->assertEquals( 'seventeen', util::number_to_word( 17 ) );
|
||||
$this->assertEquals( 'eighteen', util::number_to_word( 18 ) );
|
||||
$this->assertEquals( 'nineteen', util::number_to_word( 19 ) );
|
||||
$this->assertEquals( 'one thousand', util::number_to_word( 1000 ) );
|
||||
$this->assertEquals( 'one million', util::number_to_word( 1000000 ) );
|
||||
$this->assertEquals( 'one billion', util::number_to_word( 1000000000 ) );
|
||||
$this->assertEquals( 'one trillion', util::number_to_word( 1000000000000 ) );
|
||||
$this->assertEquals( 'one quadrillion', util::number_to_word( '1000000000000000' ) );
|
||||
$this->assertEquals( 'one quintrillion', util::number_to_word( '1000000000000000000' ) );
|
||||
$this->assertEquals( 'one sextillion', util::number_to_word( '1000000000000000000000' ) );
|
||||
$this->assertEquals( 'one septillion', util::number_to_word( '1000000000000000000000000' ) );
|
||||
$this->assertEquals( 'one octillion', util::number_to_word( '1000000000000000000000000000' ) );
|
||||
$this->assertEquals( 'one nonillion', util::number_to_word( '1000000000000000000000000000000' ) );
|
||||
$this->assertEquals( 'one decillion', util::number_to_word( '1000000000000000000000000000000000' ) );
|
||||
$this->assertEquals( 'one', util::number_to_word( '1000000000000000000000000000000000000000000' ) );
|
||||
|
||||
}
|
||||
|
||||
public function test_array_search_deep()
|
||||
{
|
||||
$users = array(
|
||||
1 => (object) array( 'username' => 'brandon', 'age' => 20 ),
|
||||
2 => (object) array( 'username' => 'matt', 'age' => 27 ),
|
||||
3 => (object) array( 'username' => 'jane', 'age' => 53 ),
|
||||
4 => (object) array( 'username' => 'john', 'age' => 41 ),
|
||||
5 => (object) array( 'username' => 'steve', 'age' => 11 ),
|
||||
6 => (object) array( 'username' => 'fred', 'age' => 42 ),
|
||||
7 => (object) array( 'username' => 'rasmus', 'age' => 21 ),
|
||||
8 => (object) array( 'username' => 'don', 'age' => 15 ),
|
||||
9 => array( 'username' => 'darcy', 'age' => 33 ),
|
||||
);
|
||||
|
||||
$test = array(
|
||||
1 => 'brandon',
|
||||
2 => 'devon',
|
||||
3 => array( 'troy' ),
|
||||
4 => 'annie'
|
||||
);
|
||||
|
||||
$this->assertFalse( util::array_search_deep( $test, 'bob' ) );
|
||||
$this->assertEquals( 3, util::array_search_deep( $test, 'troy' ) );
|
||||
$this->assertEquals( 4, util::array_search_deep( $test, 'annie' ) );
|
||||
$this->assertEquals( 2, util::array_search_deep( $test, 'devon', 'devon' ) );
|
||||
$this->assertEquals( 7, util::array_search_deep( $users, 'rasmus', 'username' ) );
|
||||
$this->assertEquals( 9, util::array_search_deep( $users, 'darcy', 'username' ) );
|
||||
$this->assertEquals( 1, util::array_search_deep( $users, 'brandon' ) );
|
||||
}
|
||||
|
||||
public function test_array_map_deep()
|
||||
{
|
||||
$input = array(
|
||||
'<',
|
||||
'abc',
|
||||
'>',
|
||||
'def',
|
||||
array( '&', 'test', '123' ),
|
||||
(object) array( 'hey', '<>' )
|
||||
);
|
||||
|
||||
$expect = array(
|
||||
'<',
|
||||
'abc',
|
||||
'>',
|
||||
'def',
|
||||
array( '&', 'test', '123' ),
|
||||
(object) array( 'hey', '<>' )
|
||||
);
|
||||
|
||||
$this->assertEquals( $expect, util::array_map_deep( $input, 'htmlentities' ) );
|
||||
}
|
||||
|
||||
public function test_random_string()
|
||||
{
|
||||
// Make sure the generated string contains only human friendly characters and is 30 characters long
|
||||
$str = util::random_string( 30 );
|
||||
$this->assertTrue( (bool) preg_match( '/^([ABCDEFGHJKLMNPQRSTUVWXYZabcdefhjkmnprstuvwxyz23456789]{30})$/', $str ) );
|
||||
|
||||
// Make sure the generated string is 30 characters long
|
||||
$str = util::random_string( 30, false, true );
|
||||
$this->assertTrue( strlen( $str ) === 30, 'random_string produced an invalid length string' );
|
||||
|
||||
// Make sure the generated string is 120 characters long
|
||||
$str = util::random_string( 120 );
|
||||
$this->assertTrue(strlen( $str ) === 120, 'random_string produced an invalid length string');
|
||||
|
||||
// Make sure the string doesn't contain duplicate letters
|
||||
$str = util::random_string( 53, true, false, true );
|
||||
$this->assertTrue(strlen($str) === 53, 'random_string produced an invalid length string');
|
||||
$this->assertTrue(count(array_unique(str_split($str))) === strlen($str), 'random_string produced a string with duplicate characters');
|
||||
|
||||
// Longer length than characters available
|
||||
try {
|
||||
$str = util::random_string( 55, true, false, true );
|
||||
$this->assertTrue( false );
|
||||
} catch (Exception $e) {
|
||||
$this->assertTrue( true );
|
||||
}
|
||||
|
||||
// Test secure variant
|
||||
$str = util::secure_random_string(16);
|
||||
$this->assertTrue(strlen($str) === 16);
|
||||
|
||||
// Longer length than characters available
|
||||
try {
|
||||
$str = util::secure_random_string(0);
|
||||
$this->assertTrue(false);
|
||||
} catch (Exception $e) {
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
public function test_match_string()
|
||||
{
|
||||
$this->assertTrue( util::match_string('a', 'a') );
|
||||
$this->assertFalse( util::match_string('a', ' a') );
|
||||
$this->assertFalse( util::match_string('/', '/something') );
|
||||
$this->assertTrue( util::match_string('test/*', 'test/first/second') );
|
||||
$this->assertTrue( util::match_string('*/test', 'first/second/test') );
|
||||
$this->assertFalse( util::match_string('first/', 'first/second/test') );
|
||||
$this->assertFalse( util::match_string('test', 'TEST') );
|
||||
$this->assertTrue( util::match_string('test', 'TEST', false) );
|
||||
}
|
||||
|
||||
public function test_validate_email()
|
||||
{
|
||||
$this->assertTrue( util::validate_email( 'john.smith@gmail.com' ) );
|
||||
$this->assertTrue( util::validate_email( 'john.smith+label@gmail.com' ) );
|
||||
$this->assertTrue( util::validate_email( 'john.smith@gmail.co.uk' ) );
|
||||
}
|
||||
|
||||
public function test_safe_truncate()
|
||||
{
|
||||
$this->assertEquals( 'The quick brown fox...', util::safe_truncate( 'The quick brown fox jumps over the lazy dog', 24 ) );
|
||||
$this->assertEquals( 'The quick brown fox jumps over the lazy dog', util::safe_truncate( 'The quick brown fox jumps over the lazy dog', 55 ) );
|
||||
$this->assertEquals( 'Th...', util::safe_truncate( 'The quick brown fox jumps over the lazy dog', 2 ) );
|
||||
$this->assertEquals( 'The...', util::safe_truncate( 'The quick brown fox jumps over the lazy dog', 3 ) );
|
||||
$this->assertEquals( 'The...', util::safe_truncate( 'The quick brown fox jumps over the lazy dog', 7 ) );
|
||||
}
|
||||
|
||||
public function test_limit_characters()
|
||||
{
|
||||
$this->assertEquals( 'The quick brown fox jump...', util::limit_characters( 'The quick brown fox jumps over the lazy dog', 24 ) );
|
||||
$this->assertEquals( 'The quick brown fox jumps over the lazy dog', util::limit_characters( 'The quick brown fox jumps over the lazy dog', 55 ) );
|
||||
$this->assertEquals( 'Th...', util::limit_characters( 'The quick brown fox jumps over the lazy dog', 2 ) );
|
||||
$this->assertEquals( 'The...', util::limit_characters( 'The quick brown fox jumps over the lazy dog', 3 ) );
|
||||
$this->assertEquals( 'The qui...', util::limit_characters( 'The quick brown fox jumps over the lazy dog', 7 ) );
|
||||
$this->assertEquals( 'The quick brown fox jumps over the lazy dog', util::limit_characters( 'The quick brown fox jumps over the lazy dog', 150 ) );
|
||||
}
|
||||
|
||||
public function test_limit_words()
|
||||
{
|
||||
$this->assertEquals( 'The quick brown...', util::limit_words( 'The quick brown fox jumps over the lazy dog', 3 ) );
|
||||
$this->assertEquals( 'The quick brown fox jumps...', util::limit_words( 'The quick brown fox jumps over the lazy dog', 5 ) );
|
||||
$this->assertEquals( 'The...', util::limit_words( 'The quick brown fox jumps over the lazy dog', 1 ) );
|
||||
$this->assertEquals( 'The quick brown fox jumps over the lazy dog', util::limit_words( 'The quick brown fox jumps over the lazy dog', 90 ) );
|
||||
$this->assertEquals( 'The quick brown fox jumps over the...', util::limit_words( 'The quick brown fox jumps over the lazy dog', 7 ) );
|
||||
}
|
||||
|
||||
public function test_ordinal()
|
||||
{
|
||||
$this->assertEquals( '1st', util::ordinal( 1 ) );
|
||||
$this->assertEquals( '2nd', util::ordinal( 2 ) );
|
||||
$this->assertEquals( '3rd', util::ordinal( 3 ) );
|
||||
$this->assertEquals( '4th', util::ordinal( 4 ) );
|
||||
$this->assertEquals( '5th', util::ordinal( 5 ) );
|
||||
$this->assertEquals( '6th', util::ordinal( 6 ) );
|
||||
$this->assertEquals( '7th', util::ordinal( 7 ) );
|
||||
$this->assertEquals( '8th', util::ordinal( 8 ) );
|
||||
$this->assertEquals( '9th', util::ordinal( 9 ) );
|
||||
$this->assertEquals( '22nd', util::ordinal( 22 ) );
|
||||
$this->assertEquals( '23rd', util::ordinal( 23 ) );
|
||||
$this->assertEquals( '143rd', util::ordinal( 143 ) );
|
||||
}
|
||||
|
||||
public function test_array_first()
|
||||
{
|
||||
$test = array( 'a' => array( 'a', 'b', 'c' ) );
|
||||
|
||||
$this->assertEquals( 'a', util::array_first( util::array_get( $test['a'] ) ) );
|
||||
}
|
||||
|
||||
public function test_array_first_key()
|
||||
{
|
||||
$test = array( 'a' => array( 'a' => 'b', 'c' => 'd' ) );
|
||||
|
||||
$this->assertEquals( 'a', util::array_first_key( util::array_get( $test['a'] ) ) );
|
||||
}
|
||||
|
||||
public function test_array_last()
|
||||
{
|
||||
$test = array( 'a' => array( 'a', 'b', 'c' ) );
|
||||
|
||||
$this->assertEquals( 'c', util::array_last( util::array_get( $test['a'] ) ) );
|
||||
}
|
||||
|
||||
public function test_array_last_key()
|
||||
{
|
||||
$test = array( 'a' => array( 'a' => 'b', 'c' => 'd' ) );
|
||||
|
||||
$this->assertEquals( 'c', util::array_last_key( util::array_get( $test['a'] ) ) );
|
||||
}
|
||||
|
||||
public function test_array_flatten()
|
||||
{
|
||||
$input = array( 'a', 'b', 'c', 'd', array( 'first' => 'e', 'f', 'second' => 'g', array( 'h', 'third' => 'i', array( array( array( array( 'j', 'k', 'l' ) ) ) ) ) ) );
|
||||
$expectNoKeys = range( 'a', 'l' );
|
||||
$expectWithKeys = array(
|
||||
'a', 'b', 'c', 'd',
|
||||
'first' => 'e',
|
||||
'f',
|
||||
'second' => 'g',
|
||||
'h',
|
||||
'third' => 'i',
|
||||
'j', 'k', 'l'
|
||||
);
|
||||
|
||||
$this->assertEquals( $expectWithKeys, util::array_flatten( $input ) );
|
||||
$this->assertEquals( $expectNoKeys, util::array_flatten( $input, false ) );
|
||||
$this->assertEquals( $expectWithKeys, util::array_flatten( $input, true ) );
|
||||
}
|
||||
|
||||
public function test_strip_space()
|
||||
{
|
||||
$input = ' The quick brown fox jumps over the lazy dog ';
|
||||
$expect = 'Thequickbrownfoxjumpsoverthelazydog';
|
||||
|
||||
$this->assertEquals($expect, Util::strip_space($input));
|
||||
}
|
||||
|
||||
public function test_sanitize_string()
|
||||
{
|
||||
$input = ' Benoit! à New-York? j’ai perçu 1 % : Qu’as-tu "gagné" chez M. V. Noël? Dix francs.';
|
||||
$expect = 'benoitanewyorkjaipercu1quastugagnechezmvnoeldixfrancs';
|
||||
|
||||
$this->assertEquals($expect, Util::sanitize_string($input));
|
||||
}
|
||||
|
||||
public function test_get_gravatar()
|
||||
{
|
||||
$_SERVER['HTTPS'] = 'on';
|
||||
$this->assertEquals('https://secure.gravatar.com/avatar/a4bf5bbb9feaa2713d99a3b52ab80024?s=32', util::get_gravatar('john.doe@example.org'));
|
||||
$this->assertEquals('https://secure.gravatar.com/avatar/a4bf5bbb9feaa2713d99a3b52ab80024?s=128', util::get_gravatar('john.doe@example.org', 128));
|
||||
|
||||
$_SERVER['HTTPS'] = 'off';
|
||||
$this->assertEquals('http://www.gravatar.com/avatar/a4bf5bbb9feaa2713d99a3b52ab80024?s=32', util::get_gravatar('john.doe@example.org'));
|
||||
$this->assertEquals('http://www.gravatar.com/avatar/a4bf5bbb9feaa2713d99a3b52ab80024?s=128', util::get_gravatar('john.doe@example.org', 128));
|
||||
}
|
||||
|
||||
public function test_get_client_ip()
|
||||
{
|
||||
$_SERVER['REMOTE_ADDR'] = '192.168.30.152';
|
||||
$_SERVER['HTTP_CLIENT_IP'] = '192.168.30.153';
|
||||
$_SERVER['HTTP_X_FORWARDED_FOR'] = '192.168.30.154';
|
||||
$this->assertEquals('192.168.30.152', util::get_client_ip());
|
||||
$this->assertEquals('192.168.30.153', util::get_client_ip(true));
|
||||
|
||||
unset($_SERVER['HTTP_CLIENT_IP']);
|
||||
$this->assertEquals('192.168.30.154', util::get_client_ip(true));
|
||||
unset($_SERVER['HTTP_X_FORWARDED_FOR']);
|
||||
$this->assertEquals('192.168.30.152', util::get_client_ip(true));
|
||||
}
|
||||
|
||||
public function test_full_permissions()
|
||||
{
|
||||
// Text a non-existant file.
|
||||
$this->assertFalse(util::full_permissions('faker-123.blah'), 'Gave a permission value for a non-existant file.');
|
||||
|
||||
// Test an existing file.
|
||||
$expected = '-rw-rw-rw-';
|
||||
$tempFile = tempnam(sys_get_temp_dir(), 'foo');
|
||||
$this->assertTrue(chmod($tempFile, 0666), 'Oops. Could not change temp file\'s permissions to 0666.');
|
||||
$this->assertEquals($expected, util::full_permissions($tempFile), 'Could not properly obtain permissions of an existing file.');
|
||||
unlink($tempFile);
|
||||
|
||||
$this->assertEquals('lr--r--r--', util::full_permissions('fake-file-222', octdec('120444')));
|
||||
$this->assertEquals('ur--r--r--', util::full_permissions('fake-file-222', octdec('000444')));
|
||||
$this->assertEquals('srwxr-xr-x', util::full_permissions('fake-file-222', octdec('140755')));
|
||||
$this->assertEquals('drwxr-xr-x', util::full_permissions('fake-file-222', octdec('40755')));
|
||||
$this->assertEquals('brw-rw----', util::full_permissions('fake-file-222', octdec('60660')));
|
||||
$this->assertEquals('crw-rw----', util::full_permissions('fake-file-222', octdec('20660')));
|
||||
$this->assertEquals('prw-rw----', util::full_permissions('fake-file-222', octdec('10660')));
|
||||
$this->assertEquals('---x------', util::full_permissions('fake-file-222', octdec('100100')));
|
||||
$this->assertEquals('--w-------', util::full_permissions('fake-file-222', octdec('100200')));
|
||||
$this->assertEquals('--wx------', util::full_permissions('fake-file-222', octdec('100300')));
|
||||
$this->assertEquals('-r--------', util::full_permissions('fake-file-222', octdec('100400')));
|
||||
$this->assertEquals('-r-x------', util::full_permissions('fake-file-222', octdec('100500')));
|
||||
$this->assertEquals('-rw-------', util::full_permissions('fake-file-222', octdec('100600')));
|
||||
$this->assertEquals('-rwx------', util::full_permissions('fake-file-222', octdec('100700')));
|
||||
|
||||
// Windows does not have the concept of /.
|
||||
if (!defined('PHP_WINDOWS_VERSION_MAJOR')) {
|
||||
$this->assertEquals('drwxr-xr-x', util::full_permissions('/'));
|
||||
}
|
||||
}
|
||||
|
||||
public function test_array_clean()
|
||||
{
|
||||
$input = array( 'a', 'b', '', null, false, 0);
|
||||
$expect = array('a', 'b');
|
||||
$this->assertEquals($expect, Util::array_clean($input));
|
||||
}
|
||||
|
||||
public function test_var_dump_plain()
|
||||
{
|
||||
$input = 'var';
|
||||
$expect = '<span style="color:#588bff;">string</span><span style="color:#999;">(</span>3<span style="color:#999;">)</span> <strong>"var"</strong>';
|
||||
$this->assertEquals($expect, Util::var_dump_plain($input, true));
|
||||
|
||||
$input = true;
|
||||
$expect = '<span style="color:#588bff;">bool</span><span style="color:#999;">(</span><strong>true</strong><span style="color:#999;">)</span>';
|
||||
$this->assertEquals($expect, Util::var_dump_plain($input, true));
|
||||
|
||||
$input = 1;
|
||||
$expect = '<span style="color:#588bff;">int</span><span style="color:#999;">(</span><strong>1</strong><span style="color:#999;">)</span>';
|
||||
$this->assertEquals($expect, Util::var_dump_plain($input, true));
|
||||
|
||||
$input = 1.5;
|
||||
$expect = '<span style="color:#588bff;">float</span><span style="color:#999;">(</span><strong>1.5</strong><span style="color:#999;">)</span>';
|
||||
$this->assertEquals($expect, Util::var_dump_plain($input, true));
|
||||
|
||||
$input = null;
|
||||
$expect = '<strong>NULL</strong>';
|
||||
$this->assertEquals($expect, Util::var_dump_plain($input, true));
|
||||
|
||||
$input = fopen('php://memory', 'r');
|
||||
$expect = '<span style="color:#588bff;">resource</span>("stream") <strong>"' . $input . '"</strong>';
|
||||
$this->assertEquals($expect, Util::var_dump_plain($input, -1));
|
||||
fclose($input);
|
||||
|
||||
// Test complex arrays.
|
||||
$input = array(1, 2, 4, 6, 10 => 20, 100 => 200);
|
||||
$actual = util::var_dump_plain($input, true);
|
||||
$this->assertContains('<img id="include-php-', $actual);
|
||||
$this->assertContains('<br /> 100 => <span', $actual);
|
||||
$this->assertContains('(</span><strong>200</strong><span style="color:#999;">)', $actual);
|
||||
|
||||
// Test complex objects.
|
||||
$experiment = new VarDumpExperiment();
|
||||
$actual = util::var_dump_plain($experiment, true);
|
||||
$this->assertContains('1 => <span style="color:#588bff;">string</span><span style="color:#999;">(</span>1<span style="color:#999;">', $actual);
|
||||
}
|
||||
|
||||
public function test_var_dump()
|
||||
{
|
||||
$input = 'var';
|
||||
$expect = '<pre style="margin-bottom: 18px;background: #f7f7f9;border: 1px solid #e1e1e8;padding: 8px;border-radius: 4px;-moz-border-radius: 4px;-webkit-border radius: 4px;display: block;font-size: 12.05px;white-space: pre-wrap;word-wrap: break-word;color: #333;font-family: Menlo,Monaco,Consolas,\'Courier New\',monospace;"><span style="color:#588bff;">string</span><span style="color:#999;">(</span>3<span style="color:#999;">)</span> <strong>"var"</strong></pre>';
|
||||
|
||||
// Ensure the proper output is returned
|
||||
$this->assertEquals($expect, Util::var_dump($input, true));
|
||||
|
||||
// Ensure the proper output is actually outputted
|
||||
$this->expectOutputString($expect);
|
||||
util::var_dump($input);
|
||||
|
||||
// Ensure we avoid infinite recursion on recursive arrays
|
||||
$a = array('a' => 'value a', 'b' => 'value b');
|
||||
$b = array('test' => &$a);
|
||||
$c = array('a' => &$a, 'b' => &$b);
|
||||
$a['c'] = &$c;
|
||||
$b['c'] = &$c;
|
||||
$this->assertContains('*RECURSION DETECTED*', Util::var_dump($c, true));
|
||||
|
||||
// Ensure we avoid infinite recursion on recursive objects
|
||||
$a = (object) array('a' => 'value a', 'b' => 'value b');
|
||||
$b = (object) array('test' => &$a);
|
||||
$c = (object) array('a' => &$a, 'b' => &$b);
|
||||
$a->c = &$c;
|
||||
$b->c = &$c;
|
||||
$this->assertContains('*RECURSION DETECTED*', Util::var_dump($c, true));
|
||||
|
||||
// Test class scoping.
|
||||
$experiment = new VarDumpExperiment();
|
||||
$actual = util::var_dump($experiment, true);
|
||||
|
||||
$snippet = substr($actual, strrpos($actual, 'display:inline'));
|
||||
$this->assertContains('"public"', $snippet);
|
||||
$this->assertContains('"protected:protected"', $snippet);
|
||||
$this->assertContains('"private:VarDumpExperiment:private"', $actual);
|
||||
}
|
||||
|
||||
public function test_linkify()
|
||||
{
|
||||
$input = 'great websites: http://www.google.com?param=test and http://yahoo.com/a/nested/folder';
|
||||
$expect = 'great websites: <a href="http://www.google.com?param=test">http://www.google.com?param=test</a> and <a href="http://yahoo.com/a/nested/folder">http://yahoo.com/a/nested/folder</a>';
|
||||
$this->assertEquals($expect, Util::linkify($input));
|
||||
|
||||
$this->assertEquals($expect, util::linkify($expect), 'linkify() tried to double linkify an href.');
|
||||
}
|
||||
|
||||
public function test_start_with()
|
||||
{
|
||||
$this->assertTrue(Util::starts_with('start a string', 'start a'));
|
||||
$this->assertFalse(Util::starts_with('start a string', 'string'));
|
||||
}
|
||||
|
||||
public function test_end_with()
|
||||
{
|
||||
$this->assertTrue(Util::ends_with('start a string', 'a string'));
|
||||
$this->assertFalse(Util::ends_with('start a string', 'start'));
|
||||
}
|
||||
|
||||
public function test_contains()
|
||||
{
|
||||
$this->assertTrue(Util::str_contains('start a string', 'a string'));
|
||||
$this->assertFalse(Util::str_contains('start a string', 'Start'));
|
||||
}
|
||||
|
||||
public function test_iContains()
|
||||
{
|
||||
$this->assertTrue(Util::str_icontains('start a string', 'a string'));
|
||||
$this->assertTrue(Util::str_icontains('start a string', 'Start'));
|
||||
}
|
||||
|
||||
public function test_get_file_ext()
|
||||
{
|
||||
$input = 'a_pdf_fil.pdf';
|
||||
$expect = 'pdf';
|
||||
$this->assertEquals($expect, Util::get_file_ext($input));
|
||||
}
|
||||
|
||||
public function test_rmdir()
|
||||
{
|
||||
$dirname = dirname(__FILE__);
|
||||
|
||||
// Test deleting a non-existant directory
|
||||
$this->assertFalse(file_exists($dirname . '/test1'));
|
||||
$this->assertTrue(util::rmdir($dirname . '/test1'));
|
||||
|
||||
// Test deleting an empty directory
|
||||
$dir = $dirname . '/test2';
|
||||
mkdir($dir);
|
||||
|
||||
$this->assertTrue(is_dir($dir));
|
||||
|
||||
if (is_dir($dir)) {
|
||||
util::rmdir($dir);
|
||||
$this->assertFalse(is_dir($dir));
|
||||
}
|
||||
|
||||
// Test deleting a non-empty directory
|
||||
$dir = $dirname . '/test3';
|
||||
$file = $dirname . '/test3/test.txt';
|
||||
mkdir($dir);
|
||||
touch($file);
|
||||
|
||||
$this->assertTrue(is_dir($dir));
|
||||
$this->assertTrue(is_file($file));
|
||||
|
||||
if (is_dir($dir)) {
|
||||
util::rmdir($dir);
|
||||
$this->assertFalse(is_dir($dir));
|
||||
$this->assertFalse(is_file($file));
|
||||
}
|
||||
|
||||
// Test deleting a non-directory path
|
||||
$file = $dirname . '/test4.txt';
|
||||
touch($file);
|
||||
|
||||
try {
|
||||
$str = util::rmdir($file);
|
||||
$this->assertTrue(false);
|
||||
} catch (\Exception $e) {
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
|
||||
unlink($file);
|
||||
|
||||
// Test deleting a nested directory
|
||||
$dir1 = $dirname . '/test5';
|
||||
$dir2 = $dirname . '/test5/nested_dir';
|
||||
$file1 = $dir1 . '/file1.txt';
|
||||
$file2 = $dir2 . '/file2.txt';
|
||||
mkdir($dir1);
|
||||
mkdir($dir2);
|
||||
touch($file1);
|
||||
touch($file2);
|
||||
|
||||
$this->assertTrue(is_dir($dir1));
|
||||
$this->assertTrue(is_dir($dir2));
|
||||
$this->assertTrue(is_file($file1));
|
||||
$this->assertTrue(is_file($file2));
|
||||
|
||||
if (is_dir($dir1)) {
|
||||
util::rmdir($dir1);
|
||||
$this->assertFalse(is_dir($dir1));
|
||||
$this->assertFalse(is_dir($dir2));
|
||||
$this->assertFalse(is_file($file1));
|
||||
$this->assertFalse(is_file($file2));
|
||||
}
|
||||
|
||||
// Test symlink traversal.
|
||||
$dir = $dirname . '/test6';
|
||||
$nestedDir = "$dir/nested";
|
||||
$symlink = "$dir/nested-symlink";
|
||||
|
||||
mkdir($dir);
|
||||
mkdir($nestedDir);
|
||||
|
||||
$symlinkStatus = symlink($nestedDir, $symlink);
|
||||
$this->assertTrue($symlinkStatus, 'The test system does not support making symlinks.');
|
||||
|
||||
if (!$symlink) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->assertTrue(util::rmdir($symlink, true), 'Could not delete a symlinked directory.');
|
||||
$this->assertFalse(file_exists($symlink), 'Could not delete a symlinked directory.');
|
||||
util::rmdir($dir, true);
|
||||
$this->assertFalse(is_dir($dir), 'Could not delete a directory with a symlinked directory inside of it.');
|
||||
}
|
||||
|
||||
public function test_get_current_url()
|
||||
{
|
||||
$expected = 'http://test.dev/test.php?foo=bar';
|
||||
$expectedAuth = 'http://admin:123@test.dev/test.php?foo=bar';
|
||||
$expectedPort = 'http://test.dev:443/test.php?foo=bar';
|
||||
$expectedPort2 = 'https://test.dev:80/test.php?foo=bar';
|
||||
$expectedSSL = 'https://test.dev/test.php?foo=bar';
|
||||
|
||||
$_SERVER['HTTP_HOST'] = 'test.dev';
|
||||
$_SERVER['SERVER_PORT'] = 80;
|
||||
$_SERVER['REQUEST_URI'] = '/test.php?foo=bar';
|
||||
$_SERVER['QUERY_STRING'] = 'foo=bar';
|
||||
$_SERVER['PHP_SELF'] = '/test.php';
|
||||
|
||||
// Test regular.
|
||||
$this->assertEquals($expected, util::get_current_url());
|
||||
|
||||
// Test server auth.
|
||||
$_SERVER['PHP_AUTH_USER'] = 'admin';
|
||||
$_SERVER['PHP_AUTH_PW'] = '123';
|
||||
$this->assertEquals($expectedAuth, util::get_current_url());
|
||||
unset($_SERVER['PHP_AUTH_USER']);
|
||||
unset($_SERVER['PHP_AUTH_PW']);
|
||||
|
||||
// Test port.
|
||||
$_SERVER['SERVER_PORT'] = 443;
|
||||
$this->assertEquals($expectedPort, util::get_current_url());
|
||||
|
||||
// Test SSL.
|
||||
$_SERVER['HTTPS'] = 'on';
|
||||
$this->assertEquals($expectedSSL, util::get_current_url());
|
||||
$_SERVER['SERVER_PORT'] = 80;
|
||||
$this->assertEquals($expectedPort2, util::get_current_url());
|
||||
unset($_SERVER['HTTPS']);
|
||||
|
||||
// Test no $_SERVER['REQUEST_URI'] (e.g., MS IIS).
|
||||
unset($_SERVER['REQUEST_URI']);
|
||||
$this->assertEquals($expected, util::get_current_url());
|
||||
}
|
||||
|
||||
public function test_set_writable()
|
||||
{
|
||||
if (strncasecmp(PHP_OS, 'WIN', 3) === 0) {
|
||||
$this->markTestSkipped('This functionality is not working on Windows.');
|
||||
}
|
||||
|
||||
if (posix_geteuid() === 0) {
|
||||
$this->markTestSkipped('These tests don\'t work when run as root');
|
||||
}
|
||||
|
||||
$this->assertFalse(util::set_writable('/no/such/file'));
|
||||
|
||||
// Create a file to test with
|
||||
$dirname = dirname(__FILE__);
|
||||
$file = $dirname . '/test7';
|
||||
touch($file);
|
||||
chmod($file, 0644);
|
||||
|
||||
// The file is owned by us so it should be writable
|
||||
$this->assertTrue(is_writable($file));
|
||||
$this->assertEquals('-rw-r--r--', util::full_permissions($file));
|
||||
|
||||
// Toggle writable bit off for us
|
||||
util::set_writable($file, false);
|
||||
clearstatcache();
|
||||
$this->assertFalse(is_writable($file));
|
||||
$this->assertEquals('-r--r--r--', util::full_permissions($file));
|
||||
|
||||
// Toggle writable bit back on for us
|
||||
util::set_writable($file, true);
|
||||
clearstatcache();
|
||||
$this->assertTrue(is_writable($file));
|
||||
$this->assertEquals('-rw-r--r--', util::full_permissions($file));
|
||||
|
||||
unlink($file);
|
||||
}
|
||||
|
||||
public function test_set_readable()
|
||||
{
|
||||
if (strncasecmp(PHP_OS, 'WIN', 3) === 0) {
|
||||
$this->markTestSkipped('This functionality is not working on Windows.');
|
||||
}
|
||||
|
||||
if (posix_geteuid() === 0) {
|
||||
$this->markTestSkipped('These tests don\'t work when run as root');
|
||||
}
|
||||
|
||||
$this->assertFalse(util::set_readable('/no/such/file'));
|
||||
|
||||
$dirname = dirname(__FILE__);
|
||||
$file = $dirname . '/test8';
|
||||
touch($file);
|
||||
|
||||
$this->assertTrue(is_readable($file));
|
||||
|
||||
util::set_readable($file, false);
|
||||
clearstatcache();
|
||||
$this->assertFalse(is_readable($file));
|
||||
|
||||
util::set_readable($file, true);
|
||||
clearstatcache();
|
||||
$this->assertTrue(is_readable($file));
|
||||
|
||||
unlink($file);
|
||||
}
|
||||
|
||||
public function test_set_executable()
|
||||
{
|
||||
if (strncasecmp(PHP_OS, 'WIN', 3) === 0) {
|
||||
$this->markTestSkipped('This functionality is not working on Windows.');
|
||||
}
|
||||
|
||||
if (posix_geteuid() === 0) {
|
||||
$this->markTestSkipped('These tests don\'t work when run as root');
|
||||
}
|
||||
|
||||
$this->assertFalse(util::set_executable('/no/such/file'));
|
||||
|
||||
$dirname = dirname(__FILE__);
|
||||
$file = $dirname . '/test9';
|
||||
touch($file);
|
||||
|
||||
$this->assertFalse(is_executable($file));
|
||||
|
||||
util::set_executable($file, true);
|
||||
clearstatcache();
|
||||
$this->assertTrue(is_executable($file));
|
||||
|
||||
util::set_executable($file, false);
|
||||
clearstatcache();
|
||||
$this->assertFalse(is_executable($file));
|
||||
|
||||
unlink($file);
|
||||
}
|
||||
|
||||
public function test_directory_size() {
|
||||
$dirname = dirname(__FILE__);
|
||||
$dir = $dirname .'/dir1';
|
||||
mkdir($dir);
|
||||
$file1 = $dir .'/file1';
|
||||
file_put_contents($file1, '1234567890');
|
||||
$file2 = $dir .'/file2';
|
||||
file_put_contents($file2, range('a', 'z'));
|
||||
$this->assertEquals(10 + 26, util::directory_size($dir));
|
||||
util::rmdir($dir);
|
||||
}
|
||||
|
||||
public function test_get_user_directory() {
|
||||
// Test for OS Default.
|
||||
$this->assertTrue(is_writable(util::get_user_directory()));
|
||||
|
||||
$oldServer = $_SERVER;
|
||||
unset($_SERVER);
|
||||
// Test for UNIX.
|
||||
$_SERVER['HOME'] = '/home/unknown';
|
||||
$this->assertEquals($_SERVER['HOME'], util::get_user_directory(), 'Could not get the user\'s home directory in UNIX.');
|
||||
unset($_SERVER);
|
||||
|
||||
// Test for Windows.
|
||||
$expected = 'X:\Users\ThisUser';
|
||||
$_SERVER['HOMEDRIVE'] = 'X:';
|
||||
$_SERVER['HOMEPATH'] = '\Users\ThisUser';
|
||||
$this->assertEquals($expected, util::get_user_directory(), 'Could not get the user\'s home directory in Windows.');
|
||||
|
||||
// In case the tests are not being run in isolation.
|
||||
$_SERVER = $oldServer;
|
||||
}
|
||||
|
||||
public function test_directory_contents() {
|
||||
$dirname = dirname(__FILE__);
|
||||
$dir = $dirname . DIRECTORY_SEPARATOR .'dir1';
|
||||
mkdir($dir);
|
||||
$file1 = $dir . DIRECTORY_SEPARATOR .'file1';
|
||||
touch($file1);
|
||||
$this->assertEquals(array($file1), util::directory_contents($dir));
|
||||
util::rmdir($dir);
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
require __DIR__ . '/src/utilphp/util.php';
|
||||
|
||||
/**
|
||||
* Globally namespaced version of the class.
|
||||
*
|
||||
* @author Brandon Wamboldt <brandon.wamboldt@gmail.com>
|
||||
*/
|
||||
class util extends \utilphp\util { }
|
||||
Reference in new issue
Block a user