Compare commits

...
Sign in to create a new pull request.

369 commits

Author SHA1 Message Date
Josh Sherman
8e88ffb440 Fixed composer.json and updated dependencies 2014-10-19 10:29:29 -04:00
Josh Sherman
11e4fee711 Switching the OAuth2 lib back again
Couldn't handle the fact that the errors were being echoed from the library
and not thrown or at the very least passed back so I could use them.
2014-10-19 10:26:15 -04:00
Josh Sherman
1ef2adae12 Added suggestions 2014-10-19 10:23:48 -04:00
Josh Sherman
a4242fd611 Updated dependencies 2014-10-19 09:31:01 -04:00
Josh Sherman
6414644f35 Shifting to that NoSQL life
Dropped the database abstraction layer, added a rudimentary MongoDB class,
dopped all of the interface classes for the OAuth2 library and updated the
dependencies to use @bshaffer's OAuth2 class as it has MongoDB support out of
the box.
2014-10-19 09:16:11 -04:00
Josh Sherman
76611eb7da Bye bye Model. 2014-10-18 12:54:33 -04:00
Josh Sherman
91579b3be4 Dropped Distance class
Moved off to joshtronic/php-distance
2014-10-17 07:26:29 -04:00
Josh Sherman
ecb075b344 Dropped Convert class
All it contained was an array to XML function. Moved off to
joshtronic/php-array2xml
2014-10-17 07:22:15 -04:00
Josh Sherman
ce45dc0dbe Dropped Sort class
Moved it off to joshtronic/php-sort
2014-10-17 07:18:47 -04:00
Josh Sherman
ea28dbbc5e Dropped file class
All it contained was a method to remove a directory recursively. Moved
files over to joshtronic/php-rmr (rm -r)
2014-10-17 07:15:06 -04:00
Josh Sherman
68b2f83379 Dropped Number class
Actually just moved it to joshtronic/php-ordinalindicator
2014-10-17 06:53:08 -04:00
Josh Sherman
9d5dac05c3 Dropped browser class
Actually moved it off to joshtronic/php-remoteaddr
2014-10-17 06:48:03 -04:00
Josh Sherman
b5b7cacc28 Merge branch '2.0' of git://github.com/picklesphp/pickles into 2.0 2014-10-16 21:12:00 -04:00
Josh Sherman
1aa39f3a8d Made refresh_token grant configurable 2014-10-16 19:25:57 -04:00
Josh Sherman
59af055f7e Merge branch 'master' into 2.0
Conflicts:
	composer.json
2014-10-16 10:40:52 -04:00
Josh Sherman
c824d3d5e6 Cleaned up the links a bit. 2014-10-16 10:40:11 -04:00
Josh Sherman
ba2729cb7f Merge branch '2.0' of github.com:picklesphp/pickles into 2.0 2014-10-16 10:34:12 -04:00
Josh Sherman
59777fe206 Update README.md 2014-10-16 10:29:49 -04:00
Josh Sherman
35af1f4037 Merge branch '2.0' of git://github.com/picklesphp/pickles into 2.0
Conflicts:
	src/OAuth2/SessionStorage.php
2014-10-16 07:32:06 -04:00
Josh Sherman
a40041acc6 Implemented refresh tokens
Right now it's hardcoded to always return a refresh token when you issue an
access token. Should think about making this an optional workflow or committing
to it being turned on indefinitely.
2014-10-16 07:30:32 -04:00
Josh Sherman
9e2e4f75f3 Tweaked schema some more. 2014-10-15 07:56:25 -04:00
Josh Sherman
f235f4a520 Tweaking the schema 2014-10-15 07:48:34 -04:00
Josh Sherman
08284b0f35 Fixed dependency version 2014-10-15 07:18:09 -04:00
Josh Sherman
32e7ae5f0f Switched oauth lib
Wasn't pleased to find that the new lib used the username as the primary key
across a bunch of tables. Not ideal IMO.
2014-10-15 07:08:39 -04:00
Josh Sherman
84231d9434 Swapped oauth lib 2014-10-14 22:24:46 -04:00
Josh Sherman
dc06f37320 Updated the interfaces and dropped oauth version
Seems the oauth lib's stable version is 3.2, dropped down from the 4 version
to that.
2014-10-14 22:05:52 -04:00
Josh Sherman
c244e02d46 Implementing storage interfaces 2014-10-14 07:11:03 -04:00
Josh Sherman
49a713eb35 Finished up password grant 2014-10-13 22:50:43 -04:00
Josh Sherman
ec14621e7c Tweaked unit tests 2014-10-13 21:46:34 -04:00
Josh Sherman
1cc1595e30 Updated dependencies 2014-10-13 21:30:57 -04:00
Josh Sherman
8e9c644822 Working out the routing 2014-10-13 21:27:19 -04:00
Josh Sherman
75596ed725 Moved to new namespace 2014-10-12 21:53:15 -04:00
Josh Sherman
2ec85c469b Working on that OAuth2 2014-10-12 21:20:48 -04:00
Josh Sherman
a834692235 Stubbed out storage classes 2014-10-11 07:40:09 -04:00
Josh Sherman
4a8378c6c2 Merge branch '2.0' of github.com:picklesphp/pickles into 2.0 2014-10-08 21:48:01 -04:00
Josh Sherman
cb4dac157d Updated dependencies 2014-10-08 21:42:42 -04:00
Josh Sherman
aa8c86e5c2 Working on oauth 2014-10-08 21:37:22 -04:00
Josh Sherman
840a68961c Cleaned up some double ;; 2014-10-07 12:10:46 -04:00
Josh Sherman
1599319478 Updated class name 2014-10-07 09:48:07 -04:00
Josh Sherman
846f75d0f3 Updated dependencies 2014-10-07 09:37:58 -04:00
Josh Sherman
8e60e9d553 Dropped date utility class
Only had one function and it was referencing the time class. Moved date tests
to the time tests because it seemed like a more comprehensive set of tests.
2014-10-07 09:33:21 -04:00
Josh Sherman
442e505cbf Merge branch 'master' into 2.0 2014-10-07 09:31:21 -04:00
Josh Sherman
de12028b35 Added oauth server as a dependency 2014-10-06 19:53:09 -04:00
Josh Sherman
c5d39db63b Brought Sort back into the repo
Decided that having a bunch of external dependencies would end up being more
trouble than it's worth
2014-10-06 18:27:53 -04:00
Josh Sherman
6c148c124e Added self-update to the travis build
Making this a standard thing in my travis scripts because it seems they let the
version go stale pretty regularly.
2014-10-04 11:10:59 -04:00
Josh Sherman
ee34d8aff9 Standardized the badges 2014-10-04 11:08:01 -04:00
Josh Sherman
77473c5b31 Dropped sort class from the core 2014-10-04 11:04:21 -04:00
Josh Sherman
e45e1251e1 Added auth test, cleaned up directory 2014-10-04 07:24:57 -04:00
Josh Sherman
a866a1a61b Merge branch 'master' into 2.0 2014-10-03 11:08:50 -04:00
Josh Sherman
2df1a5a162 Updated project name 2014-10-03 11:06:16 -04:00
Josh Sherman
ae98b67683 Cleaned up headers 2014-10-03 10:46:43 -04:00
Josh Sherman
84a785d4c9 Added Basic Auth functionality 2014-10-03 07:30:10 -04:00
Josh Sherman
89fc175701 Updated dependencies 2014-10-03 06:50:55 -04:00
Josh Sherman
e08c9a5ade Tweaked readme a bit 2014-10-03 06:43:44 -04:00
Josh Sherman
75951b90ef Updated dependencies 2014-10-03 06:41:42 -04:00
Josh Sherman
4c55c25f00 Cleared out instances 2014-10-03 06:33:55 -04:00
Josh Sherman
1a589efe12 Added config loading 2014-10-03 06:30:02 -04:00
Josh Sherman
908fff2193 Dropped php -a as it is hanging HHVM 2014-10-03 06:21:21 -04:00
Josh Sherman
823fe0759a Updated to only inject on non-HHVM
Saw someone else's .travis.yml that opted to not put those extension lines into
the INI when running on HHVM. Worth a shot!
2014-10-03 06:17:54 -04:00
Josh Sherman
ab6623d6fb Trying to debug hhvm
Added php -i to see where the php.ini file lives, the one I read about on
Github doesn't allow me to write to it.
2014-10-03 06:10:45 -04:00
Josh Sherman
c61a49f8a7 Fixed version check 2014-10-03 06:03:19 -04:00
Josh Sherman
e5270afed4 Dropped PHP 5.3 2014-10-02 23:40:56 -04:00
Josh Sherman
58e54bcf7b Updated lock file. 2014-10-02 22:56:42 -04:00
Josh Sherman
bbf392f45f Still tweaking towards HHVM 2014-10-02 22:01:59 -04:00
Josh Sherman
c7a6852a3d Working on script. 2014-10-02 21:55:16 -04:00
Josh Sherman
cd05384a6d Made script executable. 2014-10-02 21:49:28 -04:00
Josh Sherman
5b2f483fa5 Added script to set up extension
As per https://github.com/travis-ci/travis-ci/issues/2523 it appears that the
php.ini on hhvm is in a different place. Created a script to write the
extensions to the right php.ini based on the environment.
2014-10-02 21:47:01 -04:00
Josh Sherman
31f4c32fb0 Reworked test to check for PHP version
`password_hash` is PHP 5.5. Instead of adding the sanity check in the code,
I've opted to put it in the test to ditch the overhead of having to make that
check for every request.
2014-10-02 21:34:09 -04:00
Josh Sherman
1b365bcff0 Added root namespace to function
Tests were failing on 5.4 out on travis. Was barking about the function not
existing in the namespace. Hoping this resolves it.
2014-10-02 21:18:36 -04:00
Josh Sherman
5ce36537a6 Renamed bootstrap file 2014-10-02 21:11:23 -04:00
Josh Sherman
b1304a44d0 Merge branch 'master' of github.com:joshtronic/pickles 2014-10-02 21:05:20 -04:00
Josh Sherman
510b5d8edc Added new branches to test 2014-10-02 20:59:27 -04:00
Josh Sherman
d884f5a3df Finished up tests 2014-10-02 20:54:12 -04:00
Josh Sherman
4167d99623 Fixed deleting a file
Not sure when this became an issue, but attempting to delete a file that ends
with / will result in an error on OS X
2014-10-02 18:15:48 -04:00
Josh Sherman
90c4c53294 Fixed up the config again 2014-10-02 17:54:59 -04:00
Josh Sherman
c9ffe4c8bf Fixed config in tests 2014-10-02 17:44:00 -04:00
Josh Sherman
b48b73d064 Dropped SITE_PATH 2014-10-02 17:41:06 -04:00
Josh Sherman
a41ee7c2d2 Fixed config loading 2014-10-02 17:34:25 -04:00
Josh Sherman
df98b99440 Dropped uopz from travis config 2014-10-02 07:28:58 -04:00
Josh Sherman
c8d97aac26 Reworking database tests 2014-10-02 07:28:12 -04:00
Josh Sherman
07ed22c58f Fixed up resource class' tests 2014-10-02 07:02:29 -04:00
Josh Sherman
173136ddce Finished up Profiler and test coverage 2014-10-02 06:42:16 -04:00
Josh Sherman
9e65b2cfc2 Spruced up profiler, need to finish up tests 2014-10-01 22:08:11 -04:00
Josh Sherman
ee8bd63a08 Working on that new profiler
Gotta figure out what's going on with the database portion, it's going all
crazy on me.
2014-10-01 07:41:01 -04:00
Josh Sherman
506ff1fd45 Unit tests for the Object class 2014-09-30 22:24:10 -04:00
Josh Sherman
d4551d72a6 Evidently updated some dependencies 2014-09-30 18:07:49 -04:00
Josh Sherman
88a4375dd5 Wrapped up unit tests on Config class 2014-09-30 15:58:16 -04:00
Josh Sherman
2acd1b976e Updated dependencies 2014-09-30 15:06:53 -04:00
Josh Sherman
394c86d6ab Updated dependencies a bit 2014-09-30 09:49:08 -04:00
Josh Sherman
725d952192 Reworked config class, working on unit tests 2014-09-30 07:21:52 -04:00
Josh Sherman
52c8a730f3 Dropped pickles.ph made some assumptions
Wanted to be 100% reliant on the autoloader so I dropped the manual include of
pickles.php. Also moved some of the PHP ini logic out of here and baked in
some assumptions about environments and settings. Basically anything other than
"production" will set display errors to true, production is false.
2014-09-29 22:07:18 -04:00
Josh Sherman
1c974fc9ad Reworked config to be an arrayobject
Death to the mix of object variable and array. Also cleaned up the profiler
sanity checks as the variable will always be present now. Profiler is now an
all or nothing action.
2014-09-29 21:32:08 -04:00
Josh Sherman
f2d2f79a50 Update README.md 2014-09-29 17:58:38 -04:00
Josh Sherman
f2f1cbc166 Dropped validate test
All tests were moved to the RouterTest class
2014-09-28 21:51:06 -04:00
Josh Sherman
f62d12f35b Dropped dupe test 2014-09-28 21:50:28 -04:00
Josh Sherman
aea1bae3bf Working on tests for Resource 2014-09-28 21:49:49 -04:00
Josh Sherman
6c173cdc89 Working on tests for the Resource class.
Got a bunch more validation rules to port over.
2014-09-28 09:47:54 -04:00
Josh Sherman
3b8eddc7b5 Dropped status code method
The function `http_response_code` was added in PHP 5.4 which deprecated the
code I had written. Dropped functionality and tests and updated code to use the
new function.
2014-09-28 08:36:14 -04:00
Josh Sherman
da379d0849 Knocked out unit tests for the new Router 2014-09-28 08:24:02 -04:00
Josh Sherman
273af98883 Renamed bootstrap
Made it caps to go along with all of the existing test names
2014-09-28 07:43:28 -04:00
Josh Sherman
0cfc2c7979 Moved tests and updated to use namespaces 2014-09-28 07:31:02 -04:00
Josh Sherman
302f400dcb Removed some leftover debug code 2014-09-28 06:51:35 -04:00
Josh Sherman
372ba2812b Feeling frisky, added PHP 5.3 back to the tests
Curious if I'd be able to get back to PHP 5.3 compatibility to an extent.
2014-09-27 23:04:51 -04:00
Josh Sherman
59817fa5c4 That abridged README
Cut all the bullshit out so I could write out a better README once the system
is back to being stable and tested.
2014-09-27 22:55:12 -04:00
Josh Sherman
4af10e0fb6 Cleaning up a bit
The plan is to drop this file entirely and move the logic off to the config
class itself which will be instantiated by the router.
2014-09-27 22:36:03 -04:00
Josh Sherman
79f8da8c45 Namespaced the fuck out of Pickles 2014-09-27 22:28:15 -04:00
Josh Sherman
48c5289060 Moved files and added namespaces 2014-09-27 17:57:07 -04:00
Josh Sherman
8a1ac4fb47 Worked through basic authentication 2014-09-27 16:40:41 -04:00
Josh Sherman
718f8d64bb Working on basic auth and dropped log class
I personally haven't used it in years so I'm just getting to the mindset that
it's not a very useful piece of functionality. Nginx can easily log all of your
requests and any time I need to troubleshoot SQL (not all that often) I do it
directly without using the class.
2014-09-27 15:37:41 -04:00
Josh Sherman
bdb4ca8ff0 Renamed secure flag to https 2014-09-27 14:02:52 -04:00
Josh Sherman
53d8ab1137 Added powered by pickles header 2014-09-27 14:01:04 -04:00
Josh Sherman
20aff31b94 Moved validate logic into resource
I couldn't find a single scenario where I was using the Validate class in my
site level code. Dropped the overhead of calling a static class method multiple
times on a page by moving the logic in the Resource class. Also changed the
response to always return the errors as parameter => array. This allows a
developer to choose if they want to display one error or all of the errors.
2014-09-27 12:06:33 -04:00
Josh Sherman
50ea072929 Added password_hash filter
Defaulting to PASSWORD_DEFAULT, will expand to other options if the need arises.
2014-09-27 11:47:29 -04:00
Josh Sherman
3861bfc571 Dropped the filter class
Will revisit if there's ever a need to have access to it directly. Until then
it will find it in the Resource class.
2014-09-27 11:33:53 -04:00
Josh Sherman
141ac693cb Dropped response class
Seems pointless to have class that had a single method that basically contained
all of the shit that the resource already had and knew. Moved respond() method
to the response class and moved all of the response validation logic and errors
from the router to the response class.
2014-09-27 11:25:45 -04:00
Josh Sherman
a749c80d93 Added variable filtering and validation
Validation logic was existing but it was reworked to abstract out checking for
required fields initially and then sanity checks after the fact. Filters are
applied before validation but after checking existence. No support for _PUT and
_DELETE at the moment as those do not exist as super globals natively in PHP.
2014-09-27 08:13:05 -04:00
Josh Sherman
0ad0754726 Module -> Resource 2014-09-27 05:28:14 -04:00
Josh Sherman
824faffcc6 Stubbing out some new classes 2014-09-26 07:36:50 -04:00
Josh Sherman
7108c2c440 Dropped security groups 2014-09-26 07:34:11 -04:00
Josh Sherman
7f297b06f5 Put in a note about 404s 2014-09-26 07:33:32 -04:00
Josh Sherman
6097e29aef Cleaning up tests 2014-09-26 07:31:04 -04:00
Josh Sherman
bdb16009c1 Simplified the travis config a bit 2014-09-26 05:52:40 -04:00
Josh Sherman
2445f2f339 Added phpunit.xml
Was still typing in the full command to run phpunit from time to time. Can
now just run unit tests by running phpunit without any config flags
2014-09-26 05:49:49 -04:00
Josh Sherman
d7ad1d148e Dropped deprecated tests 2014-09-25 23:29:05 -04:00
Josh Sherman
39d5b8d40b Cleaned up unit tests
Wanted to get back to the point that the tests were running and not erroring.
2014-09-25 23:11:29 -04:00
Josh Sherman
ebc5584660 Merge branch '2.0' 2014-09-25 21:50:26 -04:00
Josh Sherman
26e913a3d9 Dropped Dynamic Class
Pretty sure we don't need it anymore. Could come back up in the future when an
API is returning URIs for static assets and they are being cached and it's not
being flushed correctly.
2014-09-25 21:48:13 -04:00
Josh Sherman
d5a2753c20 Reworked error handling. 2014-09-25 21:33:43 -04:00
Josh Sherman
69b14085b4 Module -> Resource
Dropping those dated naming conventions
2014-09-25 20:57:05 -04:00
Josh Sherman
94f46fc583 Controller -> Router, Display -> Response
Just gutting the brains of this thing.
2014-09-25 20:55:11 -04:00
Josh Sherman
17d19728e3 Update README.md
Tweaked buttons
2014-09-25 10:06:11 -04:00
Josh Sherman
98f03c2a76 Merge pull request #49 from waffle-iron/master
waffle.io Badge
2014-09-25 10:03:04 -04:00
Josh Sherman
b67269a202 Dropped that dirty dirty XML support. 2014-09-25 09:27:59 -04:00
Josh Sherman
2fa2b6ad03 Started gutting logic from the Controller and Display classes. 2014-09-24 23:57:39 -04:00
Josh Sherman
1381fd82a0 Dropped other classes we don't need any longer 2014-09-24 23:33:03 -04:00
Josh Sherman
e299d268c8 Setting headers and shit 2014-09-24 23:26:00 -04:00
Josh Sherman
0fdf2149be Dropped markup logic
Dropped the display / template rendering layer. API-first, converting to be a
lean mean data driven machine.
2014-09-24 23:24:36 -04:00
Josh Sherman
eba206556c Set up return structure. 2014-09-24 22:28:34 -04:00
Making GitHub Delicious.
aaa4a0fa16 add waffle.io badge 2014-09-24 07:57:17 -06:00
Josh Sherman
1718bc27a6 Dropped gravatar method
Seems I had a method in the string class that referenced the now removed
gravatar API wrapper. Dropped the method and the associated test.
2014-09-24 07:24:56 -04:00
Josh Sherman
60ab001833 Updated composer deps 2014-09-24 00:07:41 -04:00
Josh Sherman
0090adef7c Dropped AYAH
Going to merge into my AYAH library eventually. For now just need to remove it
2014-09-23 22:52:22 -04:00
Josh Sherman
5f2eaead10 Moved Google Profanity API to it's own repo
It can be found at https://github.com/joshtronic/php-googleprofanity
2014-09-23 22:19:45 -04:00
Josh Sherman
67be4e0889 Dropped Gravatar class
Gone but not forgottten, the class now lives in
https://github.com/joshtronic/php-gravatar
2014-09-23 20:58:12 -04:00
Josh Sherman
2f2dd0d8b8 Moved placehold.it class to it's own repo
Decoupling API wrappers from PICKLES. New location for the API is
https://github.com/joshtronic/php-placeholdit
2014-09-23 20:02:40 -04:00
Josh Sherman
93ee7356b2 Dropped asset minification
Been moving away from using this functionality in favor of either Grunt or
Gulp. Dropped functionality for minification of CSS and JS but left the dynamic
reference logic intact. This will be moved to the HTML class eventually and
expanded to support the generation of the HTML tags as well as injecting the
URI with a timestamp.
2014-09-23 18:22:56 -04:00
Josh Sherman
c88d469e18 Rolled back to vfsStream v1.3.0
Moved to v1.4.0 and my tests started to fail. Locked version until I get around
to figuring out what changed and fix my code to accommodate
2014-09-23 18:01:06 -04:00
Josh Sherman
55f45b8d8f Merge branch 'master' of github.com:joshtronic/pickles 2014-09-23 07:23:36 -04:00
Josh Sherman
6c7b81aeb4 Cleaned up formatting a bit
Had a few lines that were way too long.
2014-09-23 07:23:07 -04:00
Josh Sherman
3701971894 Dropped autoload require
Thinking this may bork the test suite because it won't be able to fine ayah.
This is just part of the move towards having a local copy of pickles in the
project installed and managed by composer. Also retabbed the composer json.
2014-09-21 22:08:13 -04:00
Josh Sherman
702414b694 Updated dependencies and dropped most version numbers
There's no point in defining version numbers prematurely. I'll update with
exact versions as the need arises. At the moment `dev-master` outta be good
enough.
2014-09-20 15:43:15 -04:00
Josh Sherman
617eb21614 Converted tabs to spaces. 2014-09-13 17:06:28 -04:00
Josh Sherman
3e08d173a1 Cleaned up issues with phpunit 4.2.x 2014-09-13 16:43:29 -04:00
Josh Sherman
0c40241b45 Finishing out the phpunit version. 2014-09-13 16:15:28 -04:00
Josh Sherman
891d08d7ad Eventually... 2014-09-13 16:10:32 -04:00
Josh Sherman
cc8da12327 Still trying to get uopz to load correctly. 2014-09-13 15:32:38 -04:00
Josh Sherman
07863a5a84 Dropped absolute version paths 2014-09-13 15:23:04 -04:00
Josh Sherman
60a6cfa2bf Removed a tab
How'd that get in there? ;)
2014-09-13 15:07:47 -04:00
Josh Sherman
e340593cd0 MOAR EXTENSIONS
Added additional paths to see which one will stick. Should move to a setup
script that sniffs the environment and injects the correct version.
2014-09-13 15:06:39 -04:00
Josh Sherman
1405ede86f Rehashing path 2014-09-13 14:54:44 -04:00
Josh Sherman
8b024c17d9 Still no dice, went back to just appending zend_ 2014-09-13 14:49:49 -04:00
Josh Sherman
9867789060 Dropped appending zend_ to the file. 2014-09-13 12:15:52 -04:00
Josh Sherman
c56aadd6e6 Updated sed to write to a new file and then mv 2014-09-13 12:13:50 -04:00
Josh Sherman
cdce86971a Switched command to sed
My fault for trusting some shit off teh interwebs without testing it. `tail`
srsly?!
2014-09-13 12:09:22 -04:00
Josh Sherman
e8781d8a7d Stripping first line from php.ini
I think the dupe declaration is borking the loading of the extension. This very
well could mark the point that support for PHP 5.4 is dropped.
2014-09-13 12:03:35 -04:00
Josh Sherman
651a6d338b Doing some debugging on Travis 2014-09-13 11:56:00 -04:00
Josh Sherman
4228ae81ff Updated README
Wrapped to 80 columns and cleaned up the URLs
2014-09-13 10:51:53 -04:00
Josh Sherman
70c21db132 PHP 5.6 is no longer an allowed failure. 2014-09-01 11:58:01 -04:00
Josh Sherman
30fc51dcd5 Upgraded scssphp 2014-08-14 22:16:24 -04:00
Josh Sherman
3098300c6e Fixed issue with scss being moved to PSR-4 2014-08-11 21:33:09 -04:00
Josh Sherman
695f4d3196 Added php to the list of dependencies 2014-08-10 08:21:44 -04:00
Josh Sherman
69c2fba9a1 Dumped dependency's version
@leafo's project has been quite active this week.
2014-08-10 08:17:10 -04:00
Josh Sherman
179f9cc143 Updated leafo/scssphp to 0.0.15 2014-08-07 18:57:06 -04:00
Josh Sherman
d00ce689b1 Changed username
Updated username in mock config for Model tests.
2014-08-05 20:08:56 -04:00
Josh Sherman
fea03520c8 Reconfigured database username
Seems @travis-ci did make some changes as per their blog. Updated code to use
the username `root` for connections instead of no user.
2014-08-05 18:58:33 -04:00
Josh Sherman
4645ac95eb Added command to create database
Evidently @travis-ci no longer includes the `test` database in MySQL by
default. Added the command to create said database before importing SQL.
2014-08-05 18:47:21 -04:00
Josh Sherman
e19d3bd8b5 Updated leafo/scssphp to latest version
Just clearing out out of date dependencies.
2014-08-05 18:41:04 -04:00
Josh Sherman
84df7a1136 Dropped the UA 2014-07-27 18:11:25 -04:00
Josh Sherman
c02f658385 Updated dependencies 2014-07-27 18:02:18 -04:00
Josh Sherman
79228d0f73 Updated README
Updated the optional software to include UOPZ instead of php-test-helpers
2014-07-12 14:50:19 -04:00
Josh Sherman
73d853e866 Attempting to load extension twice
Seems 5.5+ handles nicely to simply changing from extension to zend_extension. 5.4 barks about not being able to find the shared object. Added 2 commands to attempt to load both. One should fail but the tests should pass. I'm not quite ready to give up on PHP 5.4, not until 5.6 is GM
2014-07-12 14:45:43 -04:00
Josh Sherman
e14db9aec8 Getting crazy with the conditionals 2014-07-12 14:41:46 -04:00
Josh Sherman
4a06032ac7 Appending zend_ to extension call 2014-07-12 14:23:18 -04:00
Josh Sherman
fc25e80142 Interrogating PHP directly for version 2014-07-12 14:14:27 -04:00
Josh Sherman
f050b50779 More tweaks. 2014-07-12 14:08:46 -04:00
Josh Sherman
5478c8df3c Tweaked travis config
Fighting with uopz... to be expected though.
2014-07-12 14:04:45 -04:00
Josh Sherman
d83859f03c Changed phpenv call
Was getting the major.minor and I need major.minor.revision
2014-07-12 13:22:07 -04:00
Josh Sherman
b17b35b89d Attempting to add in the absolute path of the uopz install 2014-07-12 13:16:38 -04:00
Josh Sherman
4ba24d3684 Dropped adding extension to the INI
Having some problems once it gets out on travis-ci. I suspect the path to the extension isn't being set properly and/or the extension isn't being loaded as a zend_extension which is mandatory.
2014-07-12 12:58:16 -04:00
Josh Sherman
260b532a66 Dropped php-test-helpers for uopz
Seems that uopz has superseded php-test-helpers. Updated the exit overloading and adjusted some tests based on the new behavior of not echoing out the argument passed to exit().
2014-07-12 12:41:47 -04:00
Josh Sherman
018ae0edc1 Adjusted test to accommodate format
It seems like AYAH changed the format of the script URL being returned. I made the last part optional in case the last part of the URL still shows up in legacy type scenarios.
2014-07-12 11:50:50 -04:00
Josh Sherman
df19a61ab7 Updated dependency versions
SCSS and Coveralls had new versions.
2014-07-12 11:42:06 -04:00
Josh Sherman
b08e1cabeb Added config to only test master 2014-05-12 22:48:57 -04:00
Josh Sherman
5349159c51 Merge branch 'master' of github.com:joshtronic/pickles 2014-05-10 12:52:28 -04:00
Josh Sherman
0870c99ede Added browser refresh method
Closes #44
2014-05-10 12:51:28 -04:00
Joshua Sherman
2d327927ba Dropped install and added 5.6 as an allowed failure
Still no dice on HHVM even with installing php5-dev. Added PHP 5.6 to see how
we fare. Will drop the allowed failure when 5.6 is gold or when the test suite
is passing. Whichever comes first.
2014-04-29 15:12:41 -04:00
Joshua Sherman
04d4e5105d Attempting to get HHVM to test 2014-04-29 15:00:59 -04:00
Joshua Sherman
c2871fca76 Added Placehold.it API wrapper
Closes #17
2014-04-20 19:12:58 -04:00
Joshua Sherman
1d28714d0a Updated files to be Josh instead of Joshua 2014-04-20 18:47:54 -04:00
Joshua Sherman
2763818e49 Updated test RegEx for AYAH
Seems the format being returned doesn't start with ip... updated RegEx to check
for a 45 character alphanumeric instead of ip + 43 character alpha numeric
2014-04-20 18:41:01 -04:00
Joshua Sherman
fa59eddae0 Upgraded SCSS to latest 2014-04-16 11:50:18 -04:00
Joshua Sherman
2a7555bf2b Updated dependencies 2014-04-16 11:46:49 -04:00
Josh Sherman
86ef824455 Only compile LESS or SASS if minify flag is true
Probably need to rename the minify flag since it now also represents compiling the CSS. Better yet, probably better to eliminate it entirely and make it an assumption that you should only be compiling when on the "local" environment or when the minified file is completely missing.
2014-02-20 15:55:02 -05:00
Joshua Sherman
048a118236 Fixed link to branch 2014-02-02 10:36:10 -05:00
Joshua Sherman
248c0ae458 Updated dependencies
I destroyed my old AYAH repo in favor of a fork of the official stuff that I updated. Had to add some vcs entry to get composer to pull from my fork and not the main package.
2014-02-02 10:16:00 -05:00
Joshua Sherman
4c59f7c55b Added round up to Time::ago
Some strings were resulting in returns of "24 hours" and "7 days" that needed to be rounded up to the next increment. Closes #28
2014-02-02 09:47:24 -05:00
Joshua Sherman
2559672246 Fixed user links 2014-01-26 15:56:22 -05:00
Joshua Sherman
ddf1719862 Reworked the README a bit 2014-01-26 15:52:31 -05:00
Joshua Sherman
7e993d9958 Merge branch 'master' of github.com:joshtronic/pickles 2014-01-26 15:11:18 -05:00
Joshua Sherman
0810302e4f Fixed issue with UTF-8 2-byte characters
Characters were being split up and causing invalid sequences when using
`substr()`. Went ahead and updated to use `mb_strcut()` and forcing the
character encoding to UTF-8. I think the plan down the road will be to set the
internal encoding to UTF-8 but I am not currently sure how that could effect
the rest of the system (perhaps it won't). Closes #39
2014-01-26 15:09:16 -05:00
Joshua Sherman
54875f149d Merge branch 'master' of github.com:joshtronic/pickles 2014-01-25 18:53:51 -05:00
Joshua Sherman
11f4f78d9c Added branch to the travis-ci badge 2014-01-25 18:52:49 -05:00
Joshua Sherman
782bad5c02 Went back to versioneye
Unsure why but Gemnasium kept showing that it was refreshing but never seemed
to load the dependencies even though the file was read in correctly. Will check
in a week, thinking perhaps they don't refresh nearly as frequently as I would
have liked.
2014-01-21 22:05:49 -05:00
Joshua Sherman
70a547cf6c Changed build/log directory 2014-01-21 21:51:59 -05:00
Joshua Sherman
710620e96a Trying all the paths. 2014-01-21 21:40:55 -05:00
Joshua Sherman
946df09750 Debugging coverage report location 2014-01-21 00:20:54 -05:00
Joshua Sherman
5f94652e9c Rehooking up coveralls 2014-01-20 23:58:32 -05:00
Joshua Sherman
4728858880 Added package details to json file 2014-01-20 23:44:51 -05:00
Joshua Sherman
adae3ba468 Moved pickles code to src/ 2014-01-20 23:20:43 -05:00
Joshua Sherman
2c55b25988 Fixing them paths for real. 2014-01-20 22:49:56 -05:00
Joshua Sherman
4e7f442f86 Fixed vendor paths and build path 2014-01-20 22:29:08 -05:00
Joshua Sherman
ec02d03457 Switched to HTTPS instead of SSH
Hoping that clears up the prompt
2014-01-20 22:26:29 -05:00
Joshua Sherman
e2f8464c51 Working towards standard directory names 2014-01-20 22:23:04 -05:00
Joshua Sherman
293f618bef Worked through some bugs, updated dependencies
The vendor directory is now just composer stuff. Planning to rearrange some
files soon but wanted to commit these changes. AYAH is now installed via
composer from a package I am maintaining and I dropped the test helpers as it
is a dev-only requirement (and that's assuming you even want to test).
2014-01-20 22:06:59 -05:00
Joshua Sherman
c9f39e2e18 Updated email address 2014-01-20 15:19:38 -05:00
Joshua Sherman
74a77e2262 Swapped dependency monitoring
Same functionality but now the button's green color matches the other two
buttons. Was kinda bugging me :-/
2014-01-20 15:06:18 -05:00
Joshua Sherman
7c8ae14b75 And then there were none. 2014-01-20 01:25:11 -05:00
Joshua Sherman
54cb6dfe83 Any closer and it would be done
Had to rework the Model class a bit, there's some weirdness happening and I'm
unsure if it's part of the rewrite or always been busted. Won't really know for
sure until I start porting sites over to it I suppose.
2014-01-20 01:06:22 -05:00
Joshua Sherman
db6e169f7b 95% coverage, getting close. 2014-01-19 22:36:30 -05:00
Joshua Sherman
f3d5d12b9f More testing and fixed capitalization fuck up
Seems I went ahead and munged the capitalization for half of the file.
2014-01-19 18:15:13 -05:00
Joshua Sherman
dada837300 Updated mock model to use a public attribute 2014-01-19 14:27:31 -05:00
Joshua Sherman
07d2348dd1 More model testing
Getting close!
2014-01-19 14:25:15 -05:00
Joshua Sherman
4bffc1d80c Dropped error message from expected exception
Travis was dumping the same error code but now the same message. Dropping the
message assertion but still asserting the expected exception code.
2014-01-18 11:47:08 -05:00
Joshua Sherman
72be314073 Finished up security class testing. 2014-01-18 11:43:23 -05:00
Joshua Sherman
30b9616b12 Finished testing the Database class 2014-01-18 10:31:46 -05:00
Joshua Sherman
2ff7a658e7 Testing Database class 2014-01-17 17:22:23 -05:00
Joshua Sherman
8655045097 Dropped database JOINs
Not being used and the logic is pretty damn hacky. I don't believe in JOINs so
I'm unsure if this support will be re-added in the future or if there will
simply be a backed in opinion that JOINs are the devil.
2014-01-17 15:46:57 -05:00
Joshua Sherman
9cc466bcd3 Module testing coverage 100% 2014-01-17 15:30:58 -05:00
Joshua Sherman
76d3c7cdc4 Fixed glitch causing a lack of coverage
The Session class relies on the REQUEST_METHOD being set, else it won't start
up. Added the value and the coverage jumped to 100%
2014-01-17 13:36:08 -05:00
Joshua Sherman
af16edfedd Dropped index hint tests 2014-01-17 13:16:37 -05:00
Joshua Sherman
68365142e7 Dropped index hinting support
Never gets used, ended up being somewhat MySQL specific as PostgreSQL favors
letting the server handle it instead of hinting at it. Write better queries I
suppose?
2014-01-17 13:14:36 -05:00
Joshua Sherman
57a5b0c2c0 More tests. 2014-01-17 01:53:27 -05:00
Joshua Sherman
191ceaa4e9 Updated module path 2014-01-16 21:42:42 -05:00
Joshua Sherman
9dadc1c821 Removed finally keyword, bringing back 5.4 2014-01-16 17:45:42 -05:00
Joshua Sherman
e662b8f2cd Dropped create database, seems it already exists
Unsure why it was documented that way in the travis-ci docs if it already
existed.
2014-01-16 17:29:58 -05:00
Joshua Sherman
51467a60f7 Working on tests for the Model class
Fixed some bugs, got MySQL setup for Travis.
2014-01-16 17:06:31 -05:00
Joshua Sherman
200988eecf Swapped all array() for the shorthand []
Also finished up coverage on the Cache class.
2014-01-15 14:09:54 -05:00
Joshua Sherman
aecdd0981f Finished tests for Config class 2014-01-15 13:46:17 -05:00
Joshua Sherman
f9f179b45d Profiler tests and some rework
Abandoned private constructor and cleaned up the code a bit.
2014-01-15 00:40:34 -05:00
Joshua Sherman
46b77fa1b1 Added sanity check to resolve missing variable
Unsure why but as of this morning (perhaps because of upgrading to PHP 5.5.8
PHPUnit started barking about _SERVER['HTTP_HOST'] not being set.
2014-01-14 11:34:51 -05:00
Joshua Sherman
da7a0de91f Removed process isolation 2014-01-14 02:44:15 -05:00
Joshua Sherman
6257f89b18 Added most of the Cache tests
Dropped some unnecessary try/catch blocks and updated the Database class to
not use any data sources that lack a driver.
2014-01-14 02:19:40 -05:00
Joshua Sherman
7b7fd901c9 Dropped env stuff. 2014-01-13 02:04:02 -05:00
Joshua Sherman
eea368a5d8 Cleaning up, trying to figure out how to detect env
Travis environment, want to be able to issues commands just on HHVM.
2014-01-13 01:58:59 -05:00
Joshua Sherman
25a2493946 Added services 2014-01-13 01:50:54 -05:00
Joshua Sherman
d289d592ff Added new dependencies to the travis config.
Memcache, memcached and redis have to be loaded to be able to test.
2014-01-13 01:44:23 -05:00
Joshua Sherman
f160daabe7 Whoops, duped a class before commiting 2014-01-13 01:41:09 -05:00
Joshua Sherman
35d03eb719 Finished up session class rework and testing 2014-01-13 01:39:14 -05:00
Joshua Sherman
f1ecc27029 Ripped out the MySQL session handling
Write heavy operations like sessions fare much better in Redis or (sic)
Memcache[d] so I've dropped support for MySQL sessions entirely.
2014-01-13 01:06:07 -05:00
Joshua Sherman
097911a667 Added validation class testing and fixed some bugs
Amazing that there were as many bugs in there as there were.
2014-01-13 00:24:17 -05:00
Joshua Sherman
9a2d593eff Reworked the database class
Got rid of all of that object bloatin’ nonsense.
2014-01-12 23:24:41 -05:00
Joshua Sherman
7fc38398eb Forgot to include these. 2014-01-12 22:06:34 -05:00
Joshua Sherman
10a05a0a06 Added just enough tests to get all code analyzed
Coverage testing wasn't analyzing files that weren't touched at all. All files
are now included with the exception of the Database files that I'll be
consolidating soon into a single class (no reason to have so many classes
touched just to create a single database object). Aside from that, all classes
are now represented in the coverage report, Sad to go from 80% down to 50% but
oh well, it's for the best!
2014-01-12 22:04:51 -05:00
Joshua Sherman
6120933fce More tests and cleaned up some ancient code
It actually referenced the INI file, lolno.
2014-01-12 21:53:05 -05:00
Joshua Sherman
62133dc1ca Hacking away to get coverage up
Finished up all the low hanging fruit (working the classes I already started
that were just shy of 100% coverage). Just shy of 80% coverage at this point.
2014-01-12 18:20:30 -05:00
Joshua Sherman
38d5b503c8 Dropped debugging and fixed a typo 2014-01-12 17:05:53 -05:00
Joshua Sherman
482e4733ed Renamed the file to echo out to 2014-01-12 16:51:35 -05:00
Joshua Sherman
19566bbf5b Dropped php.ini still debugging location 2014-01-12 16:48:45 -05:00
Joshua Sherman
45e80af300 Adding my own php.ini 2014-01-12 16:45:38 -05:00
Joshua Sherman
08f24a686b More debugging. 2014-01-12 16:40:51 -05:00
Joshua Sherman
377f801c2e Moved it to the before script section (maybe?) 2014-01-12 16:38:21 -05:00
Joshua Sherman
8bbf39089f Added some debugging commands
Trying to figure out where I should be echoing the zend_extension line. On my
local system I slapped it to the bottom of the xdebug conf.d file. Unsure if
that directory and/or file even exist.
2014-01-12 16:35:20 -05:00
Joshua Sherman
796a86f969 Switched to zend_extension 2014-01-12 16:32:24 -05:00
Joshua Sherman
b43b02df83 Building the extension worked, but I didn't cd back 2014-01-12 16:28:26 -05:00
Joshua Sherman
8f3c623e5d Added php-test-helpers to the vendors directory
Seemed easier than trying to figure out how to force the prompt to accept the
unknown IP (perhaps not possible at all as it is part of SSH?). `yes` didn't
work, unfortunately.
2014-01-12 16:25:52 -05:00
Joshua Sherman
ebc9b7fb38 Added yes to command 2014-01-12 16:22:04 -05:00
Joshua Sherman
2357469d5b Added manual install steps
Seems the PECL version of test-helpers isn't up to date. Had to compile it
manually locally and evidently have to do the same on travis-ci until pecl is
updated.
2014-01-12 16:17:55 -05:00
Joshua Sherman
984dfe66cc Added pecl install of test-helpers 2014-01-12 16:13:48 -05:00
Joshua Sherman
8db383601e More tests and 100% coverage achievements!
Also fixed a few minor bugs and reworked Browser class to not use the constant
UNIT_TESTING so I could get the class to 100% coverage. Adds a dependency of
testing_helpers which I believe is available on Travis CI by default. Up to 75%
coverage, w00t w00t!
2014-01-12 16:09:48 -05:00
Joshua Sherman
faaefc1b82 Getting coverage to 100% on these classes
Also found a bug in the Form class that would bork phone numbers with dashes in
them. Even though the Form class is going to go away eventually I wanted to fix
the issue.
2014-01-12 13:56:52 -05:00
Joshua Sherman
5ef3b58f53 Test for img parameters 2014-01-11 19:44:55 -05:00
Joshua Sherman
f9a3311087 More tests for the Gravatar class
Trying to cover all of the bases.
2014-01-11 19:37:47 -05:00
Joshua Sherman
74611b9e74 Added test against alternate default URL 2014-01-11 19:33:34 -05:00
Joshua Sherman
36d86100f9 Fixed up a conditional, added a new Distance test. 2014-01-11 19:19:07 -05:00
Joshua Sherman
2fe3f68fe5 Dropped unnecessary tests 2014-01-11 19:13:34 -05:00
Joshua Sherman
5d7f3a0e5a Added an injectable endpoint
Allows for injecting endpoints to simulate poor responses while still testing
the responses from the actual endpoint.
2014-01-11 19:07:29 -05:00
Joshua Sherman
abe73f66a4 Added better test coverage to the AYAH class 2014-01-11 18:41:27 -05:00
Joshua Sherman
549abca8df Expanded File class testing
Shooting for 100%!
2014-01-11 18:28:14 -05:00
Joshua Sherman
9f3ec38d1a Dropped API Common class
The class didn't provide any value and promised that it would in the future.
Any sort of redundant connection logic should simply be contained in a class
that can be extended and not an API-centric common class. Trying to move away
from all common classes in favor of classes that can be reused in different
parts of the core as well as outside of it.
2014-01-11 18:07:50 -05:00
Joshua Sherman
771c2b59b1 Thinking I got the path worked out 2014-01-11 17:56:29 -05:00
Joshua Sherman
8b04815db6 Fixed path in the command
Had it working on the CLI, forgot to put it into the config
2014-01-11 17:50:43 -05:00
Joshua Sherman
d2cf41ce3b Sorta got it working locally, fingers crossed! 2014-01-11 17:48:35 -05:00
Joshua Sherman
205c0cb0cf More tweakin’ 2014-01-11 17:32:24 -05:00
Joshua Sherman
b838f05ac5 Debugging like a boss 2014-01-11 17:29:29 -05:00
Joshua Sherman
4b12aca2f8 Trying to figure out the pwd 2014-01-11 17:26:43 -05:00
Joshua Sherman
5793db4ce0 Added that ./ 2014-01-11 17:09:41 -05:00
Joshua Sherman
fba57ebeab Yet again... 2014-01-11 16:58:24 -05:00
Joshua Sherman
41a61a4f70 Dropped src, added badges to README 2014-01-11 16:50:25 -05:00
Joshua Sherman
bd143696cb Just trying shit at this point... 2014-01-11 16:46:21 -05:00
Joshua Sherman
972c9087f7 Trying the same in the travis config 2014-01-11 16:41:12 -05:00
Joshua Sherman
028d0ec486 Added ../../ to the src path
Thinking since the src path seems to be relative to the coveralls binary that
I need to go up a few directories to find my src code.
2014-01-11 16:33:51 -05:00
Joshua Sherman
b3c70ecdec Last one, I swear 2014-01-11 16:30:53 -05:00
Joshua Sherman
dcee9e748a More .composers left over 2014-01-11 16:29:09 -05:00
Joshua Sherman
f8d44618d2 Fixed composer path in bootstrap 2014-01-11 16:25:41 -05:00
Joshua Sherman
04e008c508 Moved composer out of the private directory
Unsure if that's why I couldn't make the file, thinking of perhaps making the
log directory part of the directory structure instead of creating it on the
fly in Travis CI.
2014-01-11 16:23:06 -05:00
Joshua Sherman
4a8260c0eb More path goodness 2014-01-11 16:16:55 -05:00
Joshua Sherman
b9be4b0890 Messing with the paths
Gonna get this working eventually!!
2014-01-11 16:00:49 -05:00
Joshua Sherman
d32bcbd602 Added classes to the coverage src path
Probably want to move to having my source in a src directory but that's not
something I want to do at this time. Checking coverage in ./classes will skip
over the pickles.php file (which I don't necessarily think needs tested) but
also skips over the ./vendors directory which contains some third party stuff
that doesn't have as much test coverage.
2014-01-11 15:53:31 -05:00
Joshua Sherman
82ba7b0873 Added coveralls config 2014-01-11 15:44:27 -05:00
Joshua Sherman
40d7cd2e73 Changed bin path 2014-01-11 15:37:02 -05:00
Joshua Sherman
c31e1b7742 Added coveralls stuff 2014-01-11 15:34:01 -05:00
Joshua Sherman
f3785bfa84 Added some stuff for coveralls
Still fighting with it, will remove the extra package if I find it to be an
unnecessary dependency.
2014-01-10 11:38:05 -05:00
Joshua Sherman
ed5ddf8766 Updated README 2014-01-10 11:19:43 -05:00
Joshua Sherman
8fc726b983 Updated copyright date.
It's a new year, figured it would be nice to get this done before summer time
like most years.
2014-01-05 13:44:25 -05:00
Joshua Sherman
161d0e5051 Stubbed out Profiler tests 2014-01-04 11:33:13 -05:00
Joshua Sherman
bf817d52f4 HTML class tests
Wrote tests and dropped the ol' XHTML "self-closing" tags. Also fixed a bug with closing tags when no content was present.
2014-01-04 10:15:56 -05:00
Joshua Sherman
f0b5bfa459 Form class tests and updates
Still rockin' that XHTML4 nonsense. Updates to HTML5 (sans self closing tags) and added tests.
2014-01-03 23:45:52 -05:00
Joshua Sherman
13e9507b49 Dropped PHP <5.5 in travis. 2014-01-03 19:09:46 -05:00
Joshua Sherman
dd2e6994fa New test classes
Forgot to commit them it seems.
2014-01-03 19:08:53 -05:00
Joshua Sherman
ff226a3cf9 MOAR TESTS
Had to half ass the AYAH test because it was throwing too many errors w/o an actual API key. Testing the error scenarios in the methods themselves and not the results from AYAH.
2014-01-03 19:00:38 -05:00
Joshua Sherman
c87779b9d2 Tests for gravatar class 2014-01-03 18:17:06 -05:00
Joshua Sherman
0cb3489054 Added back 5.4 and 5.3 as acceptable failures.
Don't really need them but figured why the hell not.
2014-01-03 17:53:49 -05:00
Joshua Sherman
ff44cd0e17 Cleaned up longhand arrays, added Profanity tests 2014-01-03 17:52:24 -05:00
Joshua Sherman
5678e75fbd Tinychat API has been dropped, dropping class. 2014-01-03 17:46:45 -05:00
Joshua Sherman
967f4c1e64 Added HHVM to testing 2014-01-03 13:16:11 -05:00
Joshua Sherman
6e9736f030 Finished up tests for Dynamic class
Switched closure compiler to a composer version for ease of use when doing CI testing
2014-01-03 00:22:58 -05:00
Joshua Sherman
17752f71b3 More composer stuff, updated compile / minify logic
Now using composer installed apps for less and scss files.
2014-01-02 22:39:19 -05:00
Joshua Sherman
bfa35794b5 Cleaned up old code and wrote more tests
Log class is fully tested, Dynamic class is nearly complete but I wanted to see what Travis would bark about regarding LESS and SASS
2014-01-02 18:16:15 -05:00
Joshua Sherman
3fee938c2a Stubbed out and wrote some tests
Will code tests for the stub files in the AM.
2014-01-02 01:17:25 -05:00
Joshua Sherman
5308f4ea6c Number and File class tests 2014-01-02 00:56:20 -05:00
Joshua Sherman
e9456600a7 Sort and Time class tests 2014-01-02 00:09:58 -05:00
Joshua Sherman
007ebef6e6 Distance class tests 2014-01-01 23:03:08 -05:00
Joshua Sherman
2f0472fbf3 Browser class tests 2014-01-01 22:37:05 -05:00
Joshua Sherman
6ff2889270 Moved testing TODO 2013-12-31 12:51:26 -05:00
Joshua Sherman
7a4f992210 Added TODO and new tests
Catching up the existing tests to include any new functionality that hasn't had a test written yet.
2013-12-31 11:08:19 -05:00
Joshua Sherman
9b1feda909 Added support for custom maintenance templates. 2013-12-31 10:56:31 -05:00
Joshua Sherman
5a15c791c5 Finished up Controller tests for existing functionality 2013-12-31 10:39:21 -05:00
Joshua Sherman
efa8f77eba More tests 2013-12-30 23:29:52 -05:00
Joshua Sherman
ec4d771440 Expanded sanity check to hopefully pass tests
Travis is failing and barking about an undefined index "cache". Found the one place I'm referencing it without checking it first and added an isset(). Not failing locally so perhaps it's an issue with PHP 5.5.6 in comparison to 5.5.7 or some other nuance I'm not aware of.
2013-12-30 18:11:42 -05:00
Joshua Sherman
c0dbb39bda More tests
Also, found that damn newline that was being output.
2013-12-30 17:13:22 -05:00
Joshua Sherman
64dc006b5f Documented some stuff, refactoring some other stuff
Moved re-used object instances to the Object class and added object loader logic to the constructor.
2013-12-30 15:47:13 -05:00
Joshua Sherman
74f0adb4f8 Disabled some tests as I figure out the issue, detroyed 5.4 support. 2013-12-30 00:46:29 -05:00
Joshua Sherman
54471c361b So much refactoring... 2013-12-30 00:38:13 -05:00
Joshua Sherman
03e613d380 Reworked README a bit to include PHP 5.4+
... for now, muahahahahaha
2013-12-29 13:32:23 -05:00
Joshua Sherman
7f37abc527 Cleaned up test includes a bit
Probably want to include an autoloader at some point. Also added PHP 5.3 and 5.4 to the test list, 5.3 outta fail, unsure about 5.4
2013-12-29 13:16:21 -05:00
Joshua Sherman
19a211cf6a More refactoring, ditching old code
Added a new 404 system which checks for templates/__shared/404.phtml (module-less bare in mind) and falls back to a generic Apache-ish Not found page with PICKLES shout out. Added some more assumptions (login page is always /login a/k/a the login.php module) also there's no way to customize which template is used for the 404. Removed some code that was no longer used in the Security class.
2013-12-29 12:52:13 -05:00
Joshua Sherman
09d1744910 Refactoring old code
More like removing old code. Added some memento notes for myself in there.
2013-12-28 18:41:56 -05:00
Joshua Sherman
6a1056306f Dropped old Display classes
RSS isn't ported yet but I have a copy to work from
2013-12-28 16:26:12 -05:00
Joshua Sherman
064b4d9f55 Reworked Controller around new Display class 2013-12-28 16:23:42 -05:00
Joshua Sherman
4c0632cb4c Cleaned up whitespace 2013-12-28 16:23:27 -05:00
Joshua Sherman
a050c7d031 Hacked in some public variables
Very hacky, switched variables to public and added a catch in the __get method to assign to the right place for the variables that modules are using (instead of having to update all of the modules in the wild)
2013-12-28 16:22:22 -05:00
Joshua Sherman
a4bf33cce2 If no request, assume 'home' module
Eliminates the need to define a default module in the config.
2013-12-28 16:21:24 -05:00
Joshua Sherman
e0228a9e8a Updated to use composer.json
Throwing errors about my command, figured it's best to just use the same thing I'm using locally. Really hope that this is something that can be done.
2013-12-28 02:09:53 -05:00
Joshua Sherman
e70f31c711 Moved to composer installed vfsSteam
Seems the issue was namespacing this whole time.
2013-12-28 02:08:10 -05:00
Joshua Sherman
fd157c23bc Just a bit more... 2013-12-28 01:54:21 -05:00
Joshua Sherman
054ac575e1 Debugging stuff 2013-12-28 01:52:00 -05:00
Joshua Sherman
a1d9f87a4f More tweaking. 2013-12-28 01:49:52 -05:00
Joshua Sherman
5d14f78d29 More hacking to get vfsStream to load in Travis 2013-12-28 01:44:30 -05:00
Josh Sherman
2dad337c8d Fixed composer require command 2013-12-28 01:39:33 -05:00
Josh Sherman
6b0fed32c6 Added dependencies
Added a hack to work locally for me. May move to using composer to obtain / install vfsStream just didn't like the "vendor" directory, will look into using a custom directory so it can be hidden git ignored.
2013-12-28 01:36:08 -05:00
Josh Sherman
7c4e939e6e Added status image and proper script in config
Expecting a failure due to PEAR dependencies failing.
2013-12-28 01:24:16 -05:00
Josh Sherman
6bca74f155 Added travis config 2013-12-28 01:17:00 -05:00
Josh Sherman
07a95a7508 Built out new Display class with tests
Not hooked up to the Controller yet, wanted to get Travis setup.
2013-12-28 01:13:02 -05:00
Josh Sherman
99a04865e8 Fixed existing tests
Just some small tweaks to get all of the tests passing again. Functionality changed and the tests were not kept up to date.
2013-12-26 15:01:05 -05:00
Josh Sherman
408f3cdfa3 Merge branch 'master' of github.com:joshtronic/pickles 2013-12-24 17:38:51 -05:00
Josh Sherman
89dabbf7f5 Fixed case sensitivity issue.
When developing on OS X the case sensitivity didn't matter much but on Linux it broke the include.
2013-12-24 17:36:10 -05:00
Josh Sherman
ae66815cb9 Hacked in pretty JSON option
Just need to include `?pretty=true` to a request and the JSON returned will be formatted. As I was digging in there I think I may consolidate all of the Display logic into a single class and potentially bring back `.json` and `.xml` extensions to dictate what is returned. Would help a ton in scenarios where I have an endpoint that I want to server up a template on error or return JSON on success.
2013-12-24 14:17:03 -05:00
Josh Sherman
cce87a104e Stated intentions for being bleeding edge. 2013-12-24 13:59:21 -05:00
Josh Sherman
9b297f3d87 Dropped Convert::toJSON()
In an effort to only maintain compatibility with the latest version of PHP (currently the 5.5 branch) I dropped the sanity checks if `json_encode` was available as it is always available in PHP 5.2+. Dropping this sanity check also allowed me to remove the wrapper function and the `JSON_AVAILABLE` constant. Ideally I'd like to move towards dropping the `Convert` class entirely but will need a way to convert an array to XML as the `RSS` class still leverages it. One thought is to move that code right into the `RSS` class as it never gets used elsewhere because XML is gross.
2013-12-24 13:28:49 -05:00
87 changed files with 4899 additions and 11499 deletions

1
.coveralls.yml Normal file
View file

@ -0,0 +1 @@
service_name: travis-ci

3
.gitignore vendored
View file

@ -5,7 +5,10 @@
##########################
.*
!.gitignore
!.travis.yml
!.coveralls.yml
*~
vendor
# Global/OSX.gitignore #
########################

39
.travis.yml Normal file
View file

@ -0,0 +1,39 @@
language: php
php:
- 5.4
- 5.5
- 5.6
- hhvm
matrix:
allow_failures:
- php: hhvm
branches:
only:
- master
- 2.0
- 1.9
services:
- memcache
- memcached
- redis
install:
- composer self-update
- composer install
before_script:
- ./tests/travis.sh
- mysql -e "create database IF NOT EXISTS test;" -u root
- mysql test < tests/schema.sql -u root
- mkdir -p build/logs
- phpenv rehash
script:
- phpunit --coverage-clover /home/travis/build/joshtronic/pickles/build/logs/clover.xml
after_success:
- php vendor/bin/coveralls --config ../.coveralls.yml -v

View file

@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2007-2013 Joshua Sherman
Copyright (c) 2007-2014 Josh Sherman
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

View file

@ -1,48 +1,28 @@
# PHP Interface Collection of Killer Libraries to Enhance Stuff
# Pickles
## What is PICKLES?
[![License](http://img.shields.io/packagist/l/joshtronic/pickles.svg?style=flat)][packagist]
[![Build](http://img.shields.io/travis/joshtronic/pickles.svg?style=flat)][travis]
[![Coverage](http://img.shields.io/coveralls/joshtronic/pickles.svg?style=flat)][coveralls]
[![Downloads](http://img.shields.io/packagist/dt/joshtronic/pickles.svg?style=flat)][packagist]
PICKLES is an open source framework for the rapid development of web applications.
Pickles f/k/a PICKLES (PHP Interface Collection of Killer Libraries to Enhance
Stuff) is an open source framework for the rapid development of RESTful
services. The intention of this framework is to allow developers to a means to
develop service-oriented backend systems that are completely decoupled from the
front end components. Thus allowing the freedom to build the front end
implementation(s) using whichever tools they choose, be it Ember.js, Angular.js
or some cool new system Ive yet to hear of.
## Okay, but why?
## Thanks
I could have went with any number of existing frameworks, but I opted to build my own because I like to code. I've built quite a few sites from the ground up over the years, and I wanted to roll that experience into a single system that I could not only use for my sites, but share with the world.
Special thanks to [Geoff Oliver][GeoffOliver] for being a long time user and
contributor, [Justin Davis][JustinDavis] for romanticizing the v2 reimagining
and [Dean Jones][DeanJones] for helping to come up with the original PICKLES v1
acronym.
## Wait, what, it's not MVC?
PICKLES is in fact not a true MVC system and won't be masquerading around as one (yeah, I know, I borrowed some naming conventions). PICKLES does have a main controller that handles incoming page views. The controller loads a module that contains all of the business logic (optionally interacting with data models) and then execution is passed off to the display layer. The display layer gives the user what they asked for (even if they didn't say please). This is how web pages work, and there has never been a reason for me to force PICKLES into the MVC box just for the hell of it.
## Requirements
### Required Software
* Web server (nginx or Apache with mod_rewrite)
* PHP 5.3+
Please note that PICKLES can run on 5.0+ (you may need the PECL JSON library for versions below 5.2) but is heavily field tested on servers running the latest LTS release of Ubuntu (12.04 at the moment) running the latest stable version of PHP in the main repository (which is the 5.3.x branch). nginx is the preferred web server at this point, but PICKLES was deployed to and used on Apache 1.3+ for quite sometime.
### Highly Recommended Software
* PHP 5.2.0+ for native JSON support or PECL JSON 1.2.1
### Optional Software
#### Databases
* MySQL with PDO and PDO_MYSQL drivers
* PostgreSQL with PDO and PDO_PGSQL drivers
* SQLite 3 with PDO and PDO_SQLITE drivers
#### CSS Pre-processors
* node, npm & lessc to compile LESS files
* sass to compile SASS files
## Installation
Installation is quite simple as there is no installer to run, and all server configuration options can be set in your index.php for your site.
1. Download the source http://github.com/joshtronic/pickles/zipball/master (or clone the repository)
2. Place the code anywhere you'd like (that's at least 2 directories up from the root of your website). I recommend using /usr/share/pickles
3. A starter site can be obtained from http://github.com/joshtronic/pickles-starter. It has everything you need to get a site up and running.
4. At this point you should have a very rudimentary site up and running.
[coveralls]: https://coveralls.io/r/joshtronic/pickles
[packagist]: https://packagist.org/packages/joshtronic/pickles
[travis]: http://travis-ci.org/joshtronic/pickles
[DeanJones]: https://github.com/deanproxy
[GeoffOliver]: https://github.com/geoffoliver
[JustinDavis]: http://justindavis.co

View file

@ -1,34 +0,0 @@
<?php
class API_AYAH extends API_Common
{
public static function getHTML()
{
$config = Config::getInstance();
if (!$config->api['ayah'])
{
throw new Exception('Missing API configuration.');
}
$ayah = new AYAH($config->api['ayah']);
return $ayah->getPublisherHTML();
}
public static function isHuman()
{
$config = Config::getInstance();
if (!$config->api['ayah'])
{
throw new Exception('Missing API configuration.');
}
$ayah = new AYAH($config->api['ayah']);
return $ayah->scoreResult();
}
}
?>

View file

@ -1,43 +0,0 @@
<?php
/**
* Common API Class File for PICKLES
*
* PHP version 5
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @author Joshua Sherman <pickles@joshtronic.com>
* @copyright Copyright 2007-2013, Joshua Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @package PICKLES
* @link https://github.com/joshtronic/pickles
*/
/**
* Common API Interface
*
* Parent class that our API interface classes should be extending. Contains
* execution of parental functions but may contain more down the road.
*/
abstract class API_Common extends Object
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
}
/**
* Destructor
*/
public function __destruct()
{
parent::__destruct();
}
}
?>

View file

@ -1,47 +0,0 @@
<?php
/**
* Google Profanity Class File for PICKLES
*
* PHP version 5
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @author Joshua Sherman <pickles@joshtronic.com>
* @copyright Copyright 2007-2013, Joshua Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @package PICKLES
* @link https://github.com/joshtronic/pickles
*/
/**
* Google Profanity API Interface
*/
class API_Google_Profanity extends API_Common
{
/**
* Check
*
* Checks if a word is considered profanity.
*
* @usage API_Google_Profanity::check('fuck'); // returns true
* @param string $word word to check
* @return boolean whether or not the word is profanity
*/
public static function check($word)
{
$response = json_decode(file_get_contents('http://www.wdyl.com/profanity?q=' . $word), true);
if ($response == null || !isset($response['response']) || !in_array($response['response'], array('true', 'false')))
{
throw new Exception('Invalid response from API.');
}
else
{
return $response['response'] == 'true';
}
}
}
?>

View file

@ -1,98 +0,0 @@
<?php
/**
* Gravatar Class File for PICKLES
*
* PHP version 5
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @author Joshua Sherman <pickles@joshtronic.com>
* @copyright Copyright 2007-2013, Joshua Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @package PICKLES
* @link https://github.com/joshtronic/pickles
*/
/**
* Gravatar API Interface
*
* @link http://en.gravatar.com/site/implement/
*/
class API_Gravatar extends API_Common
{
/**
* Hash
*
* Generates a hash from the passed string that can then be used for
* fetching an image or profile from Gravatar.com
*
* @static
* @param string $string string to hash, should be an email address
* @return string resulting hash
*/
public static function hash($string)
{
// Trims whitespace, lowers the case then applies MD5
return md5(strtolower(trim($string)));
}
/**
* img
*
* Generates an img tag requesting a Gravatar based on the parameters.
*
* @static
* @param string $email address to use for the hash
* @param integer $size optional size of the image requested
* @param string $default optional default style or image to generate
* @param string $rating optional filter by a certain rating
* @param boolean $force optional force the default avatar
* @param boolean $secure optional whether to use the SSL URL
* @param array $attributes optional any additional parameters to include
* @return string an img tag requesting a Gravatar
*/
public static function img($email, $size = 80, $default = 'gravatar', $rating = 'g', $force = false, $secure = false, $attributes = false)
{
if (!filter_var($email, FILTER_VALIDATE_EMAIL))
{
throw new Exception('Invalid email address.');
}
elseif ($size < 1 || $size > 2048)
{
throw new Exception('Invalid size parameter, expecting an integer between 1 and 2048.');
}
elseif (!in_array($default, array('gravatar', '404', 'mm', 'identicon', 'monsterid', 'wavatar', 'retro', 'blank')) && !filter_var($default, FILTER_VALIDATE_URL))
{
throw new Exception('Invalid default parameter, expecting gravatar, 404, mm, identicon, monsterid, wavatar, retro, blank or a valid URL.');
}
elseif (!in_array($rating, array('g', 'pg', 'r', 'x')))
{
throw new Exception('Invalid rating perameter, expecting g, pg, r or x.');
}
else
{
$default = $default == 'gravatar' ? false : urlencode($default);
$html = '<img src="'
. ($secure ? 'https://secure' : 'http://www') . '.gravatar.com/avatar/' . self::hash($email)
. sprintf('?s=%s&d=%s&r=%s', $size, urlencode($default), $rating, $force)
. ($force ? '&f=y' : '') . '"';
if (is_array($attributes))
{
foreach ($attributes as $attribute => $value)
{
$html .= sprintf(' %s="%s"', $attribute, $value);
}
}
$html .= '>';
return $html;
}
}
}
?>

View file

@ -1,185 +0,0 @@
<?php
/**
* Tinychat Class File for PICKLES
*
* PHP version 5
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @author Joshua Sherman <pickles@joshtronic.com>
* @copyright Copyright 2007-2013, Joshua Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @package PICKLES
* @link https://github.com/joshtronic/pickles
*/
/**
* Tinychat API Interface
*
* @link http://tinychat.com/developer/docs
*/
class API_Tinychat extends API_Common
{
/**
* Public Key
*
* @access private
* @var string
*/
private $public_key = null;
/**
* Secret Key
*
* @access private
* @var string
*/
private $secret_key = null;
/**
* Constructor
*
* Assigns our public and secret keys from the configuration.
*/
public function __construct()
{
parent::__construct();
if (isset($this->config->api['tinychat'], $this->config->api['tinychat']['public_key'], $this->config->api['tinychat']['secret_key']))
{
$this->public_key = $this->config->api['tinychat']['public_key'];
$this->secret_key = $this->config->api['tinychat']['secret_key'];
}
else
{
throw new Exception('Unable to load TinyChat configuration.');
}
}
/**
* Execute
*
* Constructs a valid API call, executes it and returns the results.
*
* @param string $codephrase name of the API call being called
* @param string $authentication post-codephrase portion of the auth string
* @param array $parameters key / value pairs for additional data
* @return array results of the API call
*/
private function execute($codephrase, $authentication, $parameters = null)
{
// Assembles and hashes the authentication token
$authentication = md5($this->secret_key . ':' . $authentication);
// Assembles any additional parameters
$additional = '';
if ($parameters && is_array($parameters))
{
foreach ($parameters as $key => $value)
{
$additional .= '&' . $key . '=' . $value;
}
}
// Executes the API call
$results = file_get_contents('http://tinychat.apigee.com/' . $codephrase . '?result=json&key=' . $this->public_key . '&auth=' . $authentication . $additional);
return json_decode($results, true);
}
/**
* List Rooms
*
* Pulls all rooms for the API application.
*
* @return array API results
*/
public function listRooms()
{
return $this->execute('roomlist', 'roomlist');
}
/**
* Room Info
*
* Pulls the information for a room.
*
* @param string $room name of the room
* @param boolean $with_ip whether or not to include users IP addresses
* @return array API results
*/
public function roomInfo($room, $with_ip = false)
{
return $this->execute('roominfo', $room . ':roominfo', array('room' => $room, 'with_ip' => ($with_ip ? 1 : 0)));
}
/**
* Set Room Password
*
* Sets the password for the room, only users with the correct password
* will be able to enter.
*
* @param string $room name of the room
* @param string $password password to use, blank for no password
* @return array API results
*/
public function setRoomPassword($room, $password = '')
{
return $this->execute('setroompassword', $room . ':setroompassword', array('room' => $room, 'password' => $password));
}
/**
* Set Broadcast Password
*
* Sets the password to allow broadcasting in the room. Only users with the
* correct password will be able to broadcast.
*
* @param string $room name of the room
* @param string $password password to use, blank for no password
* @return array API results
*/
public function setBroadcastPassword($room, $password = '')
{
return $this->execute('setbroadcastpassword', $room . ':setbroadcastpassword', array('room' => $room, 'password' => $password));
}
/**
* Generate HTML
*
* Creates the HTML to place a chat on a site.
*
* @todo List params...
* @return array API results
*/
public function generateHTML($room, $join = false, $nick = false, $change = false, $login = false, $oper = false, $owner = false, $bcast = false, $api = false, $colorbk = false, $tcdisplay = false, $autoop = false, $urlsuper = false, $langdefault = false)
{
return '
<script type="text/javascript">
var tinychat = {'
. 'room: "' . $room . '",'
. ($join ? 'join: "auto",' : '')
. ($nick ? 'nick: "' . $nick . '",' : '')
. ($change ? 'change: "none",' : '')
. ($login ? 'login: "' . $login . '",' : '')
. ($oper ? 'oper: "none",' : '')
. ($owner ? 'owner: "none",' : '')
. ($bcast ? 'bcast: "restrict",' : '')
. ($api ? 'api: "' . $api . '",' : '')
. ($colorbk ? 'colorbk: "' . $colorbk . '",' : '')
. ($tcdisplay ? 'tcdisplay: "vidonly",' : '')
/* @todo Implement $autoop, it's an array and needs validated */
. ($urlsuper ? 'urlsuper: "' . $urlsuper . '",' : '')
. ($langdefault ? 'langdefault: "' . $langdefault . '",' : '')
. 'key: "' . $this->public_key . '"'
. '};
</script>
<script src="http://tinychat.com/js/embed.js"></script>
<div id="client"></div>
';
}
}
?>

View file

@ -1,277 +0,0 @@
<?php
/**
* Browser Utility Collection
*
* PHP version 5
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @author Joshua Sherman <pickles@joshtronic.com>
* @copyright Copyright 2007-2013, Joshua Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @package PICKLES
* @link https://github.com/joshtronic/pickles
*/
/**
* Browser Utility Class
*
* Just a simple collection of static functions to accomplish some of the
* more redundant browser-related tasks.
*/
class Browser extends Object
{
/**
* Attributes
*
* Variables passed on the query string as /var:value/
*
* @access private
* @var array
*/
private $attributes = array();
/**
* Get instance of the object
*
* Let's the parent class do all the work
*
* @static
* @param string $class name of the class to instantiate
* @return object self::$instance instance of the Config class
*/
public static function getInstance($class = 'Browser')
{
return parent::getInstance($class);
}
/**
* Set browser variable
*
* Sets a variable in the attributes array for easier access later.
*
* @static
* @param string $variable name of the variable to set
* @param mixed $value the value to set to the variable
* @return boolean true
*/
public static function set($variable, $value)
{
$browser = Browser::getInstance();
$browser->attributes[$variable] = $value;
return true;
}
/**
* Get browser variable
*
* Gets a variable passed in from the browser. Currently only supports
* the custom attribute URI format /$variable:$value/.
*
* @static
* @param string $variable name of the variable to get
* @return mixed the value of the variable or boolean false if not set
*/
public static function get($variable)
{
$browser = Browser::getInstance();
if (isset($browser->attributes[$variable]))
{
return $browser->attributes[$variable];
}
return false;
}
/**
* Go Home
*
* Alias for `Browser::redirect('/');`
*
* @static
*/
public static function goHome()
{
Browser::redirect('/');
}
/**
* Is Mobile
*
* Detects if we're working with a mobile browser.
*
* @return boolean whether or not the browser is considered mobile
*/
public static function isMobile()
{
$user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : null;
return preg_match('/android|avantgo|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i', $user_agent) || preg_match('/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|e\-|e\/|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(di|rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|xda(\-|2|g)|yas\-|your|zeto|zte\-/i', substr($user_agent, 0, 4)) || strpos('iPhone', $user_agent);
}
/**
* Redirect
*
* Redirects the browser to another URL. Stops execution as to not run
* code erroneously due to output buffering. HTTP/1.1 request an
* absolute URI, hence the inclusion of the scheme, hostname and
* absolute path if :// is not found. Don't hate the player, hate the
* RFC.
*
* @static
* @param string $destination URL to redirect to
* @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.30
*/
public static function redirect($destination)
{
if (strpos($destination, '://') === false)
{
$destination = 'http' . ((!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] == 'off' || $_SERVER['HTTPS'] == '') ? '' : 's') . '://' . $_SERVER['HTTP_HOST'] . $destination;
}
header('Location: ' . $destination);
exit;
}
/**
* Remote IP
*
* Returns the user's IP address.
*
* @return mixed IP address or false if unable to determine
*/
public static function remoteIP()
{
if (!empty($_SERVER['HTTP_CLIENT_IP']))
{
$ip = $_SERVER['HTTP_CLIENT_IP'];
}
elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR']))
{
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
}
elseif (isset($_SERVER['REMOTE_ADDR']))
{
$ip = $_SERVER['REMOTE_ADDR'];
}
else
{
$ip = false;
}
return $ip;
}
/**
* Status
*
* Pushes a status code to the browser. Some of these codes are site
* (420) and server (444) specific, some just for LOLs (418) and some
* that are still in draft (425) and subject to change. I wanted this
* to be a complete list and in the scenario that a code had multiple
* meanings, I favored a more recent RFC (424) even if merely a draft
* (451).
*
* @static
* @param integer status response code
*/
public static function status($code = 200)
{
switch ($code)
{
// {{{ 1xx Informational
case 100: $message = '100 Continue'; break;
case 101: $message = '101 Switching Protocols'; break;
case 102: $message = '102 Processing'; break;
// }}}
// {{{ 2xx Success
case 200: $message = '200 OK'; break;
case 201: $message = '201 Created'; break;
case 202: $message = '202 Accepted'; break;
case 203: $message = '203 Non-Authoritative Information'; break;
case 204: $message = '204 No Content'; break;
case 205: $message = '205 Reset Content'; break;
case 206: $message = '206 Partial Content'; break;
case 207: $message = '207 Multi-Status'; break;
case 208: $message = '208 Already Reported'; break;
case 226: $message = '226 IM Used'; break;
// }}}
// {{{ 3xx Redirection
case 300: $message = '300 Multiple Choices'; break;
case 301: $message = '301 Moved Permanently'; break;
case 302: $message = '302 Found'; break;
case 303: $message = '303 See Other'; break;
case 304: $message = '304 Not Modified'; break;
case 305: $message = '305 Use Proxy'; break;
case 306: $message = '306 Switch Proxy'; break;
case 307: $message = '307 Temporary Redirect'; break;
case 308: $message = '308 Permanent Redirect'; break;
// }}}
// {{{ 4xx Client Error
case 400: $message = '400 Bad Request'; break;
case 401: $message = '401 Unauthorized'; break;
case 402: $message = '402 Payment Required'; break;
case 403: $message = '403 Forbidden'; break;
case 404: $message = '404 Not Found'; break;
case 405: $message = '405 Method Not Allowed'; break;
case 406: $message = '406 Not Acceptable'; break;
case 407: $message = '407 Proxy Authentication Required'; break;
case 408: $message = '408 Request Timeout'; break;
case 409: $message = '409 Conflict'; break;
case 410: $message = '410 Gone'; break;
case 411: $message = '411 Length Required'; break;
case 412: $message = '412 Precondition Failed'; break;
case 413: $message = '413 Request Entity Too Large'; break;
case 414: $message = '414 Request-URI Too Long'; break;
case 415: $message = '415 Unsupported Media Type'; break;
case 416: $message = '416 Requested Range Not Satisfied'; break;
case 417: $message = '417 Expectation Failed'; break;
case 418: $message = '418 I\'m a teapot'; break;
case 420: $message = '420 Enhance Your Calm'; break;
case 422: $message = '422 Unprocessed Entity'; break;
case 423: $message = '423 Locked'; break;
case 424: $message = '424 Failed Dependency'; break;
case 425: $message = '425 Unordered Collection'; break;
case 426: $message = '426 Upgrade Required'; break;
case 428: $message = '428 Precondition Required'; break;
case 429: $message = '429 Too Many Requests'; break;
case 431: $message = '431 Request Header Fields Too Large'; break;
case 444: $message = '444 No Response'; break;
case 449: $message = '449 Retry With'; break;
case 450: $message = '450 Blocked by Windows Parental Controls'; break;
case 451: $message = '451 Unavailable for Legal Reasons'; break;
case 494: $message = '494 Request Header Too Large'; break;
case 495: $message = '495 Cert Error'; break;
case 496: $message = '496 No Cert'; break;
case 497: $message = '497 HTTP to HTTPS'; break;
case 499: $message = '499 Client Closed Request'; break;
// }}}
// {{{ 5xx Server Error
case 500: $message = '500 Internal Server Error'; break;
case 501: $message = '501 Not Implemented'; break;
case 502: $message = '502 Bad Gateway'; break;
case 503: $message = '503 Service Unavailable'; break;
case 504: $message = '504 Gateway Timeout'; break;
case 505: $message = '505 HTTP Version Not Supported'; break;
case 506: $message = '506 Variant Also Negotiates'; break;
case 507: $message = '507 Insufficient Storage'; break;
case 508: $message = '508 Loop Detected'; break;
case 509: $message = '509 Bandwidth Limit Exceeded'; break;
case 510: $message = '510 Not Extended'; break;
case 511: $message = '511 Network Authentication Required'; break;
case 598: $message = '598 Network read timeout error'; break;
case 599: $message = '599 Network connect timeout error'; break;
// }}}
default: $message = '200 OK'; break;
}
header('HTTP/1.1 ' . $message, true, $code);
header('Status: ' . $message, true, $code);
}
}
?>

View file

@ -1,281 +0,0 @@
<?php
/**
* Caching System for PICKLES
*
* PHP version 5
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @author Joshua Sherman <pickles@joshtronic.com>
* @copyright Copyright 2007-2013, Joshua Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @package PICKLES
* @link https://github.com/joshtronic/pickles
*/
/**
* Cache Class
*
* Wrapper class for Memcache() to allow for better error handling when the
* Memcached server is unavailable. Designed around the syntax for Memcached()
* to allow for an easier transistion to the aforementioned in the future. I
* don't entirely remember specifics, but the reason for not using Memcached()
* was due to an unexplainable bug in the version in the repository for Ubuntu
* 10.04 LTS. Memcached() does support more of the memcached protocol and will
* eventually be what PICKLES uses. Keys are forced to be uppercase for
* consistencies sake as I've been burned by the case sensitivity due to typos
* in my code.
*
* Requires php5-memcache
*
* @link http://us.php.net/manual/en/book.memcache.php
* @link http://packages.ubuntu.com/lucid/php5-memcache
* @link http://www.memcached.org/
*/
class Cache extends Object
{
/**
* Namespace (prefix)
*
* @access private
* @var string
*/
private $namespace = '';
/**
* Servers
*
* @access private
* @var integer
*/
private $servers = 0;
/**
* Connection resource to Memcached
*
* @access private
* @var object
*/
private $connection = null;
/**
* Constructor
*
* Sets up our connection variables.
*
* @param string $hostname optional hostname to connect to
* @param string $database optional port to use
*/
public function __construct()
{
parent::__construct();
if ($this->config->pickles['cache'])
{
if (!is_array($this->config->pickles['cache']))
{
$datasources = array($this->config->pickles['cache']);
}
else
{
$datasources = $this->config->pickles['cache'];
}
$this->connection = new Memcache();
foreach ($datasources as $name)
{
if (isset($this->config->datasources[$name]))
{
$datasource = $this->config->datasources[$name];
$this->connection->addServer($datasource['hostname'], $datasource['port']);
$this->servers++;
if (isset($datasource['namespace']))
{
$this->namespace = $datasource['namespace'];
}
}
}
}
if ($this->namespace != '')
{
$this->namespace .= '-';
}
}
/**
* Destructor
*
* Closes the connection when the object dies.
*/
public function __destruct()
{
if ($this->servers)
{
$this->connection->close();
}
}
/**
* Get Instance
*
* Let's the parent class do all the work.
*
* @static
* @param string $class name of the class to instantiate
* @return object self::$instance instance of the Cache class
*/
public static function getInstance($class = 'Cache')
{
return parent::getInstance($class);
}
/**
* Get Key
*
* Gets the value of the key(s) and returns it.
*
* @param mixed $keys key(s) to retrieve
* @return mixed value(s) of the requested key(s), false if not set
*/
public function get($keys)
{
set_error_handler('cacheErrorHandler');
if (is_array($keys))
{
foreach ($keys as $index => $key)
{
$keys[$index] = strtoupper($this->namespace . $key);
}
}
else
{
$keys = strtoupper($this->namespace . $keys);
}
try
{
$return = $this->connection->get($keys);
}
catch (Exception $exception)
{
$return = false;
}
restore_error_handler();
return $return;
}
/**
* Set Key
*
* Sets key to the specified value. I've found that compression can lead to
* issues with integers and can slow down the storage and retrieval of data
* (defeats the purpose of caching if you ask me) and isn't supported. I've
* also been burned by data inadvertantly being cached for infinity, but
* have had great success caching data for a full day, hence defaulting the
* expiration to a full day.
*
* @param string $key key to set
* @param mixed $value value to set
* @param integer $expiration optional expiration, defaults to 1 day
* @return boolean status of writing the data to the key
*/
public function set($key, $value, $expire = Time::DAY)
{
set_error_handler('cacheErrorHandler');
$key = strtoupper($key);
try
{
$return = $this->connection->set(strtoupper($this->namespace . $key), $value, 0, $expire);
}
catch (Exception $exception)
{
$return = false;
}
restore_error_handler();
return $return;
}
/**
* Delete Key
*
* Deletes the specified key(s).
*
* @param mixed $keys key(s) to delete
* @return boolean status of deleting the key
*/
public function delete($keys)
{
set_error_handler('cacheErrorHandler');
try
{
if (!is_array($keys))
{
$keys = array($keys);
}
// Memcache() doesn't let you pass an array to delete all records the same way you can with get()
foreach ($keys as $key)
{
$this->connection->delete(strtoupper($this->namespace . $key));
}
$return = true;
}
catch (Exception $exception)
{
$return = false;
}
restore_error_handler();
return $return;
}
/**
* Increment Key
*
* Increments the value of an existing key.
*
* @param string $key key to increment
* @return boolean status of incrementing the key
* @todo Check if it's set as Memcache() doesn't and won't inc if it doesn't exist
*/
public function increment($key)
{
set_error_handler('cacheErrorHandler');
try
{
$return = $this->connection->increment(strtoupper($this->namespace . $key));
}
catch (Exception $exception)
{
$return = false;
}
restore_error_handler();
return $return;
}
}
function cacheErrorHandler($errno, $errstr, $errfile, $errline)
{
throw new Exception($errstr);
}
?>

View file

@ -1,309 +0,0 @@
<?php
/**
* Configuration Class File for PICKLES
*
* PHP version 5
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @author Joshua Sherman <pickles@joshtronic.com>
* @copyright Copyright 2007-2013, Joshua Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @package PICKLES
* @link https://github.com/joshtronic/pickles
*/
/**
* Config Class
*
* Handles loading the site's configuration file (if available). At the moment
* this class is a very skewed Singleton. The plan is to eventually extend this
* out to support multiple configuration files, and the ability to load in
* custom config files on the fly as well. The core of PICKLES uses the class
* as a Singleton so we're not loading the configuration multiple times per
* page load.
*
* @usage <code>$config = new Config($filename);</code>
*/
class Config extends Object
{
/**
* Config data
*
* @access private
* @var array
*/
private $data = array();
/**
* Constructor
*
* Calls the parent constructor and loads the passed file.
*
* @param string $filename optional Filename of the config
*/
public function __construct($filename = null)
{
parent::__construct();
// Try to fine the configuration
if ($filename == null)
{
$filename = 'config.php';
$loaded = false;
$cwd = getcwd();
while ($loaded == false)
{
chdir(dirname($filename));
if (getcwd() == '/')
{
throw new Exception('Unable to load configuration.');
}
chdir($cwd);
$filename = '../' . $filename;
$loaded = $this->load($filename);
}
}
else
{
$this->load($filename);
}
}
/**
* Loads a configuration file
*
* @param string $filename filename of the config file
* @return boolean success of the load process
*/
public function load($filename)
{
$environments = false;
$environment = false;
// Sanity checks the config file
if (file_exists($filename) && is_file($filename) && is_readable($filename))
{
require_once $filename;
// Determines the environment
if (isset($config['environment']))
{
$environment = $config['environment'];
}
else
{
if (isset($config['environments']) && is_array($config['environments']))
{
$environments = $config['environments'];
// If we're on the CLI, check an environment was even passed in
if (IS_CLI == true && $_SERVER['argc'] < 2)
{
throw new Exception('You must pass an environment (e.g. php script.php <environment>)');
}
// Loops through the environments and tries to match on IP or name
foreach ($config['environments'] as $name => $hosts)
{
if (!is_array($hosts))
{
$hosts = array($hosts);
}
// Tries to determine the environment name
foreach ($hosts as $host)
{
if (IS_CLI == true)
{
// Checks the first argument on the command line
if ($_SERVER['argv'][1] == $name)
{
$environment = $name;
break;
}
}
else
{
// Exact match
if ((preg_match('/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/', $host)
&& $_SERVER['SERVER_ADDR'] == $host)
|| $_SERVER['HTTP_HOST'] == $host)
{
$environment = $name;
break;
}
// Fuzzy match
elseif (substr($host,0,1) == '/' && (preg_match($host, $_SERVER['SERVER_NAME'], $matches) > 0 || preg_match($host, $_SERVER['HTTP_HOST'], $matches) > 0))
{
$environments[$name] = $matches[0];
$environment = $name;
$config['environments'][$name] = $matches[0];
break;
}
}
}
}
}
}
// Flattens the array based on the environment
$this->data = $this->flatten($environment, $config);
// Restore environments value
if ($environments != false)
{
$this->data['environments'] = $environments;
}
// Sets the environment if it's not set already
if (!isset($this->data['environment']))
{
$this->data['environment'] = $environment;
}
// Defaults profiler to true if it doesn't match an option exactly
if (isset($this->data['pickles']['profiler']))
{
if ($this->data['pickles']['profiler'] !== true)
{
// If we have an array convert to a string
if (is_array($this->data['pickles']['profiler']))
{
$this->data['pickles']['profiler'] = implode(',', $this->data['pickles']['profiler']);
}
// Checks that one of our known values exists, if not, force true
if (preg_match('/(objects|timers|queries|explains)/', $this->data['pickles']['profiler'] == false))
{
$this->data['pickles']['profiler'] = true;
}
}
}
else
{
$this->data['pickles']['profiler'] = false;
}
// Defaults expected PICKLES options to false
foreach (array('cache', 'logging', 'minify') as $variable)
{
if (!isset($this->data['pickles'][$variable]))
{
$this->data['pickles'][$variable] = false;
}
}
// Creates constants for the security levels
if (isset($this->data['security']['levels']) && is_array($this->data['security']['levels']))
{
foreach ($this->data['security']['levels'] as $value => $name)
{
$constant = 'SECURITY_LEVEL_' . strtoupper($name);
// Checks if constant is already defined, and throws an error
if (defined($constant))
{
throw new Exception('The constant ' . $constant . ' is already defined');
}
else
{
define($constant, $value);
}
}
}
return true;
}
return false;
}
/**
* Flatten
*
* Flattens the configuration array around the specified environment.
*
* @param string $environment selected environment
* @param array $array configuration error to flatten
* @return array flattened configuration array
*/
private function flatten($environment, $array)
{
if (is_array($array))
{
foreach ($array as $key => $value)
{
if (is_array($value))
{
if (isset($value[$environment]))
{
$value = $value[$environment];
}
else
{
$value = $this->flatten($environment, $value);
}
}
$array[$key] = $value;
}
}
return $array;
}
/**
* Get instance of the object
*
* Let's the parent class do all the work
*
* @static
* @param string $class name of the class to instantiate
* @return object self::$instance instance of the Config class
*/
public static function getInstance($class = 'Config')
{
return parent::getInstance($class);
}
/**
* Magic Setter Method
*
* Prohibits the direct modification of module variables.
*
* @param string $name name of the variable to be set
* @param mixed $value value of the variable to be set
*/
public function __set($name, $value)
{
throw new Exception('Cannot set config variables directly', E_USER_ERROR);
}
/**
* Magic Getter Method
*
* Attempts to load the config variable. If it's not set, will override
* the variable with boolean false.
*
* @param string $name name of the variable requested
* @return mixed value of the variable or boolean false
*/
public function __get($name)
{
if (!isset($this->data[$name]))
{
$this->data[$name] = false;
}
return $this->data[$name];
}
}
?>

View file

@ -1,497 +0,0 @@
<?php
/**
* Single Entry Controller
*
* PHP version 5
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @author Joshua Sherman <pickles@joshtronic.com>
* @copyright Copyright 2007-2013, Joshua Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @package PICKLES
* @link https://github.com/joshtronic/pickles
*/
/**
* Controller Class
*
* The heavy lifter of PICKLES, makes the calls to get the session and
* configuration loaded. Loads modules, serves up user authentication when the
* module asks for it, and loads the viewer that the module requested. Default
* values are present to make things easier on the user.
*
* @usage <code>new Controller($config);</code>
*/
class Controller extends Object
{
/**
* Pass Thru
*
* Whether or not the page being loaded is simple a pass thru for an
* internal PICKLES file. The point of this variable is to suppress the
* profiler report in the destructor.
*
* @access private
* @var boolean
*/
private $passthru = false;
/**
* Constructor
*
* To make life a bit easier when using PICKLES, the Controller logic is
* executed automatically via use of a constructor.
*/
public function __construct()
{
parent::__construct();
// Generate a generic "site down" message if the site is set to be disabled
if (isset($this->config->pickles['disabled']) && $this->config->pickles['disabled'] == true)
{
Error::fatal($_SERVER['SERVER_NAME'] . ' is currently<br>down for maintenance');
}
// Checks for attributes passed in the URI
if (strstr($_REQUEST['request'], ':'))
{
$parts = explode('/', $_REQUEST['request']);
$_REQUEST['request'] = '';
foreach ($parts as $part)
{
if (strstr($part, ':'))
{
list($variable, $value) = explode(':', $part);
Browser::set($variable, $value);
}
else
{
$_REQUEST['request'] .= ($_REQUEST['request'] ? '/' : '') . $part;
}
}
}
$_REQUEST['request'] = trim($_REQUEST['request']);
// Checks the passed request for validity
if ($_REQUEST['request'])
{
// Catches requests that aren't lowercase
$lowercase_request = strtolower($_REQUEST['request']);
if ($_REQUEST['request'] != $lowercase_request)
{
header('Location: ' . substr_replace($_SERVER['REQUEST_URI'], $lowercase_request, 1, strlen($lowercase_request)), true, 301);
exit;
}
$request = $_REQUEST['request'];
}
// Loads the default module information if we don't have a valid request
else
{
$request = isset($this->config->pickles['module']) ? $this->config->pickles['module'] : 'home';
}
// Loads the module's information
list($module_class, $module_filename, $template_basename, $css_class, $js_basename) = $this->prepareVariables($request);
unset($request);
$module_exists = (isset($module_filename) && $module_filename != null && file_exists($module_filename));
// Instantiates an instance of the module
if ($module_exists)
{
require_once $module_filename;
// Checks that our class exists
if (class_exists($module_class))
{
$module = new $module_class;
}
else
{
Log::warning('Class named ' . $module_class . ' was not found in ' . $module_filename);
}
}
// If a new module object wasn't created, create a generic one
if (!isset($module))
{
$module = new Module();
}
// Determines if the module is private and should be, well, private
if ($module->private == true)
{
Browser::goHome();
}
// Determines if we need to serve over HTTP or HTTPS
if ($module->secure == false && isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'])
{
Browser::redirect('http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
}
elseif ($module->secure == true && (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] == false))
{
Browser::redirect('https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
}
// Validates security level
if ($module->security !== false)
{
$is_authenticated = false;
if (is_array($module->security))
{
$module_security = $module->security;
$security_check_class = 'isLevel';
// Checks the type and validates it
if (isset($module_security['type']))
{
$security_check_type = strtoupper($module_security['type']);
if (in_array($security_check_type, array('IS', 'HAS', 'BETWEEN')))
{
$security_check_class = $security_check_type;
}
unset($security_check_type, $module_security['type']);
}
$module_security_levels = array();
// If there's a level(s) key use it
foreach (array('level', 'levels') as $security_level_key)
{
if (isset($module_security[$security_level_key]))
{
if (is_array($module_security[$security_level_key]))
{
array_merge($module_security_levels, $module_security[$security_level_key]);
}
else
{
$module_security_levels[] = $module_security[$security_level_key];
}
unset($module_security[$security_level_key]);
}
}
// Assume everything left in the array is a level and add it to the array
array_merge($module_security_levels, $module_security);
$security_level_count = count($module_security_levels);
switch ($security_check_class)
{
case 'BETWEEN':
if ($security_level_count >= 2)
{
$is_authenticated = Security::betweenLevel($module_security_levels[0], array_pop($module_security_levels));
}
break;
case 'HAS':
if ($security_level_count > 0)
{
$is_authenticated = Security::hasLevel($module_security_levels);
}
break;
case 'IS':
if ($security_level_count > 0)
{
$is_authenticated = Security::isLevel($module_security_levels);
}
break;
}
}
else
{
$is_authenticated = Security::isLevel($module->security);
}
if ($is_authenticated == false)
{
if ($_SERVER['REQUEST_METHOD'] == 'POST')
{
exit('{ "status": "error", "message": "You are not properly authenticated" }');
}
else
{
// Sets variable for the destination
$_SESSION['__pickles']['login']['destination'] = $_REQUEST['request'] ? $_REQUEST['request'] : '/';
// Redirect to login page, potentially configured in the config, else /login
Browser::redirect('/' . (isset($this->config->security['login']) ? $this->config->security['login'] : 'login'));
}
}
}
// Validates the rendering engine
$engines = is_array($module->engine) ? array_values($module->engine) : array($module->engine);
$engines = array_combine($engines, $engines);
$engine = current($engines);
// Possibly overrides the engine with the passed return type
if (isset($return_type))
{
$return_type = strtoupper($return_type);
// Validates the return type against the module
if (in_array($return_type, array('JSON', 'RSS', 'XML')) && in_array($return_type, $engines))
{
$engine = $return_type;
}
unset($return_type);
}
// Starts up the display engine
$display_class = 'Display_' . $engine;
$display = new $display_class();
// Assigns the template / template variables
$display->setTemplateVariables($module->template, $template_basename, $css_class, $js_basename, $module->fluid);
// Checks the templates
$template_exists = $display->templateExists();
// If there is no valid module or template, then redirect
if (!$module_exists && !$template_exists)
{
if (!$_REQUEST['request'])
{
Error::fatal('Way to go, you\'ve successfully created an infinite redirect loop. Good thing I was here or you would have been served with a pretty ugly browser error.<br><br>So here\'s the deal, no templates were able to be loaded. Make sure your parent and child templates actually exist and if you\'re using non-default values, make sure they\'re defined correctly in your config.');
}
else
{
$redirect_url = '/';
if (isset($this->config->pickles['404']) && $_REQUEST['request'] != $this->config->pickles['404'])
{
$redirect_url .= $this->config->pickles['404'];
}
header('Location: ' . $redirect_url, 404);
exit;
}
}
// Gets the profiler status
$profiler = $this->config->pickles['profiler'];
$default_method = '__default';
$role_method = null;
if (isset($_SESSION['__pickles']['security']['role']) && !String::isEmpty($_SESSION['__pickles']['security']['role']))
{
$role_method = '__default_' . $_SESSION['__pickles']['security']['role'];
if (method_exists($module, $role_method))
{
$default_method = $role_method;
}
}
// Attempts to execute the default method
if ($default_method == $role_method || method_exists($module, $default_method))
{
if (isset($requested_id))
{
$module->setRequest(array('id' => $requested_id));
}
// Starts a timer before the module is executed
if ($profiler === true || stripos($profiler, 'timers') !== false)
{
Profiler::timer('module ' . $default_method);
}
$valid_request = false;
$valid_security_hash = false;
$error_message = 'An unexpected error has occurred.';
// Determines if the request method is valid for this request
if ($module->method !== false)
{
$methods = (is_array($module->method) ? $module->method : array($module->method));
$request_method = $_SERVER['REQUEST_METHOD'];
foreach ($methods as $method)
{
if ($request_method == strtoupper($method))
{
$valid_request = true;
break;
}
}
if ($valid_request == false)
{
$error_message = 'There was a problem with your request method.';
}
unset($methods, $request_method, $method);
}
else
{
$valid_request = true;
}
// Validates the hash if applicable
if ($valid_request === true && $module->hash !== false)
{
if (isset($_REQUEST['security_hash']))
{
$hash_value = ($module->hash === true ? get_class($module) : $module->hash);
if (Security::generateHash($hash_value) == $_REQUEST['security_hash'])
{
$valid_security_hash = true;
}
else
{
$error_message = 'Invalid security hash.';
}
unset($hash_value);
}
else
{
$error_message = 'Missing security hash';
}
}
else
{
$valid_security_hash = true;
}
$valid_form_input = true;
if ($valid_request === true && $valid_security_hash === true && $module->validate !== false)
{
$validation_errors = $module->__validate();
if ($validation_errors !== false)
{
$error_message = implode(' ', $validation_errors);
$valid_form_input = false;
}
}
/**
* Note to Self: When building in caching will need to let the
* module know to use the cache, either passing in a variable
* or setting it on the object
*/
if ($valid_request && $valid_security_hash && $valid_form_input)
{
$module_return = $module->$default_method();
if (!is_array($module_return))
{
$module_return = $module->return;
}
else
{
$module_return = array_merge($module_return, $module->return);
}
}
$display->setModuleReturn(isset($module_return) ? $module_return : array('status' => 'error', 'message' => $error_message));
unset($error_message);
// Stops the module timer
if ($profiler === true || stripos($profiler, 'timers') !== false)
{
Profiler::timer('module ' . $default_method);
}
// Sets meta data from the module
$display->setMetaData(array(
'title' => $module->title,
'description' => $module->description,
'keywords' => $module->keywords
));
}
// Starts a timer for the display rendering
if ($profiler === true || stripos($profiler, 'timers') !== false)
{
Profiler::timer('display render');
}
// Renders the content
$display->render();
// Steps the display timer
if ($profiler === true || stripos($profiler, 'timers') !== false)
{
Profiler::timer('display render');
}
}
/**
* Destructor
*
* Dumps out the Profiler's report if applicable.
*/
public function __destruct()
{
parent::__destruct();
// Display the Profiler's report is the stars are aligned
if ($this->config->pickles['profiler'] != false && $this->passthru == false)
{
Profiler::report();
}
}
/**
* Prepare Variables
*
* Processes the request variable and creates all the variables that the
* Controller needs to load the page.
*
* @param string $basename the requested page
* @return array the resulting variables
*/
public function prepareVariables($basename)
{
// Sets up all of our variables
$module_class = strtr($basename, '/', '_');
$module_filename = SITE_MODULE_PATH . $basename . '.php';
$template_basename = $basename;
$css_class = $module_class;
$js_basename = $basename;
if (isset($action))
{
$module_class .= '_' . $action;
$template_basename .= '/' . $action;
$css_class .= '_' . $action;
$js_basename .= '/' . $action;
}
// Scrubs class names with hyphens
if (strpos($module_class, '-') !== false)
{
$module_class = preg_replace('/(-(.{1}))/e', 'strtoupper("$2")', $module_class);
}
return array($module_class, $module_filename, $template_basename, $css_class, $js_basename);
}
}
?>

View file

@ -1,153 +0,0 @@
<?php
/**
* Converter
*
* PHP version 5
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @author Joshua Sherman <pickles@joshtronic.com>
* @copyright Copyright 2007-2013, Joshua Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @package PICKLES
* @link https://github.com/joshtronic/pickles
*/
/**
* Convert Class
*
* Collection of statically called methods to help aid in converting data
* formats.
*/
class Convert
{
// {{{ Array to XML
/**
* Array to XML
*
* Converts an array into XML tags (recursive). This method expects the
* passed array to be formatted very specifically to accomodate the fact
* that an array's format isn't quite the same as well-formed XML.
*
* Input Array =
* array('children' => array(
* 'child' => array(
* array('name' => 'Wendy Darling'),
* array('name' => 'John Darling'),
* array('name' => 'Michael Darling')
* )
* ))
*
* Output XML =
* <children>
* <child><name>Wendy Darling</name></child>
* <child><name>John Darling</name></child>
* <child><name>Michael Darling</name></child>
* </children>
*
* @static
* @param array $array array to convert into XML
* @return string generated XML
*/
public static function arrayToXML($array, $format = false, $level = 0)
{
$xml = '';
if (is_array($array))
{
foreach ($array as $node => $value)
{
// Checks if the value is an array
if (is_array($value))
{
foreach ($value as $node2 => $value2)
{
if (is_array($value2))
{
// Nest the value if the node is an integer
$new_value = (is_int($node2) ? $value2 : array($node2 => $value2));
$xml .= ($format ? str_repeat("\t", $level) : '');
$xml .= '<' . $node . '>' . ($format ? "\n" : '');
$xml .= self::arrayToXML($new_value, $format, $level + 1);
$xml .= ($format ? str_repeat("\t", $level) : '');
$xml .= '</' . $node . '>' . ($format ? "\n" : '');
}
else
{
if (is_int($node2))
{
$node2 = $node;
}
// Checks for special characters
if (htmlspecialchars($value2) != $value2)
{
$xml .= ($format ? str_repeat("\t", $level) : '');
$xml .= '<' . $node2 . '><![CDATA[' . $value2 . ']]></' . $node2 . '>' . ($format ? "\n" : '');
}
else
{
$xml .= ($format ? str_repeat("\t", $level) : '');
$xml .= '<' . $node2 . '>' . $value2 . '</' . $node2 . '>' . ($format ? "\n" : '');
}
}
}
}
else
{
// Checks for special characters
if (htmlspecialchars($value) != $value)
{
$xml .= ($format ? str_repeat("\t", $level) : '');
$xml .= '<' . $node . '><![CDATA[' . $value . ']]></' . $node . '>' . ($format ? "\n" : '');
}
else
{
$xml .= ($format ? str_repeat("\t", $level) : '');
$xml .= '<' . $node . '>' . $value . '</' . $node . '>' . ($format ? "\n" : '');
}
}
}
}
return $xml;
}
// }}}
// {{{ To JSON
/**
* To JSON
*
* Encodes passed variable as JSON.
*
* Requires PHP 5 >= 5.2.0 or PECL json >= 1.2.0
*
* @link http://json.org/
* @link http://us.php.net/json_encode
* @link http://pecl.php.net/package/json
*
* @static
* @param mixed $variable variable to convert
* @return JSON encoded string
*/
public static function toJSON($variable)
{
if (JSON_AVAILABLE)
{
return json_encode($variable);
}
else
{
return '{ "status": "error", "message": "json_encode() not found" }';
}
}
// }}}
}
?>

View file

@ -1,131 +0,0 @@
<?php
/**
* Database Class File for PICKLES
*
* PHP version 5
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @author Joshua Sherman <pickles@joshtronic.com>
* @copyright Copyright 2007-2013, Joshua Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @package PICKLES
* @link https://github.com/joshtronic/pickles
*/
/**
* Database Factory
*
* Generic class to simplify connecting to a database. All database objects
* should be created by this class to future proof against any internal changes
* to PICKLES.
*/
class Database extends Object
{
/**
* Constructor
*
* Attempts to get an instance of the passed database type or attempts to
* use a default specified in the config.
*
* @param string $name optional name of the connection to use
*/
public function __construct(String $name = null)
{
parent::__construct();
return Database::getInstance($name);
}
/**
* Get Instance
*
* Looks up the datasource using the passed name and gets an instance of
* it. Allows for easy sharing of certain classes within the system to
* avoid the extra overhead of creating new objects each time. Also avoids
* the hassle of passing around variables (yeah I know, very global-ish)
*
* @static
* @param string $name name of the datasource
* @return object instance of the class
*/
public static function getInstance($name = null)
{
$config = Config::getInstance();
// Checks if we have a default
if ($name == null)
{
// Checks the config for a default
if (isset($config->pickles['datasource']))
{
$name = $config->pickles['datasource'];
}
// Tries to use the first defined datasource
elseif (is_array($config->datasources))
{
$datasources = $config->datasources;
$name = key($datasources);
}
}
// If we have a name try to set up a connection
if ($name != null)
{
if (isset($config->datasources[$name]))
{
$datasource = $config->datasources[$name];
if (!isset($datasource['driver']))
{
return false;
}
$datasource['driver'] = strtolower($datasource['driver']);
if (!isset(self::$instances['Database'][$name]))
{
// Checks the driver is legit and scrubs the name
switch ($datasource['driver'])
{
case 'pdo_mysql': $class = 'PDO_MySQL'; break;
case 'pdo_pgsql': $class = 'PDO_PostgreSQL'; break;
case 'pdo_sqlite': $class = 'PDO_SQLite'; break;
default:
throw new Exception('Datasource driver "' . $datasource['driver'] . '" is invalid');
break;
}
// Instantiates our database class
$class = 'Database_' . $class;
$instance = new $class();
// Sets our database parameters
if (is_array($datasource))
{
foreach ($datasource as $variable => $value)
{
$instance->$variable = $value;
}
}
}
// Caches the instance for possible reuse later
if (isset($instance))
{
self::$instances['Database'][$name] = $instance;
}
// Returns the instance
return self::$instances['Database'][$name];
}
}
return false;
}
}
?>

View file

@ -1,139 +0,0 @@
<?php
/**
* Common Database Class File for PICKLES
*
* PHP version 5
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @author Joshua Sherman <pickles@joshtronic.com>
* @copyright Copyright 2007-2013, Joshua Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @package PICKLES
* @link https://github.com/joshtronic/pickles
*/
/**
* Common Database Abstraction Layer
*
* Parent class that our database driver classes should be extending. Contains
* basic functionality for instantiation and interfacing.
*/
abstract class Database_Common extends Object
{
/**
* Driver
*
* @var string
*/
public $driver = null;
/**
* Hostname for the server
*
* @var string
*/
public $hostname = 'localhost';
/**
* Port number for the server
*
* @var integer
*/
public $port = null;
/**
* UNIX socket for the server
*
* @var integer
*/
public $socket = null;
/**
* Username for the server
*
* @var string
*/
public $username = null;
/**
* Password for the server
*
* @var string
*/
public $password = null;
/**
* Database name for the server
*
* @var string
*/
public $database = null;
/**
* Whether or not to use caching
*
* @var boolean
*/
public $cache = false;
/**
* Connection resource
*
* @var object
*/
public $connection = null;
/**
* Results object for the executed statement
*
* @var object
*/
public $results = null;
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
// Checks the driver is set and available
if ($this->driver == null)
{
throw new Exception('Driver name is not set');
}
else
{
if (extension_loaded($this->driver) == false)
{
throw new Exception('Driver "' . $this->driver . '" is not loaded');
}
}
}
/**
* Open Database Connection
*
* Establishes a connection to the MySQL database based on the configuration
* options that are available in the Config object.
*
* @abstract
* @return boolean true on success, throws an exception overwise
*/
abstract public function open();
/**
* Close Database Connection
*
* Sets the connection to null regardless of state.
*
* @abstract
* @return boolean always true
*/
abstract public function close();
}
?>

View file

@ -1,278 +0,0 @@
<?php
/**
* PDO Class File for PICKLES
*
* PHP version 5
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @author Joshua Sherman <pickles@joshtronic.com>
* @copyright Copyright 2007-2013, Joshua Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @package PICKLES
* @link https://github.com/joshtronic/pickles
*/
/**
* PDO Abstraction Layer
*
* Parent class for any of our database classes that use PDO.
*/
class Database_PDO_Common extends Database_Common
{
/**
* DSN format
*
* @access protected
* @var string
*/
protected $dsn;
/**
* PDO Attributes
*
* @access protected
* @var string
*/
protected $attributes = array(
PDO::ATTR_PERSISTENT => true,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::NULL_EMPTY_STRING => true,
);
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
// Checks that the prefix is set
if ($this->dsn == null)
{
throw new Exception('Data source name is not defined');
}
switch ($this->driver)
{
case 'pdo_mysql':
// Resolves "Invalid UTF-8 sequence" issues when encoding as JSON
// @todo Didn't resolve that issue, borked some other characters though
//$this->attributes[PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET NAMES utf8';
break;
case 'pdo_pgsql':
// This combats a bug: https://bugs.php.net/bug.php?id=62571&edit=1
$this->attributes[PDO::ATTR_PERSISTENT] = false;
// This allows for multiple prepared queries
$this->attributes[PDO::ATTR_EMULATE_PREPARES] = true;
break;
}
}
/**
* Opens database connection
*
* Establishes a connection to the database based on the set configuration
* options.
*
* @return boolean true on success, throws an exception overwise
*/
public function open()
{
if ($this->connection === null)
{
if (isset($this->username, $this->password, $this->database))
{
// Creates a new PDO database object (persistent)
try
{
// Swaps out any variables with values in the DSN
$this->dsn = str_replace(
array('[[hostname]]', '[[port]]', '[[socket]]', '[[username]]', '[[password]]', '[[database]]'),
array($this->hostname, $this->port, $this->socket, $this->username, $this->password, $this->database),
$this->dsn
);
// Strips any empty parameters in the DSN
$this->dsn = str_replace(array('host=;', 'port=;', 'unix_socket=;'), '', $this->dsn);
// Attempts to establish a connection
$this->connection = new PDO($this->dsn, $this->username, $this->password, $this->attributes);
}
catch (PDOException $e)
{
throw new Exception($e);
}
}
else
{
throw new Exception('There was an error loading the database configuration');
}
}
return true;
}
/**
* Closes database connection
*
* Sets the connection to null regardless of state.
*
* @return boolean always true
*/
public function close()
{
$this->connection = null;
return true;
}
/**
* Executes an SQL Statement
*
* Executes a standard or prepared query based on passed parameters. All
* queries are logged to a file as well as timed and logged in the
* execution time is over 1 second.
*
* @param string $sql statement to execute
* @param array $input_parameters optional key/values to be bound
* @return integer ID of the last inserted row or sequence number
*/
public function execute($sql, $input_parameters = null)
{
$this->open();
if ($this->config->pickles['logging'] === true)
{
$loggable_query = $sql;
if ($input_parameters != null)
{
$loggable_query .= ' -- ' . (JSON_AVAILABLE ? json_encode($input_parameters) : serialize($input_parameters));
}
Log::query($loggable_query);
}
$sql = trim($sql);
// Checks if the query is blank
if ($sql != '')
{
$files = array();
// Ubuntu 10.04 is a bit behind on PHP 5.3.x and the IGNORE_ARGS
// constant doesn't exist. To conserve memory, the backtrace will
// Only be used on servers running PHP 5.3.6 or above.
if (version_compare(PHP_VERSION, '5.3.6', '>='))
{
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
krsort($backtrace);
foreach ($backtrace as $file)
{
if (isset($file['class'], $file['line']))
{
$files[] = $file['class'] . ':' . $file['line'];
}
}
}
$sql .= "\n" . '/* [' . implode('|', $files) . '] */';
try
{
// Establishes if we're working on an EXPLAIN
if (Profiler::enabled('explains') == true)
{
$explaining = preg_match('/^EXPLAIN /i', $sql);
$selecting = preg_match('/^SELECT /i', $sql);
}
else
{
$explaining = null;
$selecting = null;
}
// Executes a standard query
if ($input_parameters === null)
{
// Explains the query
if ($selecting == true && $explaining == false)
{
$explain = $this->fetch('EXPLAIN ' . $sql);
}
$start_time = microtime(true);
$this->results = $this->connection->query($sql);
}
// Executes a prepared statement
else
{
// Explains the query
if ($selecting == true && $explaining == false)
{
$explain = $this->fetch('EXPLAIN ' . $sql, $input_parameters);
}
$start_time = microtime(true);
$this->results = $this->connection->prepare($sql);
$this->results->execute($input_parameters);
}
$end_time = microtime(true);
$duration = $end_time - $start_time;
if ($duration >= 1)
{
Log::slowQuery($duration . ' seconds: ' . $loggable_query);
}
// Logs the information to the profiler
if ($explaining == false && Profiler::enabled('explains', 'queries'))
{
Profiler::logQuery($sql, $input_parameters, (isset($explain) ? $explain : false), $duration);
}
}
catch (PDOException $e)
{
throw new Exception($e);
}
}
else
{
throw new Exception('No query to execute');
}
return $this->connection->lastInsertId();
}
/**
* Fetch records from the database
*
* @param string $sql statement to be executed
* @param array $input_parameters optional key/values to be bound
* @param string $return_type optional type of return set
* @return mixed based on return type
*/
public function fetch($sql = null, $input_parameters = null)
{
$this->open();
if ($sql !== null)
{
$this->execute($sql, $input_parameters);
}
// Pulls the results based on the type
$results = $this->results->fetchAll(PDO::FETCH_ASSOC);
return $results;
}
}
?>

View file

@ -1,45 +0,0 @@
<?php
/**
* MySQL Class File for PICKLES
*
* PHP version 5
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @author Joshua Sherman <pickles@joshtronic.com>
* @copyright Copyright 2007-2013, Joshua Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @package PICKLES
* @link https://github.com/joshtronic/pickles
*/
/**
* MySQL Database Abstraction Layer
*/
class Database_PDO_MySQL extends Database_PDO_Common
{
/**
* Driver
*
* @var string
*/
public $driver = 'pdo_mysql';
/**
* DSN format
*
* @var string
*/
public $dsn = 'mysql:host=[[hostname]];port=[[port]];unix_socket=[[socket]];dbname=[[database]]';
/**
* Default port
*
* @var integer
*/
public $port = 3306;
}
?>

View file

@ -1,45 +0,0 @@
<?php
/**
* PostgreSQL Class File for PICKLES
*
* PHP version 5
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @author Joshua Sherman <pickles@joshtronic.com>
* @copyright Copyright 2007-2013, Joshua Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @package PICKLES
* @link https://github.com/joshtronic/pickles
*/
/**
* PostgreSQL Database Abstraction Layer
*/
class Database_PDO_PostgreSQL extends Database_PDO_Common
{
/**
* Driver
*
* @var string
*/
public $driver = 'pdo_pgsql';
/**
* DSN format
*
* @var string
*/
public $dsn = 'pgsql:host=[[hostname]];port=[[port]];dbname=[[database]];user=[[username]];password=[[password]]';
/**
* Default port
*
* @var integer
*/
public $port = 5432;
}
?>

View file

@ -1,38 +0,0 @@
<?php
/**
* SQLite Class File for PICKLES
*
* PHP version 5
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @author Joshua Sherman <pickles@joshtronic.com>
* @copyright Copyright 2007-2013, Joshua Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @package PICKLES
* @link https://github.com/joshtronic/pickles
*/
/**
* SQLite Database Abstraction Layer
*/
class Database_PDO_SQLite extends Database_PDO_Common
{
/**
* Driver
*
* @var string
*/
public $driver = 'pdo_sqlite';
/**
* DSN format
*
* @var string
*/
public $dsn = 'sqlite:[[hostname]]';
}
?>

View file

@ -1,41 +0,0 @@
<?php
/**
* Date Utility Collection
*
* PHP version 5
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @author Joshua Sherman <pickles@joshtronic.com>
* @copyright Copyright 2007-2013, Joshua Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @package PICKLES
* @link https://github.com/joshtronic/pickles
*/
/**
* Date Class
*
* Just a simple collection of static functions to accomplish some of the more
* redundant date related manipulation.
*/
class Date
{
/**
* Age
*
* Calculates age based on the passed date.
*
* @static
* @param string $date birth / inception date
* @return integer $age number of years old
*/
public static function age($date)
{
return Time::age($date);
}
}
?>

View file

@ -1,199 +0,0 @@
<?php
/**
* Common Display Class File for PICKLES
*
* PHP version 5
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @author Joshua Sherman <pickles@joshtronic.com>
* @copyright Copyright 2007-2013, Joshua Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @package PICKLES
* @link https://github.com/joshtronic/pickles
*/
/**
* Common Display Class
*
* This is the parent class class that each display class should be
* extending and executing parent::render()
*/
abstract class Display_Common extends Object
{
/**
* Template Extension
*
* @access protected
* @var string $extension file extension for the template files
*/
protected $extension = null;
/**
* Parent Template
*
* @access protected
* @var string
*/
protected $parent_template = null;
/**
* Child (sub) Template
*
* @access protected
* @var string
*/
protected $child_template = null;
/**
* CSS Class Name
*
* @access protected
* @var string
*/
protected $css_class = '';
/**
* Javascript [Path and] Basename
*
* @access protected
* @var array
*/
protected $js_basename = '';
/**
* Meta Data
*
* @access protected
* @var array
*/
protected $meta_data = null;
/**
* Module Return Data
*
* @access protected
* @var array
*/
protected $module_return = null;
/**
* Constructor
*
* Gets those headers working
*/
public function __construct()
{
parent::__construct();
// Obliterates any passed in PHPSESSID (thanks Google)
if (stripos($_SERVER['REQUEST_URI'], '?PHPSESSID=') !== false)
{
list($request_uri, $phpsessid) = explode('?PHPSESSID=', $_SERVER['REQUEST_URI'], 2);
header('HTTP/1.1 301 Moved Permanently');
header('Location: ' . $request_uri);
exit;
}
else
{
// XHTML compliancy stuff
ini_set('arg_separator.output', '&amp;');
ini_set('url_rewriter.tags', 'a=href,area=href,frame=src,input=src,fieldset=');
header('Content-type: text/html; charset=UTF-8');
}
}
/**
* Set Template
*
* Sets the template file based on passed template type. Adds path and
* extension if applicable.
*
* @param string $template template file's basename
* @param string $type template file's type (either parent or child)
*/
private function setTemplate($template, $type)
{
if ($template != null)
{
$template_name = $type . '_template';
$template_path = SITE_TEMPLATE_PATH . ($type == 'parent' ? '__shared/' : '');
$template_file = $template_path . $template . ($this->extension != false ? '.' . $this->extension : '');
if (file_exists($template_file))
{
$this->$template_name = $template_file;
}
}
}
/**
* Set Template Variables
*
* Sets the variables used by the templates
*
* @param string $parent_template parent template
* @param string $child_template child (sub) template
* @param string $css_class name of the CSS class for the module
* @param string $js_basename basename for the javascript file for the module
* @param boolean $fluid whether or not use a fluid layout
*/
public function setTemplateVariables($parent_template, $child_template, $css_class, $js_basename, $fluid)
{
$this->setTemplate($parent_template, 'parent');
$this->setTemplate($child_template, 'child');
$this->css_class = $css_class;
$this->js_basename = $js_basename;
$this->fluid = $fluid;
}
/**
* Set Meta Data
*
* Sets the meta data from the module so the display class can use it
*
* @param array $meta_data key/value array of data
*/
public function setMetaData($meta_data)
{
$this->meta_data = $meta_data;
}
/**
* Set Module Return
*
* Sets the return data from the module so the display class can display it
*
* @param array $module_return key / value pairs for the data
*/
public function setModuleReturn($module_return)
{
$this->module_return = $module_return;
}
/**
* Template Exists
*
* Checks the templates for validity, not required by every display type so
* the return defaults to true.
*
* @return boolean whether or not the template exists
*/
public function templateExists()
{
return true;
}
/**
* Rendering Method
*
* @abstract
*/
abstract public function render();
}
?>

View file

@ -1,34 +0,0 @@
<?php
/**
* JSON Display Class File for PICKLES
*
* PHP version 5
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @author Joshua Sherman <pickles@joshtronic.com>
* @copyright Copyright 2007-2013, Joshua Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @package PICKLES
* @link https://github.com/joshtronic/pickles
*/
/**
* JSON Display
*
* Displays data in JavaScript Object Notation.
*/
class Display_JSON extends Display_Common
{
/**
* Renders the data in JSON format
*/
public function render()
{
echo Convert::toJSON($this->module_return);
}
}
?>

View file

@ -1,136 +0,0 @@
<?php
/**
* PHP Display Class File for PICKLES
*
* PHP version 5
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @author Joshua Sherman <pickles@joshtronic.com>
* @copyright Copyright 2007-2013, Joshua Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @package PICKLES
* @link https://github.com/joshtronic/pickles
*/
/**
* PHP Display
*
* Displays the associated PHP templates for the Model.
*/
class Display_PHP extends Display_Common
{
/**
* Template Extension
*
* I know there's some controversy amoungst my peers concerning the
* usage of the .phtml extension for these PHP template files. If you
* would prefer .php or .tpl extensions, feel free to void your
* warranty and change it here.
*
* @access protected
* @var string $extension file extension for the template files
*/
protected $extension = 'phtml';
/**
* Template Exists
*
* @return integer the number of templates defined
*/
public function templateExists()
{
if ($this->parent_template != null)
{
return file_exists($this->parent_template) && file_exists($this->child_template);
}
else
{
return file_exists($this->child_template);
}
}
/**
* Renders the PHP templated pages
*/
public function render()
{
if ($this->templateExists())
{
// Starts up the buffer
ob_start();
// Creates (possibly overwritten) objects
$dynamic_class = (class_exists('CustomDynamic') ? 'CustomDynamic' : 'Dynamic');
$form_class = (class_exists('CustomForm') ? 'CustomForm' : 'Form');
$html_class = (class_exists('CustomHTML') ? 'CustomHTML' : 'HTML');
// {{{ Old scope, magic variables
// Puts the class variables in local scope of the template
$__dynamic = new $dynamic_class();
$__form = new $form_class();
$__html = new $html_class();
$__config = $this->config;
$__meta = $this->meta_data;
$__module = $this->module_return;
$__css_class = $this->css_class;
$__js_file = $this->js_basename;
$__fluid = $this->fluid;
// }}}
// {{{ New scope, class variables
$this->dynamic = &$__dynamic;
$this->form = &$__form;
$this->html = &$__html;
$this->meta = &$__meta;
$this->module = &$__module;
$this->js_file = &$this->js_basename;
// }}}
// Loads the template
if ($this->parent_template != null)
{
if ($this->child_template == null)
{
$__template = $this->parent_template;
}
else
{
$__template = $this->child_template;
}
$this->template = $__template;
require_once $this->parent_template;
}
elseif ($this->child_template != null)
{
$__template = $this->child_template;
$this->template = $__template;
require_once $__template;
}
// Grabs the buffer contents and clears it out
$buffer = ob_get_clean();
// Kills any whitespace and HTML comments
$buffer = preg_replace(array('/^[\s]+/m', '/<!--(?:(?!BuySellAds).)+-->/U'), '', $buffer);
// Note, this doesn't exit in case you want to run code after the display of the page
echo $buffer;
}
else
{
echo Convert::toJSON($this->module_return);
}
}
}
?>

View file

@ -1,146 +0,0 @@
<?php
/**
* RSS Display Class File for PICKLES
*
* PHP version 5
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @author Joshua Sherman <pickles@joshtronic.com>
* @copyright Copyright 2007-2013, Joshua Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @package PICKLES
* @link https://github.com/joshtronic/pickles
*/
/**
* RSS Display
*
* Displays data as an RSS formatted XML string.
*/
class Display_RSS extends Display_Common
{
// {{{ Feed Defaults
/**
* RSS Version
*
* @access private
* @var string
*/
private $version = '2.0';
/**
* Date Format
*
* @access private
* @var string
*/
private $date_format = 'r';
// }}}
// {{{ Channel Defaults
/**
* Title
*
* @access private
* @var string
*/
private $title = '';
/**
* Link
*
* @access private
* @var string
*/
private $link = '';
/**
* Description
*
* @access private
* @var string
*/
private $description = '';
/**
* Language
*
* @access private
* @var string
*/
private $language = 'en-us';
/**
* Generator
*
* @access private
* @var string
*/
private $generator = 'https://github.com/joshtronic/pickles';
// }}}
/**
* Renders the data in RSS format
*/
public function render()
{
// Throws off the syntax highlighter otherwise
echo '<' . '?xml version="1.0" ?' . '><rss version="' . $this->version . '"><channel>';
// Loops through the passable channel variables
$channel = array();
foreach (array('title', 'link', 'description', 'language') as $variable)
{
if (isset($this->module_return[$variable]))
{
$this->$variable = $this->module_return[$variable];
}
$channel[$variable] = $this->$variable;
}
$channel['generator'] = $this->generator;
// Loops through the items
$items = '';
$build_date = '';
if (isset($this->module_return['items']) && is_array($this->module_return['items']))
{
foreach ($this->module_return['items'] as $item)
{
// Note: time is the equivalent to pubDate, I just don't like camel case variables
$publish_date = date($this->date_format, is_numeric($item['time']) ? $item['time'] : strtotime($item['time']));
if ($build_date == '')
{
$build_date = $publish_date;
}
if (isset($item['link']))
{
$item['guid'] = $item['link'];
}
$item['pubDate'] = $publish_date;
unset($item['time']);
$items .= Convert::arrayToXML($item);
}
}
$channel['pubDate'] = $build_date;
$channel['lastBuildDate'] = $build_date;
echo Convert::arrayToXML($channel) . $items . '</channel></rss>';
}
}
?>

View file

@ -1,34 +0,0 @@
<?php
/**
* XML Display Class File for PICKLES
*
* PHP version 5
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @author Joshua Sherman <pickles@joshtronic.com>
* @copyright Copyright 2007-2013, Joshua Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @package PICKLES
* @link https://github.com/joshtronic/pickles
*/
/**
* XML Display
*
* Displays data in XML format.
*/
class Display_XML extends Display_Common
{
/**
* Renders the data in XML format
*/
public function render()
{
echo Convert::arrayToXML($this->module_return);
}
}
?>

View file

@ -1,144 +0,0 @@
<?php
/**
* Distance
*
* PHP version 5
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @author Joshua Sherman <pickles@joshtronic.com>
* @copyright Copyright 2007-2013, Joshua Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @package PICKLES
* @link https://github.com/joshtronic/pickles
*/
/**
* Distance Class
*
* Collection of statically called methods to help aid distance-related
* conversions and calculations.
*/
class Distance
{
// {{{ Call Static
/**
* Call Static
*
* Magic method to power the unit conversion without much code.
*
* @static
* @param string $method name of the static method being called
* @param array $arguments array of the passed arguments
* @return mixed converted units or false
*/
public static function __callStatic($method, $arguments)
{
$pieces = explode('to', strtolower($method));
if (count($pieces) == 2)
{
return Distance::convertUnit($arguments[0], $pieces[0], $pieces[1]);
}
return false;
}
// }}}
// {{{ Convert Unit
/**
* Convert Unit
*
* Converts a distance from one unit to another.
*
* @static
* @param mixed $distance starting distance
* @param string $from starting unit
* @param string $to ending unit
* @return mixed
*/
private static function convertUnit($distance, $from, $to)
{
$multiplier = 1;
switch ($from)
{
case 'kilometers':
switch ($to)
{
case 'miles': $multiplier = 0.621371; break;
case 'meters': $multiplier = 1000; break;
case 'yards': $multiplier = 1093.61; break;
}
break;
case 'miles':
switch ($to)
{
case 'kilometers': $multiplier = 1.60934; break;
case 'meters': $multiplier = 1609.34; break;
case 'yards': $multiplier = 1760; break;
}
break;
case 'meters':
switch ($to)
{
case 'kilometers': $multiplier = 0.001; break;
case 'miles': $multiplier = 0.000621371; break;
case 'yards': $multiplier = 1.09361; break;
}
break;
}
return $distance * $multiplier;
}
// }}}
// {{{ Calculate Distance
/**
* Calculate Distance
*
* Calculates the distance between two sets of coordinates and returns the
* requested units. I really wanted to call this distance() but it seems
* you can't do that in PHP due to the backwards compatibility of the
* PHP4 constructors that were named the same as the class.
*
* @static
* @param mixed $latitude_from starting latitude
* @param mixed $longitude_from starting longitude
* @param mixed $latitude_to ending latitude
* @param mixed $longitude_to ending longitude
* @param string $unit optional units to return, miles by default
* @return mixed distance between the points in the desired unit
*/
public static function calculateDistance($latitude_from, $longitude_from, $latitude_to, $longitude_to, $unit = 'miles')
{
$unit = ucwords(strtolower($unit));
$theta = $longitude_from - $longitude_to;
$distance =
sin(deg2rad($latitude_from))
* sin(deg2rad($latitude_to))
+ cos(deg2rad($latitude_from))
* cos(deg2rad($latitude_to))
* cos(deg2rad($theta));
$distance = acos($distance);
$distance = rad2deg($distance);
$miles = $distance * 60 * 1.1515;
$method = 'milesTo' . $unit;
return Distance::$method($miles);
}
// }}}
}
?>

View file

@ -1,299 +0,0 @@
<?php
/**
* Dynamic Content Class File for PICKLES
*
* PHP version 5
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @author Joshua Sherman <pickles@joshtronic.com>
* @copyright Copyright 2007-2013, Joshua Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @package PICKLES
* @link https://github.com/joshtronic/pickles
*/
/**
* Dynamic Class
*
* Handles generating links to static content that are a timestamp injected as
* to avoid hard caching. Also minifies content where applicable.
*
* Note: you will want to add a mod_rewrite line to your .htaccess to support
* the routing to the filenames with the timestamp injected:
*
* RewriteRule ^(.+)\.([\d]+)\.(css|js|gif|png|jpg|jpeg)$ /$1.$3 [NC,QSA]
*/
class Dynamic extends Object
{
/**
* Generate Reference
*
* Appends a dynamic piece of information to the passed reference in the
* form of a UNIX timestamp added to the query string.
*
* @param string $reference URI reference of the file
* @param string $failover URI reference to use if the reference can't be found
* @return string URI reference reference with dynamic content
*/
public function reference($reference, $failover = false)
{
// Checks if the URI reference is absolute, and not relative
if (substr($reference, 0, 1) == '/')
{
$query_string = '';
// Checks for ? and extracts query string
if (strstr($reference, '?'))
{
list($reference, $query_string) = explode('?', $reference);
}
// Adds the dot so the file functions can find the file
$file = '.' . $reference;
if (file_exists($file))
{
// Replaces the extension with time().extension
$parts = explode('.', $reference);
if (count($parts) == 1)
{
throw new Exception('Filename must have an extension (e.g. /path/to/file.png)');
}
else
{
end($parts);
$parts[key($parts)] = filemtime($file) . '.' . current($parts);
$reference = implode('.', $parts);
}
// Adds the query string back
if ($query_string != '')
{
$reference .= '?' . $query_string;
}
}
else
{
if ($failover != false)
{
$reference = $failover;
}
else
{
throw new Exception('Supplied reference does not exist (' . $reference . ')');
}
}
}
else
{
throw new Exception('Reference value must be absolute (e.g. /path/to/file.png)');
}
return $reference;
}
/**
* Generate Stylesheet Reference
*
* Attempts to minify the stylesheet and then returns the reference URI for
* the file, minified or not. Supports LESS and SASS, pass it a .less file
* or a .scss file instead and it will be compiled before minification.
*
* @param string $reference URI reference of the Stylesheet
* @return string URI reference reference with dynamic content
* @url http://lesscss.org
* @url http://sass-lang.com
*/
public function css($original_reference)
{
$less = false;
$sass = false;
// Injects .min into the filename
$parts = explode('.', $original_reference);
if (count($parts) == 1)
{
throw new Exception('Filename must have an extension (e.g. /path/to/file.css)');
}
else
{
end($parts);
switch (current($parts))
{
case 'less':
$less = true;
$parts[key($parts)] = 'css';
break;
case 'scss':
$sass = true;
$parts[key($parts)] = 'css';
break;
}
$parts[key($parts)] = 'min.' . current($parts);
$minified_reference = implode('.', $parts);
}
$original_filename = '.' . $original_reference;
$minified_filename = '.' . $minified_reference;
$path = dirname($original_filename);
if (file_exists($original_filename))
{
$reference = $original_reference;
/**
* Disabled the sanity checks because I'm using LESS's @import for
* some hackery and it's not validating as true due to the imported
* file not being interrogated. Should be okay as minifying is now
* a subjective action that's turned on in the config due to the
* issues I had in production with it.
*
* if (is_writable($path)
* && (!file_exists($minified_filename) || filemtime($original_filename) > filemtime($minified_filename))
* && $this->config->pickles['minify'] === true)
*/
if ($this->config->pickles['minify'] === true)
{
// Compiles LESS & SASS to CSS before minifying
if ($less || $sass)
{
$compiled_filename = str_replace('.min', '', $minified_filename);
if ($less)
{
// I couldn't get getenv() to give me the PATH value... so yeah, there's that.
exec('echo $PATH', $path);
putenv('PATH=' . $path[0] . PATH_SEPARATOR . '/usr/local/bin');
$command = 'lessc ' . $original_filename . ' > ' . $compiled_filename;
}
elseif ($sass)
{
$command = 'sass ' . $original_filename . ':' . $compiled_filename;
}
exec($command, $output, $return);
if ($return !== 0)
{
throw new Exception('There was an error executing `' . $command . '` it returned exit code ' . $return);
}
$original_filename = $compiled_filename;
}
// Minifies CSS with a few basic character replacements.
$stylesheet = file_get_contents($original_filename);
$stylesheet = str_replace(array("\t", "\n", ', ', ' {', ': ', ';}', '{ ', '; '), array('', '', ',', '{', ':', '}', '{', ';'), $stylesheet);
$stylesheet = preg_replace('/\/\*.+?\*\//', '', $stylesheet);
file_put_contents($minified_filename, $stylesheet);
$reference = $minified_reference;
}
elseif (file_exists($minified_filename))
{
$reference = $minified_reference;
}
else
{
Log::warning('Unable to minify ' . $original_reference . ' and a minified copy does not already exist');
}
$reference = $this->reference($reference);
}
else
{
throw new Exception('Supplied reference does not exist');
}
return $reference;
}
/**
* Generate Javascript Reference
*
* Attempts to minify the source with Google's Closure compiler, and then
* returns the reference URI for the file, minified or not.
*
* @link http://code.google.com/closure/compiler/
* @param string $reference URI reference of the Javascript file
* @return string URI reference reference with dynamic content
*/
public function js($original_reference, $level = 'simple')
{
$level = strtoupper($level);
switch ($level)
{
CASE 'WHITESPACE':
CASE 'SIMPLE':
CASE 'ADVANCED':
// Injects .min into the filename
$parts = explode('.', $original_reference);
if (count($parts) == 1)
{
throw new Exception('Filename must have an extension (e.g. /path/to/file.js)');
}
else
{
end($parts);
$parts[key($parts)] = 'min.' . current($parts);
$minified_reference = implode('.', $parts);
}
$original_filename = '.' . $original_reference;
$minified_filename = '.' . $minified_reference;
$path = dirname($original_filename);
if (file_exists($original_filename))
{
$reference = $original_reference;
if (is_writable($path)
&& (!file_exists($minified_filename) || filemtime($original_filename) > filemtime($minified_filename))
&& extension_loaded('curl')
&& $this->config->pickles['minify'] === true)
{
exec('java -jar ' . PICKLES_PATH . 'vendors/google/closure-compiler/compiler.jar --js=' . $original_filename . ' --compilation_level=' . ($level . '_' . ($level == 'WHITESPACE' ? 'ONLY' : 'OPTIMIZATIONS')) . ' --js_output_file=' . $minified_filename);
$reference = $minified_reference;
}
elseif (file_exists($minified_filename))
{
$reference = $minified_reference;
}
else
{
Log::warning('Unable to minify ' . $original_reference . ' and a minified copy does not already exist');
}
$reference = $this->reference($reference);
}
else
{
throw new Exception('Supplied reference does not exist');
}
break;
default:
throw new Exception('The level "' . $level . '" is invalid. Valid levels include "whitespace", "simple" and "advanced"');
break;
}
return $reference;
}
}
?>

View file

@ -1,104 +0,0 @@
<?php
/**
* Error Reporting for PICKLES
*
* PHP version 5
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @author Joshua Sherman <pickles@joshtronic.com>
* @copyright Copyright 2007-2013, Joshua Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @package PICKLES
* @link https://github.com/joshtronic/pickles
*/
/**
* Error Class
*
* Standardized error reporting, mostly used to display fatal errors.
*/
class Error
{
/**
* Fatal Error
*
* Displays a friendly error to the user via HTML, logs it then exits.
*
* @static
* @param string $message the message to be displayed to the user
*/
public static function fatal($message)
{
$config = Config::getInstance();
if ($config->pickles['logging'] === true)
{
if (Log::error($message) == false)
{
$message .= '<br><br>This error message could not be logged as the log path or log file is not writable';
}
}
?>
<!DOCTYPE html>
<html>
<head>
<title><?php echo $_SERVER['SERVER_NAME']; ?> - error</title>
<style>
html
{
background: #eee;
font-family: "Lucida Sans", "Lucida Grande", "Lucida Sans Unicode", Verdana, Arial, sans-serif;
width: 100%;
height: 100%;
font-size: 1em;
}
body
{
text-align: center;
margin-top: 100px;
}
div
{
font-size: 150%;
color: #600;
text-shadow: 2px 2px 2px #eb8383;
margin: 0;
font-weight: bold;
background: #ff9c9c;
padding: 20px;
border-radius: 20px;
-moz-border-radius: 20px;
-webkit-border-radius: 20px;
width: 550px;
margin: 0 auto;
border: 3px solid #890f0f;
}
h1, a
{
font-size: 70%;
color: #999;
text-decoration: none;
}
a:hover
{
color: #000;
}
</style>
</head>
<body>
<h1><?php echo $_SERVER['SERVER_NAME']; ?></h1>
<div><?php echo $message; ?></div>
<a href="https://github.com/joshtronic/pickles" target="_blank">Powered by PICKLES</a>
</body>
</html>
<?php
exit;
}
}
?>

View file

@ -1,70 +0,0 @@
<?php
/**
* File Utility Collection
*
* PHP version 5
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @author Joshua Sherman <pickles@joshtronic.com>
* @copyright Copyright 2007-2013, Joshua Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @package PICKLES
* @link https://github.com/joshtronic/pickles
*/
/**
* File Class
*
* Just a simple collection of static functions to accomplish some of the more
* redundant file related manipulation.
*/
class File
{
/**
* Remove a Directory, Recursively
*
* Removes a directory by emptying all of the contents recursively and then
* removing the directory, as PHP will not let you rmdir() on ain non-empty
* directory. Use with caution, seriously.
*
* @static
* @param string $directory directory to remove
* @return boolean status of the final rmdir();
*/
public static function removeDirectory($directory)
{
if (substr($directory, -1) != '/')
{
$directory .= '/';
}
// If directory is a directory, read in all the files
if (is_dir($directory))
{
$files = scandir($directory);
// Loop through said files, check for directories, and unlink files
foreach ($files as $file)
{
if (!in_array($file, array('.', '..')))
{
if (is_dir($directory . $file))
{
File::removeDirectory($directory . $file);
}
else
{
unlink($directory . $file);
}
}
}
}
rmdir($directory);
}
}
?>

View file

@ -1,682 +0,0 @@
<?php
/**
* Form Class File for PICKLES
*
* PHP version 5
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @author Joshua Sherman <pickles@joshtronic.com>
* @copyright Copyright 2007-2013, Joshua Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @package PICKLES
* @link https://github.com/joshtronic/pickles
*/
/**
* Form Class
*
* This class contains methods for easily generating form elements. There is a
* heavy focus on select boxes as they have the most overhead for a developer.
*
* @deprecated
*/
class Form extends Object
{
// {{{ Get Instance
/**
* Get Instance
*
* Gets an instance of the Form class
*
* @static
* @param string $class name of the class to get an instance of
* @return object instance of the class
*/
public static function getInstance($class = 'Form')
{
return parent::getInstance($class);
}
// }}}
// {{{ Input
/**
* Input
*
* Generates an input with the passed data.
*
* @param string $name name (and ID) for the element
* @param string $value optional preset value
* @param string $classes optional class names
* @param string $additional optional additional parameters
* @param string $type optional type of input
* @param boolean $checked optional whether the input is checked
* @return string HTML for the input
*/
public function input($name, $value = null, $classes = null, $additional = null, $type = 'text', $checked = false)
{
if ($additional)
{
$additional = ' ' . $additional;
}
if (in_array($type, array('checkbox', 'radio')) && $checked == true)
{
$additional .= ' checked="checked"';
}
if ($value)
{
$additional .= ' value="' . $value . '"';
}
if ($classes)
{
$additional .= ' class="' . $classes . '"';
}
return '<input type="' . $type . '" name="' . $name . '" id="' . $name . '"' . $additional . ' />';
}
// }}}
// {{{ Hidden
/**
* Hidden
*
* Shorthand method to generate a hidden input.
*
* @param string $name name (and ID) for the element
* @param string $value optional preset value
* @param string $classes optional class names
* @param string $additional optional additional parameters
* @return string HTML for the input
*/
public function hidden($name, $value = null, $classes = null, $additional = null)
{
return $this->input($name, $value, $classes, $additional, 'hidden');
}
/**
* Hidden Input
*
* Shorthand method to generate a hidden input.
*
* @deprecated Use hidden() instead
*
* @param string $name name (and ID) for the element
* @param string $value optional preset value
* @param string $classes optional class names
* @param string $additional optional additional parameters
* @return string HTML for the input
*/
public function hiddenInput($name, $value = null, $classes = null, $additional = null)
{
return $this->input($name, $value, $classes, $additional, 'hidden');
}
// }}}
// {{{ Password
/**
* Password
*
* Shorthand method to generate a password input.
*
* @param string $name name (and ID) for the element
* @param string $value optional preset value
* @param string $classes optional class names
* @param string $additional optional additional parameters
* @return string HTML for the input
*/
public function password($name, $value = null, $classes = null, $additional = null)
{
return $this->input($name, $value, $classes, $additional, 'password');
}
/**
* Password Input
*
* Shorthand method to generate a password input.
*
* @deprecated Use password() instead
*
* @param string $name name (and ID) for the element
* @param string $value optional preset value
* @param string $classes optional class names
* @param string $additional optional additional parameters
* @return string HTML for the input
*/
public function passwordInput($name, $value = null, $classes = null, $additional = null)
{
return $this->input($name, $value, $classes, $additional, 'password');
}
// }}}
// {{{ Submit
/**
* Submit
*
* Shorthand method to generate a submit input (button).
*
* @param string $name name (and ID) for the input element
* @param string $value optional preset value
* @param string $classes optional class names
* @param string $additional optional additional parameters
* @return string HTML for the input
*/
public function submit($name, $value = null, $classes = null, $additional = null)
{
return $this->input($name, $value, $classes, $additional, 'submit');
}
/**
* Submit Input
*
* Shorthand method to generate a submit input (button).
*
* @deprecated Use submit() instead
*
* @param string $name name (and ID) for the input element
* @param string $value optional preset value
* @param string $classes optional class names
* @param string $additional optional additional parameters
* @return string HTML for the input
*/
public function submitInput($name, $value = null, $classes = null, $additional = null)
{
return $this->input($name, $value, $classes, $additional, 'submit');
}
// }}}
// {{{ Security
/**
* Security
*
* Generates a hidden input with an SHA1 hash as the value. The name of the
* field is cannot be changed as this method was only intended for use with
* forms that are submitted via AJAX to provide better security.
*
* @param string $value value to hash
* @return string HTML for the input
*/
public function security($value)
{
// Returns the hidden input
return $this->hiddenInput('security_hash', Security::generateHash($value));
}
/**
* Security Input
*
* Generates a hidden input with an SHA1 hash as the value. The name of the
* field is cannot be changed as this method was only intended for use with
* forms that are submitted via AJAX to provide better security.
*
* @deprecated Use security() instead
*
* @param string $value value to hash
* @return string HTML for the input
*/
public function securityInput($value)
{
// Returns the hidden input
return $this->hiddenInput('security_hash', Security::generateHash($value));
}
// }}}
// {{{ Checkbox
/**
* Checkbox
*
* Generates a checkbox input with the passed data.
*
* @param string $name name (and ID) for the select element
* @param string $value optional preset value
* @param boolean $checked optional whether the checkbox is checked
* @param string $classes optional class names
* @param string $additional optional additional parameters
* @return string HTML for the input
*/
public function checkbox($name, $value = null, $checked = false, $classes = null, $additional = null)
{
return $this->input($name, $value, $classes, $additional, 'checkbox', $checked);
}
// }}}
// {{{ Checkboxes
// @todo
// }}}
// {{{ Radio Button
/**
* Radio Button
*
* Generates a radio input with the passed data.
*
* @param string $name name (and ID) for the select element
* @param string $value optional preset value
* @param boolean $checked optional whether the checkbox is checked
* @param string $classes optional class names
* @param string $additional optional additional parameters
* @return string HTML for the input
*/
public function radio($name, $value = null, $checked = false, $classes = null, $additional = null)
{
return $this->input($name, $value, $classes, $additional, 'radio', $checked);
}
// }}}
// {{{ Radio Buttons
// @todo
// }}}
// {{{ Text Area
/**
* Textarea
*
* Generates a textarea with the passed data.
*
* @param string $name name (and ID) for the select element
* @param string $value optional preset value
* @param string $classes optional class names
* @param string $additional optional additional parameters
* @param string $type optional type of input
* @return string HTML for the input
*/
public function textarea($name, $value = null, $classes = null, $additional = null)
{
if ($additional)
{
$additional = ' ' . $additional;
}
if ($classes)
{
$additional .= ' class="' . $classes . '"';
}
return '<textarea name="' . $name . '" id="' . $name . '"' . $additional . '>' . $value . '</textarea>';
}
// }}}
// {{{ Select
/**
* Select
*
* Generates a select box with the passed data.
*
* @param string $name name (and ID) for the select element
* @param array $options key/values for the option elements
* @param string $selected optional selected option
* @param string $classes optional class names
* @param string $additional optional additional parameters
* @return string HTML for the select box
*/
public function select($name, $options, $selected = null, $classes = null, $additional = null)
{
if ($additional)
{
$additional = ' ' . $additional;
}
if ($classes)
{
$additional .= ' class="' . $classes . '"';
}
return '<select id="' . $name . '" name="' . $name . '" class="' . $classes . '"' . $additional . '>' . $this->options($options, $selected) . '</select>';
}
// }}}
// {{{ Options
/**
* Options
*
* Generates the option elements from the passed array
*
* @param array $options key/values for the options
* @param string $selected optional default option
* @return string HTML for the options
*/
public function options($options, $selected = null)
{
$found_selected = false;
$options_html = '';
if (is_array($options))
{
foreach ($options as $main_key => $main_label)
{
if (is_array($main_label))
{
$options_html .= '<optgroup label="' . addslashes($main_key) . '">';
foreach ($main_label as $sub_key => $sub_label)
{
$selected_attribute = false;
if ($selected !== null && $found_selected === false)
{
if ($selected == $sub_key)
{
$selected_attribute = ' selected="selected"';
$found_selected = true;
}
}
$options_html .= '<option label="' . addslashes($sub_label) . '" value="' . $sub_key . '"' . $selected_attribute . '>' . $sub_label . '</option>';
}
$options_html .= '</optgroup>';
}
else
{
$selected_attribute = false;
if ($selected !== null && $found_selected === false)
{
if ($selected == $main_key)
{
$selected_attribute = ' selected="selected"';
$found_selected = true;
}
}
$options_html .= '<option label="' . addslashes($main_label) . '" value="' . $main_key . '"' . $selected_attribute . '>' . $main_label . '</option>';
}
}
}
if ($selected !== null && $found_selected === false)
{
$options_html .= '<option value="' . $selected . '" selected="selected" class="error">' . $selected . '</option>';
}
return $options_html;
}
// }}}
// {{{ State Select
/**
* State Select
*
* Generates a select box with the United States, Puerto Rico and miliary
* options
*
* @param string $name optional name (and ID) for the select element
* @param string $selected optional selected option
* @param string $classes optional class names
* @param string $additional optional additional parameters
* @return string HTML for the select box
*/
public function stateSelect($name = 'state', $selected = null, $classes = null, $additional = null)
{
$options = array(
null => '-- Select State --',
'AK' => 'Alaska',
'AL' => 'Alabama',
'AS' => 'American Samoa',
'AZ' => 'Arizona',
'AR' => 'Arkansas',
'CA' => 'California',
'CO' => 'Colorado',
'CT' => 'Connecticut',
'DE' => 'Delaware',
'DC' => 'District of Columbia',
'FL' => 'Florida',
'GA' => 'Georgia',
'GU' => 'Guam',
'HI' => 'Hawaii',
'ID' => 'Idaho',
'IL' => 'Illinois',
'IN' => 'Indiana',
'IA' => 'Iowa',
'KS' => 'Kansas',
'KY' => 'Kentucky',
'LA' => 'Louisiana',
'ME' => 'Maine',
'MH' => 'Marshall Islands',
'MD' => 'Maryland',
'MA' => 'Massachusetts',
'MI' => 'Michigan',
'MN' => 'Minnesota',
'MS' => 'Mississippi',
'MO' => 'Missouri',
'MT' => 'Montana',
'NE' => 'Nebraska',
'NV' => 'Nevada',
'NH' => 'New Hampshire',
'NJ' => 'New Jersey',
'NM' => 'New Mexico',
'NY' => 'New York',
'NC' => 'North Carolina',
'ND' => 'North Dakota',
'MP' => 'Northern Mariana Islands',
'OH' => 'Ohio',
'OK' => 'Oklahoma',
'OR' => 'Oregon',
'PW' => 'Palau',
'PA' => 'Pennsylvania',
'PR' => 'Puerto Rico',
'RI' => 'Rhode Island',
'SC' => 'South Carolina',
'SD' => 'South Dakota',
'TN' => 'Tennessee',
'TX' => 'Texas',
'UT' => 'Utah',
'VT' => 'Vermont',
'VI' => 'Virgin Islands',
'VA' => 'Virginia',
'WA' => 'Washington',
'WV' => 'West Virginia',
'WI' => 'Wisconsin',
'WY' => 'Wyoming',
'AE' => 'Armed Forces Africa',
'AA' => 'Armed Forces Americas (except Canada)',
'AE' => 'Armed Forces Canada',
'AE' => 'Armed Forces Europe',
'AE' => 'Armed Forces Middle East',
'AP' => 'Armed Forces Pacific'
);
return $this->select($name, $options, $selected, $classes, $additional);
}
// }}}
// {{{ Date Select
/**
* Date Select
*
* Generates 3 select boxes (month, day, year)
*
* @param string $name optional name (and ID) for the select element
* @param string $selected optional selected option
* @param string $classes optional class names
* @param string $additional optional additional parameters
* @param integer $start_year optional first year to display
* @param integer $end_year optional last year to display
* @return string HTML for the select boxes
*/
public function dateSelect($name = 'date', $selected = null, $classes = null, $additional = null, $start_year = null, $end_year = null)
{
$html = '';
// Breaks apart the selected value if present
if ($selected == null || $selected == '0000-00-00')
{
$selected_month = null;
$selected_day = null;
$selected_year = null;
}
else
{
list($selected_year, $selected_month, $selected_day) = explode('-', $selected);
}
$month_options = array(
null => 'Month',
'01' => 'January',
'02' => 'February',
'03' => 'March',
'04' => 'April',
'05' => 'May',
'06' => 'June',
'07' => 'July',
'08' => 'August',
'09' => 'September',
'10' => 'October',
'11' => 'November',
'12' => 'December',
);
$day_options = array(null => 'Day');
$year_options = array(null => 'Year');
// Generates the list of days
for ($i = 1; $i <= 31; ++$i)
{
$day_options[str_pad($i, 2, '0', STR_PAD_LEFT)] = $i;
}
// Generates the list of years
$current_year = date('Y');
$start_year = $start_year == null ? $current_year - 10 : $start_year;
$end_year = $end_year == null ? $current_year + 10 : $end_year;
for ($i = $start_year; $i >= $end_year; --$i)
{
$year_options[$i] = $i;
}
// Loops through and generates the selects
foreach (array('month', 'day', 'year') as $part)
{
$options = $part . '_options';
$selected = 'selected_' . $part;
$html .= ' ' . $this->select($name . '[' . $part . ']', $$options, $$selected, $classes, $additional);
}
return $html;
}
// }}}
// {{{ Date of Birth Select
/**
* Date of Birth Select
*
* Generates 3 select boxes (month, day, year)
*
* @param string $name optional name (and ID) for the select element
* @param string $selected optional selected option
* @param string $classes optional class names
* @param string $additional optional additional parameters
* @return string HTML for the select boxes
*/
public function dobSelect($name = 'dob', $selected = null, $classes = null, $additional = null)
{
// Note: Start year based on oldest living person: http://en.wikipedia.org/wiki/Oldest_people as of November 2010
// Note: Start and end year may seem backwards, but we want them in descending order when rendered
return $this->dateSelect($name, $selected, $classes, $additional, date('Y'), 1896);
}
// }}}
// {{{ Polar Select
/**
* Polar Select
*
* Generates a polar (yes / no) select box.
*
* @param string $name optional name (and ID) for the select element
* @param string $selected optional selected option
* @param string $classes optional class names
* @param string $additional optional additional parameters
*/
public function polarSelect($name = 'decision', $selected = 0, $classes = null, $additional = null)
{
$options = array(1 => 'Yes', 0 => 'No');
return $this->select($name, $options, $selected, $classes, $additional);
}
// }}}
// {{{ Phone Input
/**
* Phone Input
*
* Generates 3 inputs for a phone number from the passed values.
*
* @param string $name optional name (and ID) for the input elements
* @param string $value optional existing value
* @param string $classes optional class names
* @param string $additional optional additional parameters
*/
public function phoneInput($name = 'phone', $value = null, $classes = null, $additional = null)
{
if ($value == null)
{
$value = array(
'area_code' => '',
'prefix' => '',
'line_number' => ''
);
}
else
{
$value = array(
'area_code' => substr($value, 0, 3),
'prefix' => substr($value, 3, 3),
'line_number' => substr($value, 6)
);
}
$parts = array(
'area_code' => 3,
'prefix' => 3,
'line_number' => 4
);
if ($additional)
{
$additional = ' ' . $additional;
}
$additional .= ' class="digits';
if ($classes)
{
$additional .= ' ' . $classes;
}
$additional .= '"';
$html = '';
foreach ($parts as $part => $size)
{
$html .= ($html != '' ? ' ' : '');
$html .= '<input type="input" name="' . $name . '[' . $part . ']" id="' . $name . '[' . $part . ']" value="' . $value[$part] . '" minlength="' . $size . '" maxlength="' . $size . '"' . $additional . ' />';
}
return $html;
}
// }}}
}
?>

View file

@ -1,155 +0,0 @@
<?php
/**
* HTML Class File for PICKLES
*
* PHP version 5
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @author Joshua Sherman <pickles@joshtronic.com>
* @copyright Copyright 2007-2013, Joshua Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @package PICKLES
* @link https://github.com/joshtronic/pickles
*/
/**
* HTML Class
*
* This class contains methods for easily generating HTML elements.
*/
class HTML extends Object
{
private $self_closing = array('br', 'hr', 'img', 'input', 'link', 'meta');
public function __call($method, $arguments)
{
$attributes = null;
$contents = null;
if (isset($arguments[0]))
{
$attributes = $arguments[0];
}
if (isset($arguments[1]))
{
$contents = $arguments[1];
}
// ->inputType('name', $attributes);
if (preg_match('/^input/', $method) && !isset($attributes['label']))
{
$type = strtolower(str_replace('input', '', $method));
switch ($type)
{
case 'datetimelocal': $type = 'datetime-local'; break;
case '': $type = 'text'; break;
}
$method = 'input';
if (is_array($attributes))
{
$attributes['type'] = $type;
}
else
{
$attributes = array('type' => $type);
}
}
if (is_array($attributes) && isset($attributes['label']))
{
if (isset($attributes['name']))
{
$label = $this->label(array('for' => $attributes['name']), $attributes['label']);
unset($attributes['label']);
}
else
{
$label = $this->label($attributes['label']);
}
return $label . $this->$method($attributes, $contents);
}
else
{
return $this->element($method, $attributes, $contents);
}
}
// {{{ Get Instance
/**
* Get Instance
*
* Gets an instance of the Form class
*
* @static
* @param string $class name of the class to get an instance of
* @return object instance of the class
*/
public static function getInstance($class = 'HTML')
{
return parent::getInstance($class);
}
// }}}
public function element($element)
{
$attributes = null;
$contents = null;
foreach (func_get_args() as $key => $value)
{
if ($key && $key < 3)
{
if (is_array($value))
{
$attributes = $value;
}
elseif ($value)
{
$contents = $value;
}
}
}
$element = strtolower($element);
$html = '<' . $element;
if ($attributes)
{
if (is_array($attributes))
{
foreach ($attributes as $attribute => $value)
{
$html .= ' ' . $attribute . '="' . str_replace('"', '\"', $value) . '"';
}
}
else
{
throw new Exception('Attributes must be an array.');
}
}
if ($contents || !in_array($element, $this->self_closing))
{
$html .= '>' . $contents . '</' . $element . '>';
}
else
{
$html .= ' />';
}
return $html;
}
}
?>

View file

@ -1,159 +0,0 @@
<?php
/**
* Logging System for PICKLES
*
* PHP version 5
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @author Joshua Sherman <pickles@joshtronic.com>
* @copyright Copyright 2007-2013, Joshua Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @package PICKLES
* @link https://github.com/joshtronic/pickles
*/
/**
* Log Class
*
* Standardized logging methods for ease of reporting.
*/
class Log
{
/**
* Log Information
*
* @static
* @param string $message message to log
* @return boolean whether or not the write was successful
*/
public static function information($message)
{
return self::write('information', $message);
}
/**
* Log Warning
*
* @static
* @param string $message message to log
* @return boolean whether or not the write was successful
*/
public static function warning($message)
{
return self::write('warning', $message);
}
/**
* Log Error
*
* @static
* @param string $message message to log
* @return boolean whether or not the write was successful
*/
public static function error($message)
{
return self::write('error', $message);
}
/**
* Log Slow Query
*
* @static
* @param string $message message to log
* @return boolean whether or not the write was successful
*/
public static function slowQuery($message)
{
return self::write('slow_query', $message);
}
/**
* Log Credit Card Transaction
*
* @static
* @param string $message message to log
* @return boolean whether or not the write was successful
*/
public static function transaction($message)
{
return self::write('transaction', $message);
}
/**
* Log PHP Error
*
* @static
* @param string $message message to log
* @return boolean whether or not the write was successful
*/
public static function phpError($message, $time = false)
{
return self::write('php_error', $message, false, $time);
}
/**
* Log SQL Query
*
* @static
* @param string $message message to log
* @return boolean whether or not the write was successful
*/
public static function query($message)
{
return self::write('query', $message);
}
/**
* Write Message to Log File
*
* @static
* @access private
* @param string $message message to log
* @return boolean whether or not the write was successful
*/
private static function write($log_type, $message, $format = true, $time = false)
{
$config = Config::getInstance();
if ($config->pickles['logging'] === true)
{
$log_path = LOG_PATH . date('Y/m/d/', ($time == false ? time() : $time));
try
{
if (!file_exists($log_path))
{
mkdir($log_path, 0755, true);
}
$log_file = $log_path . $log_type . '.log';
$message .= "\n";
if ($format == true)
{
$backtrace = debug_backtrace();
rsort($backtrace);
$frame = $backtrace[strpos($backtrace[0]['file'], 'index.php') === false ? 0 : 1];
return file_put_contents($log_file, date('H:i:s') . ' ' . str_replace(getcwd(), '', $frame['file']) . ':' . $frame['line'] . ' ' . $message, FILE_APPEND);
}
else
{
return file_put_contents($log_file, $message, FILE_APPEND);
}
}
catch (ErrorException $exception)
{
return false;
}
}
return false;
}
}
?>

File diff suppressed because it is too large Load diff

View file

@ -1,360 +0,0 @@
<?php
/**
* Module Class File for PICKLES
*
* PHP version 5
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @author Joshua Sherman <pickles@joshtronic.com>
* @copyright Copyright 2007-2013, Joshua Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @package PICKLES
* @link https://github.com/joshtronic/pickles
*/
/**
* Module Class
*
* This is a parent class that all PICKLES modules should be extending. Each
* module can specify it's own meta data and whether or not a user must be
* properly authenticated to view the page. Currently any pages without a
* template are treated as pages being requested via AJAX and the return will
* be JSON encoded. In the future this may need to be changed out for logic
* that allows the requested module to specify what display type(s) it can use.
*/
class Module extends Object
{
/**
* Cache Object
*
* @access protected
* @var object
*/
protected $cache = null;
/**
* Database Object
*
* @access protected
* @var object
*/
protected $db = null;
/**
* Fluid or Fixed?
*
* @access protected
* @var boolean
*/
protected $fluid = false;
/**
* Page Title
*
* @access protected
* @var string, null by default
*/
protected $title = null;
/**
* Meta Description
*
* @access protected
* @var string, null by default
*/
protected $description = null;
/**
* Meta Keywords (comma separated)
*
* @access protected
* @var string, null by default
*/
protected $keywords = null;
/**
* Secure
*
* Whether or not the page should be loaded via SSL.
*
* @access protected
* @var boolean, null by default
*/
protected $secure = null;
/**
* Private
*
* Whether or not the page can be accessed directly.
*
* @access protected
* @var boolean, false by default
*/
protected $private = false;
/**
* Security Settings
*
* @access protected
* @var boolean, null by default
*/
protected $security = null;
/**
* Session
*
* Whether or not a session should be established.
*
* @access protected
* @var boolean, null by default
*/
protected $session = null;
/**
* AJAX
*
* Whether or not the module is being called via AJAX. This determines if
* errors should be returned as JSON or if it should use the Error class
* which can be interrogated from within a template.
*
* @access protected
* @var boolean, false (not AJAX) by default
*/
protected $ajax = false;
/**
* Method
*
* Request methods that are allowed to access the module.
*
* @access protected
* @var string or array, null by default
*/
protected $method = null;
/**
* Validate
*
* Variables to validate.
*
* @access protected
* @var array, null by default
*/
protected $validate = null;
/**
* Hash
*
* Whether or not to validate the security hash. Boolean true will indicate
* using the name of the module as the hash, a string value will use the
* value instead.
*
* @access protected
* @var string or boolean, null by default
*/
protected $hash = null;
/**
* Default Display Engine
*
* Defaults to PHP but could be set to JSON, XML or RSS. Value is
* overwritten by the config value if not set by the module.
*
* @access protected
* @var string, null by default
*/
protected $engine = DISPLAY_PHP;
/**
* Default Template
*
* Defaults to null but could be set to any valid template basename. The
* value is overwritten by the config value if not set by the module. The
* display engine determines what the file extension should be.
*
* @access protected
* @var string, 'index' by default
*/
protected $template = 'index';
/**
* Return
*
* Array that is returned to the template in the case of the module not
* returning anything itself. This is somewhat of a one way trip as you
* cannot get the variable unless you reference the return array explicitly
* $this->return['variable']
*
* @access protected
* @var array
*/
protected $return = array();
/**
* Constructor
*
* The constructor does nothing by default but can be passed a boolean
* variable to tell it to automatically run the __default() method. This is
* typically used when a module is called outside of the scope of the
* controller (the registration page calls the login page in this manner.
*
* @param boolean $autorun optional flag to autorun __default()
* @param boolean $valiate optional flag to disable input validation during autorun
*/
public function __construct($autorun = false, $validate = true)
{
parent::__construct();
$this->cache = Cache::getInstance();
$this->db = Database::getInstance();
if ($autorun === true)
{
if ($validate === true)
{
$errors = $this->__validate();
if ($errors !== false)
{
exit('Errors encountered, this is a @todo for form validation when calling modules from inside of modules');
}
}
$this->__default();
}
}
/**
* Default "Magic" Method
*
* This function is overloaded by the module. The __default() method is
* where you want to place any code that needs to be executed at runtime.
* The reason the code isn't in the constructor is because the module must
* be instantiated before the code is executed so that the controller
* script is aware of the authentication requirements.
*/
public function __default()
{
}
/**
* Magic Setter Method
*
* Places the variables that are being modified in the return array that is
* returned if nothing is returned by the module itself. This also prohibits
* the direct modification of module variables which could cause issues.
*
* @param string $name name of the variable to be set
* @param mixed $value value of the variable to be set
*/
public function __set($name, $value)
{
$this->return[$name] = $value;
}
/**
* Magic Getter Method
*
* Attempts to load the module variable. If it's not set, will attempt to
* load from the config.
*
* @param string $name name of the variable requested
* @return mixed value of the variable or boolean false
*/
public function __get($name)
{
if (!isset($this->$name))
{
if (isset($this->config->pickles[$name]))
{
$this->$name = $this->config->pickles[$name];
}
else
{
$this->$name = false;
}
}
return $this->$name;
}
/**
* Sets the Request
*
* @param array $request data to be loaded into the request variable
* @return boolean whether or not the assignment was successful
*/
public function setRequest($request)
{
$backtrace = debug_backtrace();
if ($backtrace[1]['class'] == 'Controller')
{
$this->request = $request;
return true;
}
else
{
throw new Exception('Only Controller can perform setRequest()');
}
}
/**
* Validate
*
* Internal validation for data passed to a Module. Grabs the super global
* based on the Module's request method and loops through the data using the
* Module's validation array (if present) sanity checking each variable
* against the rules.
*
* @return mixed boolean false if everything is fine or an array or errors
*/
public function __validate()
{
$errors = array();
if ($this->validate !== false)
{
switch (strtoupper($this->method))
{
case 'GET': $global = &$_GET; break;
case 'POST': $global = &$_POST; break;
default: $global = &$_REQUEST; break;
}
foreach ($this->validate as $variable => $rules)
{
if (!is_array($rules))
{
$variable = $rules;
$rules = true;
}
if (isset($global[$variable]) && !String::isEmpty($global[$variable]))
{
if (is_array($rules))
{
$rule_errors = Validate::isValid($global[$variable], $rules);
if (is_array($rule_errors))
{
$errors = array_merge($errors, $rule_errors);
}
}
}
else
{
$errors[] = 'The ' . $variable . ' field is required.';
}
}
}
return $errors == array() ? false : $errors;
}
}
?>

View file

@ -1,61 +0,0 @@
<?php
/**
* Number Utility Collection
*
* PHP version 5
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @author Joshua Sherman <pickles@joshtronic.com>
* @copyright Copyright 2007-2013, Joshua Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @package PICKLES
* @link https://github.com/joshtronic/pickles
*/
/**
* Number Class
*
* Just a simple collection of static functions to accomplish some of the more
* redundant numeric related manipulation.
*/
class Number
{
/**
* Ordinal Indiciator
*
* Formats a number by appending an ordinal indicator.
*
* @static
* @link http://en.wikipedia.org/wiki/Ordinal_indicator
* @link http://en.wikipedia.org/wiki/English_numerals#Ordinal_numbers
* @param string $number number to format
* @param boolean $superscript include <sup> tags
* @return string formatted number
*/
public static function ordinalIndicator($number, $superscript = false)
{
$suffix = 'th';
if (!in_array(($number % 100), array(11, 12, 13)))
{
switch ($number % 10)
{
case 1: $suffix = 'st'; break;
case 2: $suffix = 'nd'; break;
case 3: $suffix = 'rd'; break;
}
}
if ($superscript)
{
$suffix = '<sup>' . $suffix . '</sup>';
}
return $number . $suffix;
}
}
?>

View file

@ -1,122 +0,0 @@
<?php
/**
* Object Class File for PICKLES
*
* PHP version 5
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @author Joshua Sherman <pickles@joshtronic.com>
* @copyright Copyright 2007-2013, Joshua Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @package PICKLES
* @link https://github.com/joshtronic/pickles
*/
/**
* Object Class
*
* Every instantiated class in PICKLES should be extending this class. By doing
* so the class is automatically hooked into the profiler, and the object will
* have access to some common components as well.
*/
class Object
{
/**
* Object Instances
*
* @static
* @access private
* @var mixed
*/
protected static $instances = array();
/**
* Instance of the Config object
*
* @access protected
* @var object
*/
protected $config = null;
/**
* Profiler flag
*
*
* @access private
* @var mixed
*/
private $profiler = false;
/**
* Constructor
*
* Establishes a Config instance for all children to enjoy
*/
public function __construct()
{
// Gets an instance of the config, unless we ARE the config
if (get_class($this) == 'Config')
{
$this->config = true;
}
else
{
$this->config = Config::getInstance();
}
// Assigns the profiler flag
$this->profiler = (isset($this->config->pickles['profiler']) && $this->config->pickles['profiler'] != '' ? $this->config->pickles['profiler'] : false);
// Optionally logs the constructor to the profiler
if ($this->profiler === true || ((is_array($this->profiler) && in_array('objects', $this->profiler)) || stripos($this->profiler, 'objects') !== false))
{
Profiler::log($this, '__construct');
}
}
/**
* Get Instance
*
* Gets an instance of the passed class. Allows for easy sharing of certain
* classes within the system to avoid the extra overhead of creating new
* objects each time. Also avoids the hassle of passing around variables.
*
* @static
* @param string $class name of the class
* @return object instance of the class
*/
public static function getInstance($class = false)
{
// In < 5.3 arguments must match in child, hence defaulting $class
if ($class == false)
{
return false;
}
else
{
if (!isset(self::$instances[$class]))
{
self::$instances[$class] = new $class();
}
return self::$instances[$class];
}
}
/**
* Destructor
*/
public function __destruct()
{
// Optionally logs the destructor to the profiler
if ($this->profiler === true || ((is_array($this->profiler) && in_array('objects', $this->profiler)) || stripos($this->profiler, 'objects') !== false))
{
Profiler::log($this, '__destruct');
}
}
}
?>

View file

@ -1,411 +0,0 @@
<?php
/**
* Profiler
*
* PHP version 5
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @author Joshua Sherman <pickles@joshtronic.com>
* @copyright Copyright 2007-2013, Joshua Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @package PICKLES
* @link https://github.com/joshtronic/pickles
*/
/**
* Profiler Class
*
* The Profiler class is statically interfaced with and allows for in depth
* profiling of a site. By default profiling is off, but can be enabled in the
* config.ini for a site. Out of the box the profiler will report on every
* class object in the system that extends the code Object class.
*
* Note: I really wanted to use PHP Quick Profiler by Ryan Campbell of
* Particletree but it kept barking out errors when I tried to use it with
* E_STRICT turned on. Here's a link anyway since it looks awesome:
* http://particletree.com/features/php-quick-profiler/
*
* @usage <code>Profiler::log('some action you want to track');</code>
* @usage <code>Profiler::log($object, 'methodName');</code>
*/
class Profiler
{
/**
* Config
*
* Profiler configuration
*
* @static
* @access private
* @var array
*/
private static $config;
/**
* Profile
*
* Array of logged events
*
* @static
* @access private
* @var array
*/
private static $profile = array();
/**
* Queries
*
* Number of queries that have been logged
*
* @static
* @access private
* @var integer
*/
private static $queries = 0;
/**
* Timers
*
* Array of active timers
*
* @static
* @access private
* @var array
*/
private static $timers = array();
/**
* Constructor
*
* Private constructor since this class is interfaced wtih statically.
*
* @access private
*/
private function __construct()
{
}
/**
* Enabled
*
* Checks if the profiler is set to boolean true or if the passed type is
* specified in the profiler configuration value.
*
* @param array $type type(s) to check
* @return boolean whether or not the type is enabled
*/
public static function enabled(/* polymorphic */)
{
// Grabs the config object if we don't have one yet
if (self::$config == null)
{
$config = Config::getInstance();
self::$config = $config->pickles['profiler'];
}
// Checks if we're set to boolean true
if (self::$config === true)
{
return true;
}
else
{
$types = func_get_args();
foreach ($types as $type)
{
if (stripos(self::$config, $type) !== false)
{
return true;
}
}
}
return false;
}
/**
* Log
*
* Logs the event to be displayed later on. Due to the nature of how much
* of a pain it is to determine which class method called this method I
* opted to make the method a passable argument for ease of use. Perhaps
* I'll revisit in the future. Handles all elapsed time calculations and
* memory usage.
*
* @static
* @param mixed $data data to log
* @param string $method name of the class method being logged
*/
public static function log($data, $method = false, $type = false)
{
$time = microtime(true);
$data_type = ($data == 'timer' ? $data : gettype($data));
// Tidys the data by type
switch ($data_type)
{
case 'array':
$log = '<pre>' . print_r($data, true) . '</pre>';
break;
case 'object':
$log = '<span style="color:#666">[</span><span style="color:#777">' . get_parent_class($data) . '</span><span style="color:#666">]</span> '
. '<span style="color:#69c">' . get_class($data) . '</span>'
. ($method != '' ? '<span style="color:#666">-></span><span style="color:#4eed9e">' . $method . '</span><span style="color:#666">()</span>' : '');
$data_type = '<span style="color:Peru">' . $data_type . '</span>';
break;
case 'timer':
$log = $method;
$data_type = '<span style="color:#6c0">' . $data_type . '</span>';
break;
case 'string':
default:
if ($type != false)
{
$data_type = $type;
}
$log = $data;
break;
}
self::$profile[] = array(
'log' => $log,
'type' => $data_type,
'time' => $time,
'elapsed' => $time - PICKLES_START_TIME,
'memory' => memory_get_usage(),
);
}
/**
* Log Query
*
* Serves as a wrapper to get query data to the log function
*
* @static
* @param string $query the query being executed
* @param array $input_parameters optional prepared statement data
* @param array $explain EXPLAIN data for the query
* @param float $duration the speed of the query
*/
public static function logQuery($query, $input_parameters = false, $explain = false, $duration = false)
{
self::$queries++;
$log = '';
if ($input_parameters != 'false' && is_array($input_parameters))
{
$log .= '<br />';
foreach ($input_parameters as $key => $value)
{
$log .= '<br /><span style="color:#a82222">' . $key . '</span> <span style="color:#666">=></span> <span style="color:#ffff7f">' . $value . '</span>';
$query = str_replace($key, '<span style="color:#a82222">' . $key . '</span>', $query);
}
}
$log = '<span style="color:#009600">' . $query . '</span>' . $log;
if (is_array($explain))
{
$log .= '<br />';
foreach ($explain as $table)
{
$log .= '<br /><span style="color:RoyalBlue">Possible Keys</span> <span style="color:#666">=></span> <span style="color:DarkGoldenRod">' . ($table['possible_keys'] == '' ? '<em style="color:red">NONE</em>' : $table['possible_keys']) . '</span>'
. '<br /><span style="color:RoyalBlue">Key</span> <span style="color:#666">=></span> <span style="color:DarkGoldenRod">' . ($table['key'] == '' ? '<em style="color:red">NONE</em>' : $table['key']) . '</span>'
. '<br /><span style="color:RoyalBlue">Type</span> <span style="color:#666">=></span> <span style="color:DarkGoldenRod">' . $table['type'] . '</span>'
. '<br /><span style="color:RoyalBlue">Rows</span> <span style="color:#666">=></span> <span style="color:DarkGoldenRod">' . $table['rows'] . '</span>'
. ($table['Extra'] != '' ? '<br /><span style="color:RoyalBlue">Extra</span> <span style="color:#666">=></span> <span style="color:DarkGoldenRod">' . $table['Extra'] . '</span>' : '');
}
}
$log .= '<br /><br /><span style="color:DarkKhaki">Speed:</span> ' . number_format($duration * 100, 3) . ' ms';
self::log($log, false, '<span style="color:DarkCyan">database</span>');
}
/**
* Timer
*
* Logs the start and end of a timer.
*
* @param string $timer name of the timer
* @return boolean whether or not timer profiling is enabled
*/
public static function timer($timer)
{
if (self::enabled('timers'))
{
// Starts the timer
if (!isset(self::$timers[$timer]))
{
self::$timers[$timer] = microtime(true);
self::Log('timer', '<span style="color:Orchid">Started timer</span> <span style="color:Yellow">' . $timer . '</span>');
}
// Ends the timer
else
{
self::Log('timer', '<span style="color:Orchid">Stopped timer</span> <span style="color:Yellow">' . $timer . '</span> <span style="color:#666">=></span> <span style="color:DarkKhaki">Time Elapsed:</span> ' . number_format((microtime(true) - self::$timers[$timer]) * 100, 3) . ' ms');
unset(self::$timers[$timer]);
}
return true;
}
return false;
}
/**
* Report
*
* Generates the Profiler report that is displayed by the Controller.
* Contains all the HTML needed to display the data properly inline on the
* page. Will generally be displayed after the closing HTML tag.
*/
public static function report()
{
?>
<style>
#pickles-profiler
{
background: #212121;
width: 800px;
margin: 0 auto;
margin-top: 20px;
margin-bottom: 20px;
-moz-border-radius: 20px;
-webkit-border-radius: 20px;
border-radius: 20px;
-moz-box-shadow: 0 3px 4px rgba(0,0,0,0.5);
-webkit-box-shadow: 0 3px 4px rgba(0,0,0,0.5);
box-shadow: 0 3px 4px rgba(0,0,0,0.5);
border: 6px solid #666;
padding: 10px 20px 20px;
font-family: monospace;
font-size: 12px;
text-align: left;
}
#pickles-profiler table
{
width: 100%;
}
#pickles-profiler table tr th, #pickles-profiler table tr td
{
padding: 10px;
}
#pickles-profiler .even
{
background-color: #323232;
}
#pickles-profiler, #pickles-profiler table tr td, #pickles-profiler table tr th
{
color: #efefe8;
}
</style>
<div id="pickles-profiler">
<strong style="font-size:1.5em">PICKLES Profiler</strong><br /><br />
<?php
if (count(self::$profile) == 0)
{
echo '<em style="line-height:18px">There is nothing to profile. This often happens when the profiler configuration is set to either "queries" or "explains" and there are no database queries on the page (common on pages that only have a template). You may want to set the profiler to boolean true to ensure you get a profile of the page.</em>';
}
else
{
$start_time = PICKLES_START_TIME;
$peak_usage = self::formatSize(memory_get_peak_usage());
$end_time = self::$profile[count(self::$profile) - 1]['time']; // TODO
$duration = ($end_time - $start_time);
$logs = count(self::$profile);
$logs .= ' Log' . ($logs == 1 ? '' : 's');
$files = count(get_included_files());
$files .= ' File' . ($files == 1 ? '' : 's');
$queries = self::$queries . ' Quer'. (self::$queries == 1 ? 'y' : 'ies');
?>
<table style="border-collapse:separate;border-spacing:1px;border-radius:10px;text-shadow:1px 1px 1px #000">
<tr>
<td style="text-align:center;background:#480000">
<span style="font-weight:bold;">Console</span>
<div style="color:#ff7f7f;font-size:1.2em;padding-top:10px"><?php echo $logs; ?></div>
</td>
<td style="text-align:center;background:#552200">
<span style="font-weight:bold;">Load Time</span>
<div style="color:#ffa366;font-size:1.2em;padding-top:10px"><?php echo number_format($duration * 100, 3) . ' ms / ' . ini_get('max_execution_time'); ?></div>
</td>
<td style="text-align:center;background:#545500">
<span style="font-weight:bold;">Memory Usage</span>
<div style="color:#ffff6d;font-size:1.2em;padding-top:10px"><?php echo $peak_usage . ' / ' . ini_get('memory_limit'); ?></div>
</td>
<td style="text-align:center;background:#004200">
<span style="font-weight:bold;">Database</span>
<div style="color:#7dff7d;font-size:1.2em;padding-top:10px"><?php echo $queries; ?></div>
</td>
<td style="text-align:center;background:#000048">
<span style="font-weight:bold;">Includes</span>
<div style="color:#c4c4ff;font-size:1.2em;padding-top:10px"><?php echo $files; ?></div>
</td>
</tr>
</table>
<table>
<tr>
<th style="text-align:left" colspan="2">Console</th>
<th style="text-align:right">Memory</th>
<th style="text-align:right">Time</th>
</tr>
<?php
foreach (self::$profile as $key => $entry)
{
?>
<tr>
<td style="font-weight:bold;color:#999"><?php echo $entry['type']; ?></td>
<td><?php echo $entry['log']; ?></td>
<td style="text-align:right" nowrap="nowrap"><?php echo self::formatSize($entry['memory']); ?></td>
<td style="text-align:right" nowrap="nowrap"><?php echo number_format($entry['elapsed'] * 100, 3); ?> ms</td>
</tr>
<?php
}
?>
</table>
<?php
}
?>
</div>
<br /><br />
<?php
}
/**
* Format Size
*
* Formats the passed size into a human readable string
*
* @static
* @access private
* @param float $filesize size of the file
* @return string formatted number string
*/
private static function formatSize($filesize)
{
$units = array('bytes', 'kB', 'MB', 'GB');
return number_format(round($filesize / pow(1024, ($i = floor(log($filesize, 1024)))), 2), 2) . ' ' . $units[$i];
}
}
?>

View file

@ -1,436 +0,0 @@
<?php
/**
* Security System for PICKLES
*
* PHP version 5
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @author Joshua Sherman <pickles@joshtronic.com>
* @copyright Copyright 2007-2013, Joshua Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @package PICKLES
* @link https://github.com/joshtronic/pickles
*/
/**
* Security Class
*
* Collection of static methods for handling security within a website running
* on PICKLES. Requires sessions to be enabled.
*
* @usage <code>Security::login(10);</code>
* @usage <code>Security::isLevel(SECURITY_LEVEL_ADMIN);</code>
*/
class Security
{
/**
* Lookup Cache
*
* Used to minimize database lookups
*
* @static
* @access private
* @var array
*/
private static $cache = array();
/**
* Generate Hash
*
* Generates an SHA1 hash from the provided string. Salt optional.
*
* @param string $source value to hash
* @param mixed $salts optional salt or salts
* @return string SHA1 hash
*/
public static function generateHash($source, $salts = null)
{
// Determines which salt(s) to use
if ($salts == null)
{
$config = Config::getInstance();
if (isset($config->security['salt']) && $config->security['salt'] != null)
{
$salts = $config->security['salt'];
}
else
{
$salts = array('P1ck73', 'Ju1C3');
}
}
// Forces the variable to be an array
if (!is_array($salts))
{
$salts = array($salts);
}
// Loops through the salts, applies them and calculates the hash
$hash = $source;
foreach ($salts as $salt)
{
$hash = sha1($salt . $hash);
}
return $hash;
}
/**
* SHA-256
*
* Generates an SHA-256 hash from the provided string.
*
* @param string $source value to hash
* @return string SHA1 hash
*/
public static function sha256($source)
{
return hash('sha256', $source);
}
/**
* Generate SHA-256 Hash
*
* Generates an SHA-256 hash from the provided string and salt. Borrowed the
* large iteration logic from fCryptography::hashWithSalt() as, and I quote,
* "makes rainbow table attacks infesible".
*
* @param string $source value to hash
* @param mixed $salt value to use as salt
* @return string SHA-256 hash
* @link https://github.com/flourishlib/flourish-classes/blob/master/fCryptography.php
*/
public static function generateSHA256Hash($source, $salt)
{
$sha256 = sha1($salt . $source);
for ($i = 0; $i < 1000; $i++)
{
$sha256 = Security::sha256($sha256 . (($i % 2 == 0) ? $source : $salt));
}
return $sha256;
}
/**
* Check Session
*
* Checks if sessions are enabled.
*
* @static
* @access private
* @return boolean whether or not sessions are enabled
*/
private static function checkSession()
{
if (session_id() == '')
{
return false;
}
else
{
return true;
}
}
/**
* Check Level
*
* Checks if a passed level is an integer and/or properly defined in the
* site's configuration file.
*
* @static
* @access private
* @param mixed access level to validate
* @return whether ot not the access level is valid
*/
private static function checkLevel(&$access_level)
{
if (is_int($access_level))
{
return true;
}
else
{
$config = Config::getInstance();
// Attempts to validate the string passed
if (isset($config->security[$access_level]))
{
if (is_numeric($config->security[$access_level]))
{
$access_level = (int)$config->security[$access_level];
return true;
}
else
{
throw new Exception('Level "' . $access_level . '" is not numeric in config.ini');
}
}
else
{
throw new Exception('Level "' . $access_level . '" is not defined in config.ini');
}
}
return false;
}
/**
* Login
*
* Creates a session variable containing the user ID and generated token.
* The token is also assigned to a cookie to be used when validating the
* security level. When the level value is present, the class will by pass
* the database look up and simply use that value when validating (the less
* paranoid scenario).
*
* @static
* @param integer $user_id ID of the user that's been logged in
* @param integer $level optional level for the user being logged in
* @param string $role textual representation of the user's level
* @return boolean whether or not the login could be completed
*/
public static function login($user_id, $level = null, $role = null)
{
if (self::checkSession())
{
$token = sha1(microtime());
$_SESSION['__pickles']['security'] = array(
'token' => $token,
'user_id' => (int)$user_id,
'level' => $level,
'role' => $role,
);
setcookie('pickles_security_token', $token);
return true;
}
else
{
return false;
}
}
/**
* Logout
*
* Clears out the security information in the session and the cookie.
*
* @static
* @return boolean true
*/
public static function logout()
{
if (isset($_SESSION['__pickles']['security']))
{
$_SESSION['__pickles']['security'] = null;
unset($_SESSION['__pickles']['security']);
setcookie('pickles_security_token', '', time() - 3600);
}
return true;
}
/**
* Get User Level
*
* Looks up the user level in the database and caches it. Cache is used
* for any subsequent look ups for the user. Also validates the session
* variable against the cookie to ensure everything is legit. If the user
* level is set in the session, that value will take precedence.
*
* return integer user level or false
*/
private static function getUserLevel()
{
if (self::checkSession() == true && isset($_SESSION['__pickles']['security']['user_id']))
{
// Checks the session against the cookie
if (isset($_SESSION['__pickles']['security']['token'], $_COOKIE['pickles_security_token'])
&& $_SESSION['__pickles']['security']['token'] != $_COOKIE['pickles_security_token'])
{
Security::logout();
}
elseif (isset($_SESSION['__pickles']['security']['level']) && $_SESSION['__pickles']['security']['level'] != null)
{
return $_SESSION['__pickles']['security']['level'];
}
// Hits the database to determine the user's level
else
{
// Checks the session cache instead of hitting the database
if (isset($_SESSION['__pickles']['security']['user_id'], self::$cache[(int)$_SESSION['__pickles']['security']['user_id']]))
{
return self::$cache[(int)$_SESSION['__pickles']['security']['user_id']];
}
else
{
// Pulls the config and defaults where necessary
$config = Config::getInstance();
if ($config->security === false)
{
$config = array();
}
else
{
$config = $config->security;
}
$defaults = array('login' => 'login', 'model' => 'User', 'column' => 'level');
foreach ($defaults as $variable => $value)
{
if (!isset($config[$variable]))
{
$config[$variable] = $value;
}
}
// Uses the model to pull the user's access level
$class = $config['model'];
$model = new $class(array('fields' => $config['column'], 'conditions' => array('id' => (int)$_SESSION['__pickles']['security']['user_id'])));
if ($model->count() == 0)
{
Security::logout();
}
else
{
$constant = 'SECURITY_LEVEL_' . $model->record[$config['column']];
if (defined($constant))
{
$constant = constant($constant);
self::$cache[(int)$_SESSION['__pickles']['security']['user_id']] = $constant;
return $constant;
}
else
{
throw new Exception('Security level constant is not defined');
}
}
}
}
}
return false;
}
/**
* Is Level
*
* Checks the user's access level is exactly the passed level
*
* @static
* @param integer $access_level access level to be checked against
* @return boolean whether or not the user is that level
*/
public static function isLevel()
{
$is_level = false;
if (self::checkSession())
{
$arguments = func_get_args();
if (is_array($arguments[0]))
{
$arguments = $arguments[0];
}
foreach ($arguments as $access_level)
{
if (self::checkLevel($access_level))
{
if (self::getUserLevel() == $access_level)
{
$is_level = true;
break;
}
}
}
}
return $is_level;
}
/**
* Has Level
*
* Checks the user's access level against the passed level.
*
* @static
* @param integer $access_level access level to be checked against
* @return boolean whether or not the user has access
*/
public static function hasLevel()
{
$has_level = false;
if (self::checkSession())
{
$arguments = func_get_args();
if (is_array($arguments[0]))
{
$arguments = $arguments[0];
}
foreach ($arguments as $access_level)
{
if (self::checkLevel($access_level))
{
if (self::getUserLevel() >= $access_level)
{
$has_level = true;
break;
}
}
}
}
return $has_level;
}
/**
* Between Level
*
* Checks the user's access level against the passed range.
*
* @static
* @param integer $low access level to be checked against
* @param integer $high access level to be checked against
* @return boolean whether or not the user has access
*/
public static function betweenLevel($low, $high)
{
$between_level = false;
if (self::checkSession())
{
if (self::checkLevel($low) && self::checkLevel($high))
{
$user_level = self::getUserLevel();
if ($user_level >= $low && $user_level <= $high)
{
$between_level = true;
break;
}
}
}
return $between_level;
}
}
?>

View file

@ -1,345 +0,0 @@
<?php
/**
* Session Handling for PICKLES
*
* PHP version 5
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @author Joshua Sherman <pickles@joshtronic.com>
* @copyright Copyright 2007-2013, Joshua Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @package PICKLES
* @link https://github.com/joshtronic/pickles
*/
/**
* Session Class
*
* Provides session handling via database instead of the file based session
* handling built into PHP. Using this class requires an array to be
* defined in place of the boolean true/false (on/off). If simply array(),
* the datasource will default to the value in
* $config['pickles']['datasource'] and if the table will default to
* "sessions". The format is as follows:
*
* $config = array(
* 'pickles' => array(
* 'session' => array(
* 'datasource' => 'mysql',
* 'table' => 'sessions',
* )
* )
* );
*
* In addition to the configuration variables, a table in your database
* must be created. The [MySQL] table schema is as follows:
*
* CREATE TABLE sessions (
* id varchar(32) COLLATE utf8_unicode_ci NOT NULL,
* session text COLLATE utf8_unicode_ci NOT NULL,
* expires_at datetime NOT NULL,
* PRIMARY KEY (id),
* INDEX (expires_at)
* ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
*
* Note: The reason for not using a model class was to avoid a naming
* conflict between the Session model and the Session class itself. This
* will eventually be resolved when I abandon full 5.x support and migrate
* to 5.3+ (assuming that ever happens).
*/
class Session extends Object
{
/**
* Handler
*
* What the session is being handled by.
*
* @access private
* @var string
*/
private $handler = false;
/**
* Accessed At
*
* The UNIX timestamp of when the page was accessed.
*
* @access private
* @var integer
*/
private $accessed_at = null;
/**
* Time to Live
*
* The number of seconds the session should remain active. Corresponds
* to the INI variable session.gc_maxlifetime
*
* @access private
* @var integer
*/
private $time_to_live = null;
/**
* Datasource
*
* Name of the datasource, defaults to whatever the default datasource
* is defined to in config.php
*
* @access private
* @var string
*/
private $datasource = null;
/**
* Table
*
* Name of the database table in the aforementioned datasource that
* holds the session data. The expected schema is defined above.
*
* @access private
* @var string
*/
private $table = null;
/**
* Database
*
* Our database object to interact with the aforementioned datasource
* and table. This object is shared with other PICKLES internals.
*
* @access private
* @var object
*/
private $db = null;
/**
* Constructor
*
* All of our set up logic for the session in contained here. This
* object is initially instantiated from pickles.php and the session
* callbacks are established here. All variables are driven from
* php.ini and/or the site config. Once configured, the session is
* started automatically.
*/
public function __construct()
{
if (!IS_CLI)
{
parent::__construct();
// Sets up our configuration variables
if (isset($this->config->pickles['session']))
{
$session = $this->config->pickles['session'];
$version = 1;
}
if (isset($this->config->pickles['sessions']))
{
$session = $this->config->pickles['sessions'];
$version = 2;
}
$datasources = $this->config->datasources;
$this->handler = 'files';
$datasource = false;
$table = 'sessions';
if (isset($datasources[$session]))
{
$datasource = $datasources[$session];
$this->handler = $datasource['type'];
if (isset($datasource['hostname'], $datasource['port']))
{
$host = 'tcp://' . $datasource['hostname'] . ':' . $datasource['port'];
}
}
switch ($this->handler)
{
case 'memcache':
ini_set('session.save_handler', 'memcache');
ini_set('session.save_path', $host . '?persistent=1&amp;weight=1&amp;timeout=1&amp;retry_interval=15');
break;
// @todo memcached
case 'mysql':
// Sets our access time and time to live
$this->accessed_at = time();
$this->time_to_live = ini_get('session.gc_maxlifetime');
$this->datasource = $datasource;
$this->table = $table;
// Gets a database instance
$this->db = Database::getInstance($this->datasource);
// Initializes the session
$this->initialize();
break;
case 'redis':
// Keep in mind that the database value is ignored by phpredis
$save_path = $host . '?weight=1'
. (isset($datasource['database']) ? '&database=' . $datasource['database'] : '')
. (isset($datasource['prefix']) ? '&prefix=' . $datasource['prefix'] : '');
ini_set('session.save_handler', 'redis');
ini_set('session.save_path', $save_path);
break;
default:
case 'files':
ini_set('session.save_handler', 'files');
break;
}
if (isset($_SERVER['HTTP_USER_AGENT'])
&& !String::isEmpty($_SERVER['HTTP_USER_AGENT'])
&& !preg_match('/(Baidu|Gigabot|Googlebot|libwww-perl|lwp-trivial|msnbot|SiteUptime|Slurp|WordPress|ZIBB|ZyBorg)/i', $_SERVER['HTTP_USER_AGENT']))
{
session_start();
}
}
}
/**
* Destructor
*
* Runs garbage collection and closes the session. I'm not sure if the
* garbage collection should stay as it could be accomplished via
* php.ini variables. The session_write_close() is present to combat a
* chicken and egg scenario in earlier versions of PHP 5.
*/
public function __destruct()
{
if ($this->handler == 'mysql')
{
$this->gc($this->time_to_live);
session_write_close();
}
}
/**
* Initializes the Session
*
* This method exists to combat the fact that calling session_destroy()
* also clears out the save handler. Upon destorying a session this
* method is called again so the save handler is all set.
*/
public function initialize()
{
// Sets up the session handler
session_set_save_handler(
array($this, 'open'),
array($this, 'close'),
array($this, 'read'),
array($this, 'write'),
array($this, 'destroy'),
array($this, 'gc')
);
register_shutdown_function('session_write_close');
}
/**
* Opens the Session
*
* Since the session is in the database, opens the database connection.
* This step isn't really necessary as the Database object is smart
* enough to open itself up upon execute.
*/
public function open()
{
session_regenerate_id();
return $this->db->open();
}
/**
* Closes the Session
*
* Same as above, but in reverse.
*/
public function close()
{
return $this->db->close();
}
/**
* Reads the Session
*
* Checks the database for the session ID and returns the session data.
*
* @param string $id session ID
* @return string serialized session data
*/
public function read($id)
{
$sql = 'SELECT session FROM `' . $this->table . '` WHERE id = ?;';
$session = $this->db->fetch($sql, array($id));
return isset($session[0]['session']) ? $session[0]['session'] : '';
}
/**
* Writes the Session
*
* When there's changes to the session, writes the data to the
* database.
*
* @param string $id session ID
* @param string $session serialized session data
* @return boolean whether the query executed correctly
*/
public function write($id, $session)
{
$sql = 'REPLACE INTO `' . $this->table . '` VALUES (?, ? ,?);';
$parameters = array($id, $session, date('Y-m-d H:i:s', strtotime('+' . $this->time_to_live . ' seconds')));
return $this->db->execute($sql, $parameters);
}
/**
* Destroys the Session
*
* Deletes the session from the database.
*
* @param string $id session ID
* @return boolean whether the query executed correctly
*/
public function destroy($id)
{
$sql = 'DELETE FROM `' . $this->table . '` WHERE id = ?;';
return $this->db->execute($sql, array($id));
}
/**
* Garbage Collector
*
* This is who you call when you got trash to be taken out.
*
* @param integer $time_to_live number of seconds a session is active
* @return boolean whether the query executed correctly
*/
public function gc($time_to_live)
{
$sql = 'DELETE FROM `' . $this->table . '` WHERE expires_at < ?;';
$parameters = array(date('Y-m-d H:i:s', $this->accessed_at - $time_to_live));
return $this->db->execute($sql, $parameters);
}
}
?>

View file

@ -1,72 +0,0 @@
<?php
/**
* Sorting Utility Collection
*
* PHP version 5
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @author Joshua Sherman <pickles@joshtronic.com>
* @copyright Copyright 2007-2013, Joshua Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @package PICKLES
* @link https://github.com/joshtronic/pickles
*/
/**
* Sort Class
*
* I got tired of writing separate usort functions to sort by different array
* keys in the array, this class solves that.
*/
class Sort
{
/**
* Ascending
*
* Variable to utilize ascending sort
*
* @var integer
*/
const ASC = 'ASC';
/**
* Descending
*
* Variable to utilize descending sort
*
* @var integer
*/
const DESC = 'DESC';
/**
* Sort By
*
* Sorts an array by the specified column, optionally in either direction.
*
* @param string $field field to sort by
* @param array $array array to sort
* @param string $direction optional direction to sort
* @retun boolean true because sorting is done by reference
*/
public static function by($field, &$array, $direction = Sort::ASC)
{
usort($array, create_function('$a, $b', '
$a = $a["' . $field . '"];
$b = $b["' . $field . '"];
if ($a == $b)
{
return 0;
}
return ($a ' . ($direction == Sort::DESC ? '>' : '<') .' $b) ? -1 : 1;
'));
return true;
}
}
?>

View file

@ -1,267 +0,0 @@
<?php
/**
* String Utility Collection
*
* PHP version 5
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @author Joshua Sherman <pickles@joshtronic.com>
* @copyright Copyright 2007-2013, Joshua Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @package PICKLES
* @link https://github.com/joshtronic/pickles
*/
/**
* String Class
*
* Just a simple collection of static functions to accomplish some of the
* more redundant string related manipulation.
*/
class String
{
// {{{ Format Phone Number
/**
* Format Phone Number
*
* Formats a 10 digit phone number with dashes as ###-###-####.
*
* @static
* @param string $number number to format
* @param string $replacement output of the string
* @return string formatted phone number
*/
public static function formatPhoneNumber($number, $replacement = '$1-$2-$3')
{
// Strips characters we don't need
$number = str_replace(array('(', ')', ' ', '-', '.', '_'), '', $number);
// Formats the number
return preg_replace('/^(\d{3})(\d{3})(.+)$/', $replacement, $number);
}
// }}}
// {{{ Generate Gravatar Hash
/**
* Generate Gravatar Hash
*
* Generates a hash from the passed string that can then be used for
* fetching an avatar from Gravatar.com
*
* @deprecated
* @static
* @param string $string string to hash, should be an email address
* @return string resulting hash
*/
public static function generateGravatarHash($string)
{
return API_Gravatar::hash($string);
}
// }}}
// {{{ Generate Slug
/**
* Generate Slug
*
* Generates a slug from the pass string by lowercasing the string,
* trimming whitespace and converting non-alphanumeric values to
* dashes. Takes care of multiple dashes as well.
*
* @static
* @param string $string to be converted to the slug
* @return string resulting slug
*/
public static function generateSlug($string)
{
$string = strtolower(trim($string));
$string = preg_replace('/[^a-z0-9-]/', '-', $string);
$string = preg_replace('/-+/', '-', $string);
return trim($string, '-');;
}
// }}}
// {{{ Is Empty
/**
* Is Empty
*
* Checks if a string is empty. You can use the PHP function empty()
* but that returns true for a string of "0". Last I checked, that's
* not an empty string. PHP's function also doesn't apply trim() to the
* value to ensure it's not just a bunch of spaces.
*
* @static
* @param string $value string(s) to be checked
* @return boolean whether or not the string is empty
*/
public static function isEmpty()
{
foreach (func_get_args() as $value)
{
if (trim($value) == '')
{
return true;
}
}
return false;
}
// }}}
// {{{ Pluralize
/**
* Pluralize
*
* Based on a passed integer, the word will be pluralized. A value of
* zero will also pluralize the word (e.g. 0 things not 0 thing).
*
* @static
* @param string $string the word to plurailze
* @param integer $count the count to interrogate
* @param boolean $both (optional) include count in return
* @return string pluralized word
*/
public static function pluralize($string, $count, $both = false)
{
if ($count != 1)
{
$string .= 's';
}
if ($both)
{
$string = $count . ' ' . $string;
}
return $string;
}
// }}}
// {{{ Random
/**
* Random
*
* Generates a pseudo-random string based on the passed parameters.
*
* Note: Similar characters = 0, O, 1, I (and may be expanded)
*
* @static
* @param integer $length optional length of the generated string
* @param boolean $alpha optional include alpha characters
* @param boolean $numeric optional include numeric characters
* @param boolean $similar optional include similar characters
* @return string generated string
*/
public static function random($length = 8, $alpha = true, $numeric = true, $similar = true)
{
$characters = array();
$string = '';
// Adds alpha characters to the list
if ($alpha == true)
{
if ($similar == true)
{
$characters = array_merge($characters, range('a', 'z'));
}
else
{
$characters = array_merge($characters, range('a', 'h'), range('j', 'n'), range('p', 'z'));
}
}
// Adds numeric characters to the list
if ($numeric == true)
{
if ($similar == true)
{
$characters = array_merge($characters, range('0', '9'));
}
else
{
$characters = array_merge($characters, range('2', '9'));
}
}
if (count($characters) > 0)
{
shuffle($characters);
for ($i = 0; $i < $length; $i++)
{
$string .= $characters[array_rand($characters)];
}
}
return $string;
}
// }}}
// {{{ Truncate
/**
* Truncate
*
* Truncates a string to a specified length and (optionally) adds a
* span to provide a rollover to see the expanded text.
*
* @static
* @param string $string string to truncate
* @param integer $length length to truncate to
* @param boolean $hover (optional) whether or not to add the rollover
* @return string truncate string
*/
public static function truncate($string, $length, $hover = true)
{
if (strlen($string) > $length)
{
if ($hover == true)
{
$string = '<span title="' . $string . '">' . substr($string, 0, $length) . '&hellip;</span>';
}
else
{
$string = substr($string, 0, $length) . '...';
}
}
return $string;
}
// }}}
// {{{ Upper Words
/**
* Upper Words
*
* Applies strtolower() and ucwords() to the passed string. The
* exception being email addresses which are not formatted at all.
*
* @static
* @param string $string string to format
* @return string formatted string
*/
public static function upperWords($string)
{
// Only formats non-email addresses
if (filter_var($string, FILTER_VALIDATE_EMAIL) == false)
{
$string = ucwords(strtolower($string));
}
return $string;
}
// }}}
}
?>

View file

@ -1,234 +0,0 @@
<?php
/**
* Time Utility Collection
*
* PHP version 5
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @author Joshua Sherman <pickles@joshtronic.com>
* @copyright Copyright 2007-2013, Joshua Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @package PICKLES
* @link https://github.com/joshtronic/pickles
*/
/**
* Time Class
*
* Just a simple collection of static functions to accomplish some of the more
* redundant time and date related manipulation.
*/
class Time
{
// {{{ Intervals (in seconds)
/**
* Minute
*
* Seconds in a minute
*
* @var integer
*/
const MINUTE = 60;
/**
* Hour
*
* Seconds in an hour (minute * 60)
*
* @var integer
*/
const HOUR = 3600;
/**
* Day
*
* Seconds in a day (hour * 24)
*
* @var integer
*/
const DAY = 86400;
/**
* Week
*
* Seconds in a week (day * 7)
*
* @var integer
*/
const WEEK = 604800;
/**
* Month
*
* Seconds in a month (day * 30)
*
* @var integer
*/
const MONTH = 2592000;
/**
* Quarter
*
* Seconds in a quarter (day * 90)
*
* @var integer
*/
const QUARTER = 7776000;
/**
* Year
*
* Seconds in a year (day * 365)
*
* @var integer
*/
const YEAR = 31536000;
/**
* Decade
*
* Seconds in a decade (year * 10)
*
* @var integer
*/
const DECADE = 315360000;
/**
* Century
*
* Seconds in a decade (decade * 10)
*
* @var integer
*/
const CENTURY = 3153600000;
// }}}
/**
* Age
*
* Calculates age based on the passed date.
*
* @static
* @param string $date birth / inception date
* @return integer $age number of years old
* @todo Wondering if this really should live in the Date class since it's a Date function. Could flip the aliasing to preserve any older code.
*/
public static function age($date)
{
if (!preg_match('/\d{4}-\d{2}-\d{2}/', $date))
{
$date = date('Y-m-d', strtotime($date));
}
list($year, $month, $day) = explode('-', $date, 3);
$age = date('Y') - $year;
if (date('md') < $month . $day)
{
$age--;
}
return $age;
}
/**
* Ago
*
* Generates a relative time (e.g. X minutes ago).
*
* @static
* @param mixed $time timestamp to calculate from
* @return string relative time
*/
public static function ago($time)
{
$current = strtotime(Time::timestamp());
$time = preg_match('/^\d+$/', $time) ? $time : strtotime($time);
if ($current == $time)
{
$time_ago = 'just now';
}
else
{
if ($current > $time)
{
$difference = $current - $time;
$suffix = ' ago';
}
else
{
$difference = $time - $current;
$suffix = ' from now';
}
// Less than 1 minute ago (seconds ago)
if ($difference < 60)
{
$time_ago = 'seconds';
}
// Less than 1 hour ago (minutes ago)
elseif ($difference < 3600)
{
$minutes = round($difference / 60);
$time_ago = $minutes . ' minute' . ($minutes != 1 ? 's' : '');
}
// Less than 1 day ago (hours ago)
elseif ($difference < 86400)
{
$hours = round($difference / 3600);
$time_ago = $hours . ' hour' . ($hours != 1 ? 's' : '');
}
// Less than 1 week ago (days ago)
elseif ($difference < 604800)
{
$days = round($difference / 86400);
$time_ago = $days . ' day' . ($days != 1 ? 's' : '');
}
// Less than 1 month ago (weeks ago)
elseif ($difference < 2419200)
{
$weeks = round($difference / 604800);
$time_ago = $weeks . ' week' . ($weeks != 1 ? 's' : '');
}
// Less than 1 year ago (months ago)
elseif ($difference < 31449600)
{
$months = round($difference / 2419200);
$time_ago = $months . ' month' . ($months != 1 ? 's' : '');
}
// Over 1 year ago (years ago)
else
{
$years = round($difference / 31449600);
$time_ago = $years . ' year' . ($years != 1 ? 's' : '');
}
$time_ago .= $suffix;
}
return $time_ago;
}
/**
* Timestamp
*
* Current Universal Time in the specified format.
*
* @static
* @param string $format format of the timestamp
* @return string $timestamp formatted timestamp
*/
public static function timestamp($format = 'Y-m-d H:i:s')
{
return gmdate($format);
}
}
?>

View file

@ -1,157 +0,0 @@
<?php
/**
* Validator
*
* PHP version 5
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @author Joshua Sherman <pickles@joshtronic.com>
* @copyright Copyright 2007-2013, Joshua Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @package PICKLES
* @link https://github.com/joshtronic/pickles
*/
/**
* Validate Class
*
* Validation layer that's used by the Modules to validate passed data. Handles
* single sanity checks against a variable so the validation itself can be used
* in other places in the system
*/
class Validate
{
/**
* Is Valid?
*
* Checks if a variable is valid based on the passed rules.
*
* @param mixed $value the value to be validated
* @param array $rules an array of rules (and messages) to validate with
* @return mixed boolean true if valid, array of errors if invalid
*/
public static function isValid($value, $rules)
{
$errors = array();
if (is_array($rules))
{
foreach ($rules as $rule => $message)
{
$rule = explode(':', $rule);
switch (strtolower($rule[0]))
{
// @todo case 'alpha':
// @todo case 'alphanumeric':
// @todo case 'date':
// {{{ Checks using filter_var()
case 'filter':
if (count($rule) < 2)
{
throw new Exception('Invalid validation rule, expected: "validate:boolean|email|float|int|ip|regex|url".');
}
else
{
switch (strtolower($rule[1]))
{
case 'boolean':
case 'email':
case 'float':
case 'int':
case 'ip':
case 'regex':
case 'url':
$filter = constant('FILTER_VALIDATE_' . strtoupper($rule[1]));
break;
default:
throw new Exception('Invalid filter, expecting boolean, email, float, int, ip, regex or url.');
break;
}
if (!filter_var($value, $filter))
{
$errors[] = $message;
}
}
break;
// }}}
// {{{ Checks using strlen()
case 'length':
if (count($rule) < 3)
{
throw new Exception('Invalid validation rule, expected: "length:<|<=|==|!=|>=|>:integer".');
}
else
{
if (!filter_var($rule[2], FILTER_VALIDATE_INT))
{
throw new Exception('Invalid length value, expecting an integer.');
}
else
{
$length = strlen($value);
switch ($rule[1])
{
case '<': $valid = $length < $rule[2]; break;
case '<=': $valid = $length <= $rule[2]; break;
case '==': $valid = $length == $rule[2]; break;
case '!=': $valid = $length != $rule[2]; break;
case '>=': $valid = $length >= $rule[2]; break;
case '>': $valid = $length > $rule[2]; break;
default:
throw new Exception('Invalid operator, expecting <, <=, ==, !=, >= or >.');
break;
}
if ($valid === true)
{
$errors[] = $message;
}
}
}
break;
// }}}
// @todo case 'range':
// {{{ Checks using preg_match()
case 'regex':
if (count($rule) < 3)
{
throw new Exception('Invalid validation rule, expected: "regex:is|not:string".');
}
else
{
if ((strtolower($rule[1]) == 'not' && !preg_match($rule[2], $value)) || preg_match($rule[2], $value))
{
$errors[] = $message;
}
}
break;
// }}}
}
}
}
return count($errors) ? $errors : true;
}
}
?>

37
composer.json Normal file
View file

@ -0,0 +1,37 @@
{
"name": "joshtronic/pickles",
"description": "Pickles is a PHP framework for building kick-ass services",
"type": "library",
"keywords": ["framework", "api", "soa", "oauth"],
"homepage": "http://picklesphp.com",
"license": "MIT",
"authors": [
{
"name": "Josh Sherman",
"email": "josh@gravityblvd.com",
"homepage": "http://joshtronic.com"
}
],
"support": {
"issues": "https://github.com/joshtronic/pickles/issues",
"source": "https://github.com/joshtronic/pickles"
},
"minimum-stability" : "dev",
"require-dev": {
"phpunit/phpunit": "dev-master",
"satooshi/php-coveralls": "dev-master"
},
"require": {
"php": ">=5.4",
"league/oauth2-server": "4.0.x-dev"
},
"suggest": {
"mongodb/mongo-php-driver": "Required to use the Mongo storage engine",
"predis/predis": "Required to use the Redis storage engine"
},
"autoload": {
"psr-4": {
"Pickles\\" : "src/"
}
}
}

1446
composer.lock generated Normal file

File diff suppressed because it is too large Load diff

14
phpunit.xml Normal file
View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.2/phpunit.xsd"
bootstrap="tests/bootstrap.php"
colors="true"
stderr="true"
>
<testsuites>
<testsuite name="Pickles Test Harness">
<directory>./tests/Pickles</directory>
</testsuite>
</testsuites>
</phpunit>

View file

@ -1,379 +0,0 @@
<?php
/**
* Core PICKLES Include File
*
* This is the file that you include on the page you're instantiating the
* controller from (typically index.php). The path to the PICKLES code
* base is established as well as the path that Smarty will use to store
* the compiled pages.
*
* PHP version 5
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @author Joshua Sherman <pickles@joshtronic.com>
* @copyright Copyright 2007-2013, Joshua Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @package PICKLES
* @link https://github.com/joshtronic/pickles
* @usage <code>require_once 'pickles.php';</code>
*/
// {{{ PICKLES Constants
// Grabs the start time in case we're profiling
define('PICKLES_START_TIME', microtime(true));
// Establishes our PICKLES paths
define('PICKLES_PATH', dirname(__FILE__) . '/');
define('PICKLES_CLASS_PATH', PICKLES_PATH . 'classes/');
define('PICKLES_VENDOR_PATH', PICKLES_PATH . 'vendors/');
// Establishes our site paths
define('SITE_PATH', getcwd() . '/../');
define('SITE_CLASS_PATH', SITE_PATH . 'classes/');
define('SITE_MODEL_PATH', SITE_PATH . 'models/');
define('SITE_MODULE_PATH', SITE_PATH . 'modules/');
define('SITE_TEMPLATE_PATH', SITE_PATH . 'templates/');
define('PRIVATE_PATH', SITE_PATH . 'private/');
define('LOG_PATH', PRIVATE_PATH . 'logs/');
// Sets up constants for the Display names
define('DISPLAY_JSON', 'JSON');
define('DISPLAY_PHP', 'PHP');
define('DISPLAY_RSS', 'RSS');
define('DISPLAY_XML', 'XML');
// Creates a constant as to whether or not we have JSON available
define('JSON_AVAILABLE', function_exists('json_encode'));
// Creates a variable to flag if we're on the command line
define('IS_CLI', !isset($_SERVER['REQUEST_METHOD']));
// }}}
// {{{ Defaults some important configuration options
// Turns on error before the config is loaded to help catch parse errors
ini_set('display_errors', true);
error_reporting(-1);
// Sets the error and exception handlers
// set_error_handler('__handleError');
// set_exception_handler('__handleException');
// Defaults timezone to UTC if not set
if (ini_get('date.timezone') == '')
{
ini_set('date.timezone', 'Etc/UTC');
}
// Sets the session variables
ini_set('session.cache_expire', 86400);
ini_set('session.entropy_file', '/dev/urandom');
ini_set('session.entropy_length', 512);
ini_set('session.gc_maxlifetime', 86400);
ini_set('session.gc_probability', 1);
ini_set('session.gc_divisor', 1000);
ini_set('session.hash_function', 1);
// }}}
// {{{ Loads the configuration file and sets any configuration options
// Loads the base config
$config = Config::getInstance();
// Configures any available PHP configuration options
if (is_array($config->php) && count($config->php) > 0)
{
foreach ($config->php as $variable => $value)
{
ini_set($variable, $value);
}
}
// Starts session handling (old)
if (isset($config->pickles['session']))
{
if (session_id() == '' && $config->pickles['session'] !== false)
{
new Session();
}
}
// Starts session handling (new)
if (isset($config->pickles['sessions']))
{
if (session_id() == '' && $config->pickles['sessions'] !== false)
{
new Session();
}
}
// }}}
// {{{ Defaults some internals for ease of use
if (!isset($_REQUEST['request']))
{
$_REQUEST['request'] = isset($config->pickles['module']) ? $config->pickles['module'] : '';
}
// }}}
// {{{ Auto[magical] Loader
/**
* Magic function to automatically load classes
*
* Attempts to load a core PICKLES class or a site level data model or
* module class.
*
* @param string $class Name of the class to be loaded
* @return boolean Return value of require_once() or false (default)
*/
function __autoload($class)
{
$loaded = false;
$filename = preg_replace('/_/', '/', $class) . '.php';
if ($class == 'AYAH')
{
$loaded = require_once PICKLES_VENDOR_PATH . '/ayah/' . $filename;
}
else
{
// Path as the key, boolean value is whether ot not to convert back to hyphenated
$paths = array(
PICKLES_CLASS_PATH => false,
SITE_CLASS_PATH => false,
SITE_MODEL_PATH => false,
SITE_MODULE_PATH => true,
);
foreach ($paths as $path => $hyphenated)
{
// Converts the filename back to hypenated
if ($hyphenated == true)
{
$filename = strtolower(preg_replace('/([A-Z]{1})/', '-$1', $filename));;
}
if (file_exists($path . $filename))
{
$loaded = require_once $path . $filename;
break;
}
}
}
return $loaded;
}
// }}}
// {{{ Error Handler
/**
* Error handling function that thinks it's magical
*
* Catches errors (warnings and the like) and throws it back out as an
* ErrorException. This really helps trapping complex errors that need a ton of
* sanity checks, just try / catch and you're good. Also, this isn't a magic
* function, but I opted to use the __ prefix to help avoid a naming collision
* since namespace support is 5.3+ and PICKLES strives to be 5.0+ compatible.
*
* Keep in mind that fatal errors cannot and will not be handled.
*
* @param integer $errno the level of the error raised
* @param string $errstr the error message
* @param string $errfile filename that the error was raised in
* @param integer $errline line number the error was raised at
* @param array $errcontext array of every variable that existed in scope
* @return ErrorException not really returned, but worth documenting
*/
function __handleError($errno, $errstr, $errfile, $errline, array $errcontext)
{
// Handle hacktastic @ error suppression. Seriously, don't ever use @
if (error_reporting() === 0)
{
return false;
}
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}
// }}}
// {{{ Exception Handler
/**
* Top level exception handling function
*
* Catches uncaught exceptions and displays them.
*
* @param object $exception the exception
*/
function __handleException($exception)
{
if (IS_CLI == true)
{
$lines = array();
$maxes = array('key' => 0, 'method' => 0, 'file' => 0, 'line' => 4);
$trace = $exception->getTrace();
rsort($trace);
foreach ($trace as $key => $data)
{
$method = '';
if (isset($data['class']))
{
$method .= $data['class'] . $data['type'];
}
$method .= $data['function'] . '()';
$line = array(
'key' => $key + 1 . '.',
'method' => $method,
'file' => (isset($data['file']) ? $data['file'] : __FILE__),
'line' => (isset($data['line']) ? $data['line'] : '0')
);
foreach (array_keys($maxes) as $variable)
{
$length = strlen($line[$variable]);
if ($length > $maxes[$variable])
{
$maxes[$variable] = $length;
}
}
$lines[] = $line;
}
$max_length = array_sum($maxes) + 11;
$horizontal_border = '+' . str_repeat('-', $max_length) . '+' . "\n";
echo $horizontal_border;
echo '|' . str_pad('Uncaught Exception', $max_length, ' ', STR_PAD_BOTH) . '|' . "\n";
echo $horizontal_border;
echo '|' . str_pad(' ' . $exception->getMessage(), $max_length) . '|' . "\n";
echo '|' . str_pad(' in ' . $exception->getFile() . ' on line ' . $exception->getLine(), $max_length) . '|' . "\n";
echo $horizontal_border;
echo '| ' . str_pad('Trace', $maxes['key'] + $maxes['method'] + 3) . ' | ' . str_pad('File', $maxes['file']) . ' | ' . str_pad('Line', $maxes['line']) . ' |' . "\n";
echo $horizontal_border;
foreach ($lines as $line)
{
echo '| ';
echo implode(
array(
str_pad($line['key'], $maxes['key'], ' ', STR_PAD_LEFT),
str_pad($line['method'], $maxes['method']),
str_pad($line['file'], $maxes['file']),
str_pad($line['line'], $maxes['line'], ' ', STR_PAD_LEFT)
),
' | '
);
echo ' |' . "\n";
}
echo $horizontal_border;
}
else
{
?>
<style>
#pickles-exception
{
background: #212121;
width: 800px;
margin: 0 auto;
margin-top: 20px;
margin-bottom: 20px;
border-radius: 20px;
-moz-border-radius: 20px;
-webkit-border-radius: 20px;
box-shadow: 0 3px 4px #000;
-moz-box-shadow: 0 3px 4px #000;
-webkit-box-shadow: 0 3px 4px #000;
border: 6px solid #666;
padding: 10px 20px 20px;
font-family: monospace;
font-size: 12px;
text-align: left;
}
#pickles-exception table
{
width: 100%;
}
#pickles-exception table tr th, #pickles-exception table tr td
{
padding: 10px;
}
#pickles-exception .even
{
background-color: #323232;
}
#pickles-exception, #pickles-exception table tr td, #pickles-exception table tr th
{
color: #efefe8;
}
</style>
<div id="pickles-exception">
<strong style="font-size:1.5em">Uncaught Exception</strong><br /><br />
<table style="border-collapse:separate;border-spacing:1px;border-radius:10px;text-shadow:1px 1px 1px #000;text-align:center">
<tr><td style="background-color:#480000;padding:10px">
<div style="font-size:1.5em;font-style:italic"><?php echo $exception->getMessage(); ?></div>
</td></tr>
<tr><td style="background-color:#552200;padding:10px">
<div style="font-size:1.2em"><?php echo $exception->getFile(); ?> on line <?php echo $exception->getLine(); ?></div>
</td></tr>
</table>
<table>
<tr>
<th style="text-align:left" colspan="2">Trace</th>
<th style="text-align:left">File</th>
<th style="text-align:right">Line</th>
</tr>
<?php
$trace = $exception->getTrace();
rsort($trace);
foreach ($trace as $key => $data)
{
$method = '';
if (isset($data['class']))
{
$method .= $data['class'] . $data['type'];
}
$method .= $data['function'] . '()';
?>
<tr>
<td style="font-weight:bold;color:#999"><?php echo $key + 1; ?>.</td>
<td><?php echo $method; ?></td>
<td><?php echo isset($data['file']) ? $data['file'] : __FILE__; ?></td>
<td style="text-align:right"><?php echo isset($data['line']) ? $data['line'] : '0'; ?></td>
</tr>
<?php
}
?>
</table>
</div>
<br /><br />
<?php
}
}
// }}}
?>

129
sql/oauth2.sql Normal file
View file

@ -0,0 +1,129 @@
CREATE TABLE `oauth_clients` (
`id` CHAR(40) NOT NULL,
`secret` CHAR(40) NOT NULL,
`name` VARCHAR(255) NOT NULL,
`auto_approve` TINYINT(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `u_oacl_clse_clid` (`secret`,`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
CREATE TABLE `oauth_endpoints` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`client_id` char(40) NOT NULL,
`redirect_uri` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
KEY `i_oaclen_clid` (`client_id`),
CONSTRAINT `f_oaclen_clid`
FOREIGN KEY (`client_id`)
REFERENCES `oauth_clients` (`id`)
ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
CREATE TABLE `oauth_sessions` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`client_id` char(40) NOT NULL,
`owner_type` enum('user','client') NOT NULL DEFAULT 'user',
`owner_id` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
KEY `i_uase_clid_owty_owid` (`client_id`,`owner_type`,`owner_id`),
CONSTRAINT `f_oase_clid`
FOREIGN KEY (`client_id`)
REFERENCES `oauth_clients` (`id`)
ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
CREATE TABLE `oauth_access_tokens` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`session_id` int(10) unsigned NOT NULL,
`access_token` char(40) NOT NULL,
`expires_at` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `u_oaseacto_acto_seid` (`access_token`,`session_id`),
KEY `f_oaseto_seid` (`session_id`),
CONSTRAINT `f_oaseto_seid`
FOREIGN KEY (`session_id`)
REFERENCES `oauth_sessions` (`id`)
ON DELETE CASCADE ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
CREATE TABLE `oauth_authorization_codes` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`session_id` int(10) unsigned NOT NULL,
`authorization_code` char(40) NOT NULL,
`expires_at` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
KEY `session_id` (`session_id`),
CONSTRAINT `oauth_authorization_codes_ibfk_1`
FOREIGN KEY (`session_id`)
REFERENCES `oauth_sessions` (`id`)
ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
CREATE TABLE `oauth_redirect_uris` (
`session_id` int(10) unsigned NOT NULL,
`redirect_uri` varchar(255) NOT NULL,
PRIMARY KEY (`session_id`),
CONSTRAINT `f_oasere_seid`
FOREIGN KEY (`session_id`)
REFERENCES `oauth_sessions` (`id`)
ON DELETE CASCADE ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
CREATE TABLE `oauth_refresh_tokens` (
`access_token_id` int(10) unsigned NOT NULL,
`refresh_token` char(40) NOT NULL,
`expires_at` int(10) unsigned NOT NULL,
`client_id` char(40) NOT NULL,
PRIMARY KEY (`access_token_id`),
KEY `client_id` (`client_id`),
CONSTRAINT `oauth_refresh_tokens_ibfk_1`
FOREIGN KEY (`client_id`)
REFERENCES `oauth_clients` (`id`)
ON DELETE CASCADE,
CONSTRAINT `f_oasetore_setoid`
FOREIGN KEY (`access_token_id`)
REFERENCES `oauth_access_tokens` (`id`)
ON DELETE CASCADE ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
CREATE TABLE `oauth_scopes` (
`id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
`scope` varchar(255) NOT NULL,
`name` varchar(255) NOT NULL,
`description` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `u_oasc_sc` (`scope`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
CREATE TABLE `oauth_access_token_scopes` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`access_token_id` int(10) unsigned DEFAULT NULL,
`scope_id` smallint(5) unsigned NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `u_setosc_setoid_scid` (`access_token_id`,`scope_id`),
KEY `f_oasetosc_scid` (`scope_id`),
CONSTRAINT `f_oasetosc_scid`
FOREIGN KEY (`scope_id`)
REFERENCES `oauth_scopes` (`id`)
ON DELETE CASCADE ON UPDATE NO ACTION,
CONSTRAINT `f_oasetosc_setoid`
FOREIGN KEY (`access_token_id`)
REFERENCES `oauth_access_tokens` (`id`)
ON DELETE CASCADE ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
CREATE TABLE `oauth_authorization_code_scopes` (
`authorization_code_id` int(10) unsigned NOT NULL,
`scope_id` smallint(5) unsigned NOT NULL,
KEY `authorization_code_id` (`authorization_code_id`),
KEY `scope_id` (`scope_id`),
CONSTRAINT `oauth_authorization_code_scopes_ibfk_2`
FOREIGN KEY (`scope_id`)
REFERENCES `oauth_scopes` (`id`)
ON DELETE CASCADE,
CONSTRAINT `oauth_authorization_code_scopes_ibfk_1`
FOREIGN KEY (`authorization_code_id`)
REFERENCES `oauth_authorization_codes` (`id`)
ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;

212
src/Config.php Normal file
View file

@ -0,0 +1,212 @@
<?php
/**
* Configuration
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @copyright Copyright 2007-2014, Josh Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @link https://github.com/joshtronic/pickles
* @package Pickles
*/
namespace Pickles;
/**
* Config Class
*
* Handles loading the site's configuration file (if available). At the moment
* this class is a very skewed Singleton. The plan is to eventually extend this
* out to support multiple configuration files, and the ability to load in
* custom config files on the fly as well. The core of Pickles uses the class
* as a Singleton so we're not loading the configuration multiple times per
* page load.
*/
class Config extends \ArrayObject
{
private static $_instance = false;
/**
* Constructor
*
* Calls the parent constructor and loads the passed file.
*/
public function __construct($config_filename = false)
{
try
{
ini_set('display_errors', true);
error_reporting(-1);
$filename = getcwd() . '/../../pickles.php';
$environments = false;
$environment = false;
// Why not PHP_SAPI? because I wanted it to be convenient to unit test
$cli = !isset($_SERVER['REQUEST_METHOD']);
if ($config_filename)
{
$filename = $config_filename;
}
// Only require in case you want to reload the config
require $filename;
// Checks that we have the config array
if (!isset($config))
{
throw new \Exception('Missing $config array.');
}
// Determines the environment
if (!isset($config['environments']) || !is_array($config['environments']))
{
throw new \Exception('Environments are misconfigured.');
}
$environments = $config['environments'];
// If we're on the CLI, check an environment was even passed in
if ($cli && $_SERVER['argc'] < 2)
{
throw new \Exception('You must pass an environment (e.g. php script.php <environment>)');
}
// Loops through the environments and looks for a match
foreach ($config['environments'] as $name => $hosts)
{
if (!is_array($hosts))
{
$hosts = [$hosts];
}
// Tries to determine the environment name
foreach ($hosts as $host)
{
if ($cli)
{
// Checks the first argument on the command line
if ($_SERVER['argv'][1] == $name)
{
$environment = $name;
break;
}
}
else
{
// Exact match
if ((preg_match('/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/', $host)
&& $_SERVER['SERVER_ADDR'] == $host)
|| (isset($_SERVER['HTTP_HOST']) && $_SERVER['HTTP_HOST'] == $host))
{
$environment = $name;
break;
}
// Fuzzy match
elseif (substr($host, 0, 1) == '/'
&& (preg_match($host, $_SERVER['SERVER_NAME'], $matches) > 0
|| preg_match($host, $_SERVER['HTTP_HOST'], $matches) > 0))
{
$environments[$name] = $matches[0];
$environment = $name;
$config['environments'][$name] = $matches[0];
break;
}
}
}
}
if (!$environment)
{
throw new \Exception('Unable to determine the environment.');
}
// Flattens the array based on the environment
$config = $this->flatten($environment, $config);
// Disables display errors in production
if ($environment == 'production')
{
ini_set('display_errors', false);
}
// Assigns the environment
$config['environment'] = $environment;
// Defaults expected Pickles variables to false
foreach (['auth', 'cache', 'profiler'] as $variable)
{
if (!isset($config[$variable]))
{
$config[$variable] = false;
}
}
// Assigns the config variables to the object
foreach ($config as $variable => $value)
{
$this[$variable] = $value;
}
}
catch (\Exception $e)
{
throw $e;
}
}
/**
* Flatten
*
* Flattens the configuration array around the specified environment.
*
* @param string $environment selected environment
* @param array $array configuration error to flatten
* @return array flattened configuration array
*/
private function flatten($environment, $array)
{
if (is_array($array))
{
foreach ($array as $key => $value)
{
if (is_array($value))
{
if (isset($value[$environment]))
{
$value = $value[$environment];
}
else
{
$value = $this->flatten($environment, $value);
}
}
$array[$key] = $value;
}
}
return $array;
}
/**
* Get instance of the object
*
* Let's the parent class do all the work
*
* @static
* @param string $file name of config to load
* @return object self::$_instance instance of the Config class
*/
public static function getInstance($file = false)
{
if (!self::$_instance || $file)
{
self::$_instance = new Config($file);
}
return self::$_instance;
}
}

50
src/Mongo.php Normal file
View file

@ -0,0 +1,50 @@
<?php
/**
* Mongo Abstraction Layer
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @copyright Copyright 2007-2014, Josh Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @link https://github.com/joshtronic/pickles
* @package Pickles
*/
namespace Pickles;
class Mongo extends Object
{
public static function getInstance($class = 'Mongo')
{
$config = Config::getInstance();
if (!isset(self::$instances['Mongo']))
{
if (!isset($config['mongo'], $config['mongo']['database']))
{
throw new \Exception('The “mongo” datasource is not defined in the configuration.', 500);
}
$mongo = $config['mongo'];
// Defaults to the local server on the default port
if (!isset($mongo['server']))
{
$mongo['server'] = 'mongodb://localhost:27017';
}
// Instantiates our Mongo client
$instance = new \MongoClient($mongo['server']);
$instance->selectDB($mongo['database']);
// Caches the instance for possible reuse later
self::$instances['Mongo'] = $instance;
}
// Returns the instance
return self::$instances['Mongo'];
}
}

View file

@ -0,0 +1,84 @@
<?php
namespace Pickles\OAuth2;
use \League\OAuth2\Server\Entity\AbstractTokenEntity;
use \League\OAuth2\Server\Entity\AccessTokenEntity;
use \League\OAuth2\Server\Entity\ScopeEntity;
use \League\OAuth2\Server\Storage\AccessTokenInterface;
class AccessTokenStorage extends StorageAdapter implements AccessTokenInterface
{
public function get($token)
{
$sql = 'SELECT oauth_access_tokens.*'
. ' FROM oauth_access_tokens'
. ' WHERE access_token = ?'
. ' AND expires_at >= ?;';
$results = $this->db->fetch($sql, [$token, time()]);
if (count($results) === 1)
{
return (new AccessTokenEntity($this->server))
->setId($results[0]['access_token'])
->setExpireTime($results[0]['expires_at']);
}
return null;
}
public function getScopes(AbstractTokenEntity $token)
{
$sql = 'SELECT oauth_scopes.id, oauth_scopes.description'
. ' FROM oauth_access_token_scopes'
. ' INNER JOIN oauth_scopes'
. ' ON oauth_access_token_scopes.scope_id = oauth_scopes.id'
. ' WHERE oauth_access_token_scopes.access_token_id = ?;';
$results = $this->db->fetch($sql, [$token->getId()]);
$response = [];
if (count($results) > 0)
{
foreach ($results as $row)
{
$response[] = (new ScopeEntity($this->server))->hydrate([
'id' => $row['id'],
'description' => $row['description']
]);
}
}
return $response;
}
public function create($token, $expiration, $session_id)
{
$sql = 'INSERT INTO oauth_access_tokens'
. ' (access_token, session_id, expires_at)'
. ' VALUES'
. ' (?, ?, ?);';
$this->db->execute($sql, [$token, $session_id, $expiration]);
}
public function associateScope(AbstractTokenEntity $token, ScopeEntity $scope)
{
$sql = 'INSERT INTO oauth_access_token_scopes'
. ' (access_token, scope)'
. ' VALUES'
. ' (?, ?);';
$this->db->execute($sql, [$token->getId(), $scope->getId()]);
}
public function delete(AbstractTokenEntity $token)
{
$sql = 'DELETE FROM oauth_access_token_scopes'
. ' WHERE access_token = ?;';
$this->db->execute($sql, [$token->getId()]);
}
}

View file

@ -0,0 +1,81 @@
<?php
namespace Pickles\OAuth2;
use \League\OAuth2\Server\Entity\ClientEntity;
use \League\OAuth2\Server\Entity\SessionEntity;
use \League\OAuth2\Server\Storage\Adapter;
use \League\OAuth2\Server\Storage\ClientInterface;
class ClientStorage extends StorageAdapter implements ClientInterface
{
public function get($client_id, $client_secret = null, $redirect_uri = null, $grant_type = null)
{
$sql = 'SELECT oauth_clients.*';
if ($redirect_uri)
{
$sql .= ', oauth_client_redirect_uris.*'
. ' INNER JOIN oauth_redirect_uris'
. ' ON oauth_clients.id = oauth_redirect_uris.client_id';
}
$sql .= ' FROM oauth_clients WHERE oauth_clients.id = ?';
$parameters = [$client_id];
if ($client_secret)
{
$sql .= ' AND oauth_clients.secret = ?';
$parameters[] = $client_secret;
}
if ($redirect_uri)
{
$sql .= 'AND oauth_redirect_uris.redirect_uri = ?';
$parameters[] = $redirect_uri;
}
$results = $this->db->fetch($sql, $parameters);
if (count($results) === 1)
{
$client = new ClientEntity($this->server);
$client->hydrate([
'id' => $results[0]['id'],
'name' => $results[0]['name']
]);
return $client;
}
return null;
}
public function getBySession(SessionEntity $session)
{
$sql = 'SELECT oauth_clients.id, oauth_clients.name'
. ' FROM oauth_clients'
. ' INNER JOIN oauth_sessions'
. ' ON oauth_clients.id = oauth_sessions.client_id'
. ' WHERE oauth_sessions.id = ?';
$results = $this->db->fetch($sql, [$session->getId()]);
if (count($results) === 1)
{
$client = new ClientEntity($this->server);
$client->hydrate([
'id' => $results[0]['id'],
'name' => $results[0]['name']
]);
return $client;
}
return null;
}
}

View file

@ -0,0 +1,56 @@
<?php
namespace Pickles\OAuth2;
use \League\OAuth2\Server\Entity\RefreshTokenEntity;
use \League\OAuth2\Server\Storage\RefreshTokenInterface;
class RefreshTokenStorage extends StorageAdapter implements RefreshTokenInterface
{
public function get($token)
{
$sql = 'SELECT oauth_refresh_tokens.*'
. ' FROM oauth_refresh_tokens'
. ' WHERE refresh_token = ?'
. ' AND expires_at >= ?;';
$results = $this->db->fetch($sql, [$token, time()]);
if (count($results) === 1)
{
return (new RefreshTokenEntity($this->server))
->setId($results[0]['refresh_token'])
->setExpireTime($results[0]['expires_at'])
->setAccessTokenId($results[0]['access_token_id']);
}
return null;
}
public function create($token, $expiration, $access_token)
{
$sql = 'SELECT id FROM oauth_access_tokens WHERE access_token = ?;';
$results = $this->db->fetch($sql, [$access_token]);
$token_id = $results[0]['id'];
$sql = 'INSERT INTO oauth_refresh_tokens'
. ' (refresh_token, access_token_id, expires_at, client_id)'
. ' VALUES'
. ' (?, ?, ?, ?);';
$this->db->execute($sql, [
$token,
$token_id,
$expiration,
$this->server->getRequest()->request->get('client_id', null),
]);
}
public function delete(RefreshTokenEntity $token)
{
$sql = 'DELETE FROM oauth_refresh_tokens WHERE refresh_token = ?;';
$this->db->execute($sql, [$token->getId()]);
}
}

141
src/OAuth2/Resource.php Normal file
View file

@ -0,0 +1,141 @@
<?php
namespace Pickles\OAuth2;
use \League\OAuth2\Exception\OAuthException;
use \League\OAuth2\Server\AuthorizationServer;
use \League\OAuth2\Server\Grant\PasswordGrant;
use \League\OAuth2\Server\Grant\RefreshTokenGrant;
use \Pickles\App\Models\User;
use \Pickles\Config;
class Resource extends \Pickles\Resource
{
public function POST()
{
if (!isset($this->config['oauth'][$_SERVER['__version']]))
{
throw new \Exception('Forbidden.', 403);
}
elseif (!isset($_REQUEST['grant_type']))
{
throw new \Exception('Bad Request.', 400);
}
$config = $this->config['oauth'][$_SERVER['__version']];
switch (substr($_REQUEST['request'], strlen($_SERVER['__version']) + 2))
{
case 'oauth/access_token':
try
{
$server = new AuthorizationServer;
$server->setSessionStorage(new SessionStorage);
$server->setAccessTokenStorage(new AccessTokenStorage);
$server->setClientStorage(new ClientStorage);
$server->setScopeStorage(new ScopeStorage);
$server->setRefreshTokenStorage(new RefreshTokenStorage);
$grant_type = $_REQUEST['grant_type'];
$grants = ['password'];
if (isset($config['grants']))
{
$grants = array_unique(array_merge($grants, $config['grants']));
}
if (!in_array($grant_type, $grants))
{
throw new \Exception('Unsupported grant type.', 403);
}
// Defaults TTLs to 1 day and 1 week respectively
$token_ttl = 3600;
$refresh_ttl = 604800;
if (isset($config['ttl']['access_token']))
{
$token_ttl = $config['ttl']['access_token'];
}
switch ($grant_type)
{
case 'authorization_code':
throw new \Exception('Not Implemented', 501);
break;
case 'client_credentials':
throw new \Exception('Not Implemented', 501);
break;
case 'implicit':
throw new \Exception('Not Implemented', 501);
break;
case 'password':
$grant = new PasswordGrant;
$grant->setAccessTokenTTL($token_ttl);
$grant->setVerifyCredentialsCallback(function ($username, $password)
{
$user = new User([
'conditions' => [
'email' => $username,
],
]);
return $user->count()
&& password_verify($password, $user->record['password']);
});
break;
case 'refresh_token':
throw new \Exception('Not Implemented', 501);
// @todo Need to work through this, appears lib is busted
$grant = new RefreshTokenGrant;
//$grant->setAccessTokenTTL($refresh_ttl);
$server->addGrantType($grant);
break;
}
$server->addGrantType($grant);
// Adds the refresh token grant if enabled
if ($grant_type != 'refresh_token'
&& in_array('refresh_token', $grants))
{
if (isset($config['ttl']['refresh_token']))
{
$refresh_ttl = $config['ttl']['refresh_token'];
}
$grant = new RefreshTokenGrant;
$grant->setAccessTokenTTL($refresh_ttl);
$server->addGrantType($grant);
}
$response = $server->issueAccessToken();
return $response;
}
catch (OAuthException $e)
{
throw new \Exception($e->getMessage(), $e->httpStatusCode);
}
catch (\Exception $e)
{
throw new \Exception($e->getMessage(), $e->getCode());
}
break;
default:
throw new \Exception('Not Found.', 404);
break;
}
}
}

View file

@ -0,0 +1,26 @@
<?php
namespace Pickles\OAuth2;
use \League\OAuth2\Server\Storage\Adapter;
use \League\OAuth2\Server\Storage\ScopeInterface;
class ScopeStorage extends StorageAdapter implements ScopeInterface
{
public function get($scope, $grant_type = null, $client_id = null)
{
$sql = 'SELECT * FROM oauth_scopes WHERE id = ?;';
$results = $this->db->fetch($sql, [$scope]);
if (count($results) === 0)
{
return null;
}
return (new ScopeEntity($this->server))->hydrate([
'id' => $result[0]['id'],
'description' => $result[0]['description'],
]);
}
}

View file

@ -0,0 +1,106 @@
<?php
namespace Pickles\OAuth2;
use \League\OAuth2\Server\Entity\AccessTokenEntity;
use \League\OAuth2\Server\Entity\AuthCodeEntity;
use \League\OAuth2\Server\Entity\ScopeEntity;
use \League\OAuth2\Server\Entity\SessionEntity;
use \League\OAuth2\Server\Storage\Adapter;
use \League\OAuth2\Server\Storage\SessionInterface;
class SessionStorage extends StorageAdapter implements SessionInterface
{
public function getByAccessToken(AccessTokenEntity $access_token)
{
$sql = 'SELECT oauth_sessions.id, oauth_sessions.owner_type,'
. ' oauth_sessions.owner_id, oauth_sessions.client_id,'
. ' oauth_sessions.client_redirect_uri'
. ' FROM oauth_sessions'
. ' INNER JOIN oauth_access_tokens'
. ' ON oauth_access_tokens.session_id = oauth_sessions.id'
. ' WHERE oauth_access_tokens.access_token = ?;';
$results = $this->db->fetch($sql, [$access_token->getId()]);
if (count($results) === 1)
{
$session = new SessionEntity($this->server);
$session->setId($result[0]['id']);
$session->setOwner($result[0]['owner_type'], $result[0]['owner_id']);
return $session;
}
return null;
}
public function getByAuthCode(AuthCodeEntity $auth_code)
{
$sql = 'SELECT oauth_sessions.id, oauth_sessions.owner_type,'
. ' oauth_sessions.owner_id, oauth_sessions.client_id,'
. ' oauth_sessions.client_redirect_uri'
. ' FROM oauth_sessions'
. ' INNER JOIN oauth_authorization_codes'
. ' ON oauth_authorization_codes.session_id = oauth_sessions.id'
. ' WHERE oauth_authorization_codes.authorization_code = ?;';
$results = $this->db->fetch($sql, [$auth_code->getId()]);
if (count($results) === 1)
{
$session = new SessionEntity($this->server);
$session->setId($result[0]['id']);
$session->setOwner($result[0]['owner_type'], $result[0]['owner_id']);
return $session;
}
return null;
}
public function getScopes(SessionEntity $session)
{
$sql = 'SELECT oauth_sessions.*'
. ' FROM oauth_sessions'
. ' INNER JOIN oauth_access_token_scopes'
. ' ON oauth_sessions.id = oauth_access_token_scopes.access_token_id'
. ' INNER JOIN oauth_scopes'
. ' ON oauth_scopes.id = oauth_access_token_scopes.scope_id'
. ' WHERE oauth_sessions.id = ?;';
$results = $this->db->fetch($sql, [$session->getId()]);
$scopes = [];
foreach ($results as $scope)
{
$scopes[] = (new ScopeEntity($this->server))->hydrate([
'id' => $scope['id'],
'description' => $scope['description'],
]);
}
return $scopes;
}
public function create($owner_type, $owner_id, $client_id, $client_redirect_uri = null)
{
$sql = 'INSERT INTO oauth_sessions'
. ' (owner_type, owner_id, client_id)'
. ' VALUES'
. ' (?, ?, ?);';
return $this->db->execute($sql, [$owner_type, $owner_id, $client_id]);
}
public function associateScope(SessionEntity $session, ScopeEntity $scope)
{
$sql = 'INSERT INTO oauth_access_token_scopes'
. ' (access_token_id, scope_id)'
. ' VALUES'
. ' (?, ?);';
$this->db->execute($sql, [$session->getId(), $scope->getId()]);
}
}

View file

@ -0,0 +1,20 @@
<?php
namespace Pickles\OAuth2;
use \League\OAuth2\Server\Storage\Adapter;
use \Pickles\Config;
use \Pickles\Database;
class StorageAdapter extends Adapter
{
protected $config;
protected $db;
public function __construct()
{
$this->config = Config::getInstance();
$this->db = Database::getInstance();
}
}

114
src/Object.php Normal file
View file

@ -0,0 +1,114 @@
<?php
/**
* Parent Object
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @copyright Copyright 2007-2014, Josh Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @link https://github.com/joshtronic/pickles
* @package Pickles
*/
namespace Pickles;
/**
* Object Class
*
* Every instantiated class in Pickles should be extending this class. By doing
* so the class is automatically hooked into the profiler, and the object will
* have access to some common components as well.
*/
class Object
{
/**
* Object Instances
*
* @static
* @var array
*/
public static $instances = [];
/**
* Instance of the Config object
*
* @var object
*/
public $config = null;
/**
* Instance of the Mongo object
*
* @var object
*/
public $mongo = null;
/**
* Instance of the Redis object
*
* @var object
*/
public $redis = null;
/**
* Constructor
*
* Establishes a Config instance for all children to enjoy
*/
public function __construct()
{
// @todo Lazy load these so we're not loading them on every instance
$this->config = Config::getInstance();
$this->mongo = Mongo::getInstance();
//$this->redis = Redis::getInstance();
// Optionally logs the constructor to the profiler
if ($this->config['profiler'])
{
Profiler::log($this, '__construct');
}
}
/**
* Get Instance
*
* Gets an instance of the passed class. Allows for easy sharing of certain
* classes within the system to avoid the extra overhead of creating new
* objects each time. Also avoids the hassle of passing around variables.
*
* @static
* @param string $class name of the class
* @return object instance of the class
*/
public static function getInstance($class = false)
{
if ($class)
{
$class = 'Pickles\\' . $class;
if (!isset(self::$instances[$class]))
{
self::$instances[$class] = new $class();
}
return self::$instances[$class];
}
return false;
}
/**
* Destructor
*/
public function __destruct()
{
// Optionally logs the destructor to the profiler
if ($this->config['profiler'])
{
Profiler::log($this, '__destruct');
}
}
}

196
src/Profiler.php Normal file
View file

@ -0,0 +1,196 @@
<?php
/**
* Profiler
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @copyright Copyright 2007-2014, Josh Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @link https://github.com/joshtronic/pickles
* @package Pickles
*/
namespace Pickles;
/**
* Profiler Class
*
* The Profiler class is statically interfaced with and allows for in depth
* profiling of a site. By default profiling is off, but can be enabled in the
* config.ini for a site. Out of the box the profiler will report on every
* class object in the system that extends the code Object class.
*
* @usage <code>Profiler::log('some action you want to track');</code>
* @usage <code>Profiler::log($object, 'methodName');</code>
*/
class Profiler
{
/**
* Logs
*
* Array of logged events
*
* @static
* @access private
* @var array
*/
private static $logs = [];
/**
* Timers
*
* Array of active timers
*
* @static
* @access private
* @var array
*/
private static $timers = [];
/**
* Log
*
* Logs the event to be displayed later on. Due to the nature of how much
* of a pain it is to determine which class method called this method I
* opted to make the method a passable argument for ease of use. Perhaps
* I'll revisit in the future. Handles all elapsed time calculations and
* memory usage.
*
* @static
* @param mixed $data data to log
* @param string $method name of the class method being logged
*/
public static function log($data, $method = false, $type = false)
{
$time = microtime(true);
$data_type = ($data == 'timer' ? $data : gettype($data));
// Tidys the data by type
switch ($data_type)
{
case 'object':
$details['class'] = get_class($data);
if ($method != '')
{
$details['method'] = $method . '()';
}
$data_type = $data_type;
break;
case 'timer':
$details = $method;
$data_type = $data_type;
break;
default:
if ($type != false)
{
$data_type = $type;
}
$details = $data;
break;
}
self::$logs[] = [
'type' => $data_type,
'timestamp' => $time,
'elapsed_time' => $time - $_SERVER['REQUEST_TIME_FLOAT'],
'memory_usage' => memory_get_usage(),
'details' => $details,
];
}
/**
* Query
*
* Serves as a wrapper to get query data to the log function
*
* @static
* @param string $query the query being executed
* @param array $input_parameters optional prepared statement data
* @param array $results optional results of the query
* @param float $duration the speed of the query
* @param array $explain EXPLAIN data for the query
*/
public static function query($query, $input_parameters = false, $results = false, $duration = false, $explain = false)
{
$log = [
'query' => $query,
'parameters' => $input_parameters,
'results' => $results,
'execution_time' => $duration,
];
if ($explain)
{
$log['explain'] = $explain;
}
self::log($log, false, 'database');
}
/**
* Timer
*
* Logs the start and end of a timer.
*
* @param string $timer name of the timer
* @return boolean whether or not timer profiling is enabled
*/
public static function timer($timer)
{
// Starts the timer
if (!isset(self::$timers[$timer]))
{
self::$timers[$timer] = microtime(true);
self::Log('timer', [
'action' => 'start',
'name' => $timer
]);
}
// Ends the timer
else
{
self::Log('timer', [
'action' => 'stop',
'name' => $timer,
'elapsed_time' => (microtime(true) - self::$timers[$timer])
]);
unset(self::$timers[$timer]);
}
}
/**
* Report
*
* Generates the Profiler report that is displayed by the Controller.
* Contains all the HTML needed to display the data properly inline on the
* page. Will generally be displayed after the closing HTML tag.
*/
public static function report()
{
$report = [
'request_time' => $_SERVER['REQUEST_TIME_FLOAT'],
'execution_time' => self::$logs[count(self::$logs) - 1]['timestamp']
- $_SERVER['REQUEST_TIME_FLOAT'],
'peak_memory_usage' => memory_get_peak_usage(),
'max_execution_time' => ini_get('max_execution_time'),
'memory_limit' => ini_get('memory_limit'),
'included_files' => count(get_included_files()),
'logs' => self::$logs,
];
self::$logs = [];
self::$timers = [];
return $report;
}
}

387
src/Resource.php Normal file
View file

@ -0,0 +1,387 @@
<?php
/**
* Resource Class
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @copyright Copyright 2007-2014, Josh Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @link https://github.com/joshtronic/pickles
* @package Pickles
*/
namespace Pickles;
use \League\OAuth2\Server\ResourceServer;
use Pickles\OAuth2\AccessTokenStorage;
use Pickles\OAuth2\ClientStorage;
use Pickles\OAuth2\ScopeStorage;
use Pickles\OAuth2\SessionStorage;
/**
* Resource Class
*
* This is a parent class that all Pickles modules should be extending. Each
* module can specify it's own meta data and whether or not a user must be
* properly authenticated to view the page. Currently any pages without a
* template are treated as pages being requested via AJAX and the return will
* be JSON encoded. In the future this may need to be changed out for logic
* that allows the requested module to specify what display type(s) it can use.
*/
class Resource extends Object
{
/**
* Filter
*
* Variables to filter.
*
* @var array
*/
public $filter = [];
/**
* Validate
*
* Variables to validate.
*
* @var array
*/
public $validate = [];
// @todo Document this
public $description = [];
public $auth = false;
public $status = 200;
public $message = 'OK';
public $echo = false;
public $limit = false;
public $offset = false;
public $errors = [];
public $uids = [];
public $response = false;
public $profiler = false;
/**
* Constructor
*
* The constructor does nothing by default but can be passed a boolean
* variable to tell it to automatically run the __default() method. This is
* typically used when a module is called outside of the scope of the
* controller (the registration page calls the login page in this manner.
*/
public function __construct($uids = false)
{
parent::__construct();
$this->uids = $uids;
$method = $_SERVER['REQUEST_METHOD'];
try
{
// Checks if auth flag is explicity true or true for the method
if ($this->auth === true
|| (isset($this->auth[$method]) && $this->auth[$method]))
{
if (isset($this->config['oauth'][$_SERVER['__version']]))
{
$server = new ResourceServer(
new SessionStorage,
new AccessTokenStorage,
new ClientStorage,
new ScopeStorage
);
$server->isValidRequest();
}
else
{
throw new \Exception('Authentication is not configured properly.', 401);
}
}
// Hacks together some new globals
if (in_array($method, ['PUT', 'DELETE']))
{
$GLOBALS['_' . $method] = [];
// @todo Populate it
}
$filter = isset($this->filter[$method]);
$validate = isset($this->validate[$method]);
if ($filter || $validate)
{
$global =& $GLOBALS['_' . $method];
// Checks that the required parameters are present
// @todo Add in support for uid:* variables
if ($validate)
{
$variables = [];
foreach ($this->validate[$method] as $variable => $rules)
{
if (!is_array($rules))
{
$variable = $rules;
}
$variables[] = $variable;
}
$missing_variables = array_diff($variables, array_keys($global));
if ($missing_variables !== array())
{
foreach ($missing_variables as $variable)
{
$this->errors[$variable][] = 'The ' . $variable . ' parameter is required.';
}
}
}
foreach ($global as $variable => $value)
{
// Applies any filters
if ($filter && isset($this->filter[$method][$variable]))
{
$function = $this->filter[$method][$variable];
if ($function == 'password_hash')
{
$global[$variable] = password_hash($value, PASSWORD_DEFAULT);
}
else
{
$global[$variable] = $function($value);
}
}
if ($validate && isset($this->validate[$method][$variable]))
{
$rules = $this->validate[$method][$variable];
if (is_array($rules))
{
if (isset($global[$variable]) && !String::isEmpty($global[$variable]))
{
if (is_array($rules))
{
foreach ($rules as $rule => $message)
{
$rule = explode(':', $rule);
for ($i = 1; $i <= 2; $i++)
{
if (!isset($rule[$i]))
{
$rule[$i] = false;
}
}
switch ($rule[0])
{
// {{{ Checks using filter_var()
case 'filter':
switch ($rule[1])
{
case 'boolean':
case 'email':
case 'float':
case 'int':
case 'ip':
case 'url':
$filter = constant('FILTER_VALIDATE_' . strtoupper($rule[1]));
if (!filter_var($value, $filter))
{
$this->errors[$variable][] = $message;
}
break;
default:
$this->errors[$variable] = 'Invalid filter, expecting boolean, email, float, int, ip or url.';
break;
}
break;
// }}}
// {{{ Checks using strlen()
case 'length':
$length = strlen($value);
switch ($rule[1])
{
case '<':
$valid = $length < $rule[2];
break;
case '<=':
$valid = $length <= $rule[2];
break;
case '==':
$valid = $length == $rule[2];
break;
case '!=':
$valid = $length != $rule[2];
break;
case '>=':
$valid = $length >= $rule[2];
break;
case '>':
$valid = $length > $rule[2];
break;
default:
$valid = false;
$message = 'Invalid operator, expecting <, <=, ==, !=, >= or >.';
break;
}
if (!$valid)
{
$this->errors[$variable][] = $message;
}
break;
// }}}
// {{{ Checks using preg_match()
case 'regex':
if (preg_match($rule[1], $value))
{
$this->errors[$variable][] = $message;
}
break;
// }}}
// @todo case 'alpha':
// @todo case 'alphanumeric':
// @todo case 'date':
// @todo case 'range':
}
}
}
}
}
}
}
// if PUT or DELETE, need to update the super globals directly as
// they do not stay in sync. Probably need to make them global in
// this class method
//
// $_PUT = $GLOBALS['_PUT'];
}
if ($this->errors)
{
throw new \Exception('Missing or invalid parameters.', 400);
}
parent::__construct();
// Checks if the request method has been implemented
if (get_class($this) != 'Pickles\\Resource')
{
if (!method_exists($this, $method))
{
throw new \Exception('Method not allowed.', 405);
}
else
{
// Starts a timer before the resource is executed
if ($this->config['profiler'])
{
$timer = get_class($this) . '->' . $method . '()';
Profiler::timer($timer);
}
$this->response = $this->$method();
// Stops the resource timer
if ($this->config['profiler'])
{
Profiler::timer($timer);
}
}
}
}
catch (\Exception $e)
{
$code = $e->getCode();
// Anything below 200 is probably a PHP error
if ($code < 200)
{
$code = 500;
}
$this->status = $code;
$this->message = $e->getMessage();
}
}
public function respond()
{
http_response_code($this->status);
header('Content-Type: application/json');
header('X-Powered-By: Pickles (http://picklesphp.com)');
$meta = [
'status' => $this->status,
'message' => $this->message,
];
// Forces errors to be an array of arrays
if ($this->errors)
{
foreach ($this->errors as $key => $error)
{
if (!is_array($error))
{
$this->errors[$key] = [$error];
}
}
}
foreach (['echo', 'limit', 'offset', 'errors'] as $variable)
{
if ($this->$variable)
{
$meta[$variable] = $this->$variable;
}
}
$response = ['meta' => $meta];
foreach (['response', 'profiler'] as $variable)
{
if ($this->$variable)
{
$response[$variable] = $this->$variable;
}
}
if ($this->config['profiler'])
{
$response['profiler'] = Profiler::report();
}
$pretty = isset($_REQUEST['pretty']) ? JSON_PRETTY_PRINT : false;
echo json_encode($response, $pretty);
}
}

113
src/Router.php Normal file
View file

@ -0,0 +1,113 @@
<?php
/**
* Endpoint Router
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @copyright Copyright 2007-2014, Josh Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @link https://github.com/joshtronic/pickles
* @package Pickles
*/
namespace Pickles;
/**
* Router Class
*
* The heavy lifter of Pickles, makes the calls to get the session and
* configuration loaded. Loads modules, serves up user authentication when the
* module asks for it, and loads the viewer that the module requested. Default
* values are present to make things easier on the user.
*
* @usage <code>new Pickles\Router;</code>
*/
class Router extends Object
{
/**
* Constructor
*
* To save a few keystrokes, the Controller is executed as part of the
* constructor instead of via a method. You either want the Controller or
* you don't.
*/
public function __construct()
{
parent::__construct();
try
{
// Secure by default
if (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] == false)
{
throw new \Exception('HTTPS is required.', 400);
}
// Grabs the requested page
$request = $_REQUEST['request'];
$components = explode('/', $request);
$nouns = [];
$uids = [];
$version = array_shift($components);
$_SERVER['__version'] = substr($version, 1);
// Checks if we're trying to rock some OAuth
if ($components[0] == 'oauth')
{
$class = 'Pickles\OAuth2\Resource';
}
else
{
// Loops through the components to determine nouns and IDs
foreach ($components as $index => $component)
{
if ($index % 2)
{
$uids[end($nouns)] = $component;
}
else
{
$nouns[] = $component;
}
}
// Creates our class name
array_unshift($nouns, '', 'Pickles', 'App', 'Resources', $version);
$class = implode('\\', $nouns);
}
// Checks that the file is present and contains our class
if (!class_exists($class))
{
throw new \Exception('Not Found.', 404);
}
// Instantiates our resource with the UIDs
$resource = new $class($uids);
}
catch (\Exception $e)
{
// Creates a resource object if we don't have one
if (!isset($resource))
{
$resource = new Resource;
}
$code = $e->getCode();
// Anything below 200 is probably a PHP error
if ($code < 200)
{
$code = 500;
}
$resource->status = $code;
$resource->message = $e->getMessage();
}
$resource->respond();
}
}

245
src/String.php Normal file
View file

@ -0,0 +1,245 @@
<?php
/**
* String Utility Collection
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @copyright Copyright 2007-2014, Josh Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @link https://github.com/joshtronic/pickles
* @package Pickles
*/
namespace Pickles;
/**
* String Class
*
* Just a simple collection of static functions to accomplish some of the
* more redundant string related manipulation.
*/
class String
{
// {{{ Format Phone Number
/**
* Format Phone Number
*
* Formats a 10 digit phone number with dashes as ###-###-####.
*
* @static
* @param string $number number to format
* @param string $replacement output of the string
* @return string formatted phone number
*/
public static function formatPhoneNumber($number, $replacement = '$1-$2-$3')
{
// Strips characters we don't need
$number = str_replace(['(', ')', ' ', '-', '.', '_'], '', $number);
// Formats the number
return preg_replace('/^(\d{3})(\d{3})(.+)$/', $replacement, $number);
}
// }}}
// {{{ Generate Slug
/**
* Generate Slug
*
* Generates a slug from the pass string by lowercasing the string,
* trimming whitespace and converting non-alphanumeric values to
* dashes. Takes care of multiple dashes as well.
*
* @static
* @param string $string to be converted to the slug
* @return string resulting slug
*/
public static function generateSlug($string)
{
$string = strtolower(trim($string));
$string = preg_replace('/[^a-z0-9-]/', '-', $string);
$string = preg_replace('/-+/', '-', $string);
return trim($string, '-');
}
// }}}
// {{{ Is Empty
/**
* Is Empty
*
* Checks if a string is empty. You can use the PHP function empty()
* but that returns true for a string of "0". Last I checked, that's
* not an empty string. PHP's function also doesn't apply trim() to the
* value to ensure it's not just a bunch of spaces.
*
* @static
* @param string $value string(s) to be checked
* @return boolean whether or not the string is empty
*/
public static function isEmpty()
{
foreach (func_get_args() as $value)
{
if (trim($value) == '')
{
return true;
}
}
return false;
}
// }}}
// {{{ Pluralize
/**
* Pluralize
*
* Based on a passed integer, the word will be pluralized. A value of
* zero will also pluralize the word (e.g. 0 things not 0 thing).
*
* @static
* @param string $string the word to plurailze
* @param integer $count the count to interrogate
* @param boolean $both (optional) include count in return
* @return string pluralized word
*/
public static function pluralize($string, $count, $both = false)
{
if ($count != 1)
{
$string .= 's';
}
if ($both)
{
$string = $count . ' ' . $string;
}
return $string;
}
// }}}
// {{{ Random
/**
* Random
*
* Generates a pseudo-random string based on the passed parameters.
*
* Note: Similar characters = 0, O, 1, I (and may be expanded)
*
* @static
* @param integer $length optional length of the generated string
* @param boolean $alpha optional include alpha characters
* @param boolean $numeric optional include numeric characters
* @param boolean $similar optional include similar characters
* @return string generated string
*/
public static function random($length = 8, $alpha = true, $numeric = true, $similar = true)
{
$characters = [];
$string = '';
// Adds alpha characters to the list
if ($alpha == true)
{
if ($similar == true)
{
$characters = array_merge($characters, range('a', 'z'));
}
else
{
$characters = array_merge($characters, range('a', 'h'), range('j', 'n'), range('p', 'z'));
}
}
// Adds numeric characters to the list
if ($numeric == true)
{
if ($similar == true)
{
$characters = array_merge($characters, range('0', '9'));
}
else
{
$characters = array_merge($characters, range('2', '9'));
}
}
if (count($characters) > 0)
{
shuffle($characters);
for ($i = 0; $i < $length; $i++)
{
$string .= $characters[array_rand($characters)];
}
}
return $string;
}
// }}}
// {{{ Truncate
/**
* Truncate
*
* Truncates a string to a specified length and (optionally) adds a
* span to provide a rollover to see the expanded text.
*
* @static
* @param string $string string to truncate
* @param integer $length length to truncate to
* @param boolean $hover (optional) whether or not to add the rollover
* @return string truncate string
*/
public static function truncate($string, $length, $hover = true)
{
if (strlen($string) > $length)
{
if ($hover == true)
{
$string = '<span title="' . $string . '">' . mb_strcut($string, 0, $length, 'UTF-8') . '&hellip;</span>';
}
else
{
$string = mb_strcut($string, 0, $length, 'UTF-8') . '&hellip;';
}
}
return $string;
}
// }}}
// {{{ Upper Words
/**
* Upper Words
*
* Applies strtolower() and ucwords() to the passed string. The
* exception being email addresses which are not formatted at all.
*
* @static
* @param string $string string to format
* @return string formatted string
*/
public static function upperWords($string)
{
// Only formats non-email addresses
if (filter_var($string, FILTER_VALIDATE_EMAIL) == false)
{
$string = ucwords(strtolower($string));
}
return $string;
}
// }}}
}

271
src/Time.php Normal file
View file

@ -0,0 +1,271 @@
<?php
/**
* Time Utility Collection
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @copyright Copyright 2007-2014, Josh Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @link https://github.com/joshtronic/pickles
* @package Pickles
*/
namespace Pickles;
/**
* Time Class
*
* Just a simple collection of static functions to accomplish some of the more
* redundant time and date related manipulation.
*/
class Time
{
// {{{ Intervals (in seconds)
/**
* Minute
*
* Seconds in a minute
*
* @var integer
*/
const MINUTE = 60;
/**
* Hour
*
* Seconds in an hour (minute * 60)
*
* @var integer
*/
const HOUR = 3600;
/**
* Day
*
* Seconds in a day (hour * 24)
*
* @var integer
*/
const DAY = 86400;
/**
* Week
*
* Seconds in a week (day * 7)
*
* @var integer
*/
const WEEK = 604800;
/**
* Month
*
* Seconds in a month (day * 30)
*
* @var integer
*/
const MONTH = 2592000;
/**
* Quarter
*
* Seconds in a quarter (day * 90)
*
* @var integer
*/
const QUARTER = 7776000;
/**
* Year
*
* Seconds in a year (day * 365)
*
* @var integer
*/
const YEAR = 31536000;
/**
* Decade
*
* Seconds in a decade (year * 10)
*
* @var integer
*/
const DECADE = 315360000;
/**
* Century
*
* Seconds in a decade (decade * 10)
*
* @var integer
*/
const CENTURY = 3153600000;
// }}}
/**
* Age
*
* Calculates age based on the passed date.
*
* @static
* @param string $date birth / inception date
* @return integer $age number of years old
*/
public static function age($date)
{
if (!preg_match('/\d{4}-\d{2}-\d{2}/', $date))
{
$date = date('Y-m-d', strtotime($date));
}
list($year, $month, $day) = explode('-', $date, 3);
$age = date('Y') - $year;
if (date('md') < $month . $day)
{
$age--;
}
return $age;
}
/**
* Ago
*
* Generates a relative time (e.g. X minutes ago).
*
* @static
* @param mixed $time timestamp to calculate from
* @return string relative time
*/
public static function ago($time)
{
$current = strtotime(Time::timestamp());
$time = preg_match('/^\d+$/', $time) ? $time : strtotime($time);
if ($current == $time)
{
$time_ago = 'just now';
}
else
{
if ($current > $time)
{
$difference = $current - $time;
$suffix = ' ago';
}
else
{
$difference = $time - $current;
$suffix = ' from now';
}
// Less than 1 minute ago (seconds ago)
if ($difference < 60)
{
$time_ago = 'seconds';
}
// Less than 1 hour ago (minutes ago)
elseif ($difference < Time::HOUR)
{
$minutes = round($difference / 60);
if ($minutes == 60)
{
$time_ago = 'an hour';
}
else
{
$time_ago = ($minutes == 1 ? 'a' : $minutes) . ' minute' . ($minutes != 1 ? 's' : '');
}
}
// Less than 1 day ago (hours ago)
elseif ($difference < Time::DAY)
{
$hours = round($difference / Time::HOUR);
if ($hours == 24)
{
$time_ago = 'a day';
}
else
{
$time_ago = ($hours == 1 ? 'an' : $hours) . ' hour' . ($hours != 1 ? 's' : '');
}
}
// Less than 1 week ago (days ago)
elseif ($difference < Time::WEEK)
{
$days = round($difference / Time::DAY);
if ($days == 7)
{
$time_ago = 'a week';
}
else
{
$time_ago = ($days == 1 ? 'a' : $days) . ' day' . ($days != 1 ? 's' : '');
}
}
// Less than 1 month ago (weeks ago)
elseif ($difference < Time::MONTH)
{
$weeks = round($difference / Time::WEEK);
if ($weeks == 4)
{
$time_ago = 'a month';
}
else
{
$time_ago = ($weeks == 1 ? 'a' : $weeks) . ' week' . ($weeks != 1 ? 's' : '');
}
}
// Less than 1 year ago (months ago)
elseif ($difference < Time::YEAR)
{
$months = round($difference / Time::MONTH);
if ($months == 12)
{
$time_ago = 'a year';
}
else
{
$time_ago = ($months == 1 ? 'a' : $months) . ' month' . ($months != 1 ? 's' : '');
}
}
// Over 1 year ago (years ago)
else
{
$years = round($difference / Time::YEAR);
$time_ago = ($years == 1 ? 'a' : $years) . ' year' . ($years != 1 ? 's' : '');
}
$time_ago .= $suffix;
}
return $time_ago;
}
/**
* Timestamp
*
* Current Universal Time in the specified format.
*
* @static
* @param string $format format of the timestamp
* @return string $timestamp formatted timestamp
*/
public static function timestamp($format = 'Y-m-d H:i:s')
{
return gmdate($format);
}
}

View file

@ -0,0 +1,174 @@
<?php
class ConfigTest extends PHPUnit_Framework_TestCase
{
public static function setUpBeforeClass()
{
touch('/tmp/pickles.php');
}
public static function tearDownAfterClass()
{
unlink('/tmp/pickles.php');
}
/**
* @expectedException Exception
* @expectedExceptionMessage Missing $config array.
*/
public function testMissingConfig()
{
file_put_contents('/tmp/pickles.php', '');
new Pickles\Config('/tmp/pickles.php');
}
/**
* @expectedException Exception
* @expectedExceptionMessage Environments are misconfigured.
*/
public function testMissingEnvironments()
{
file_put_contents('/tmp/pickles.php', '<?php
$config = [];
');
new Pickles\Config('/tmp/pickles.php');
}
/**
* @expectedException Exception
* @expectedExceptionMessage You must pass an environment (e.g. php script.php <environment>)
*/
public function testMissingCLIEnvironment()
{
$_SERVER['argc'] = 1;
file_put_contents('/tmp/pickles.php', '<?php
$config = [
"environments" => [
"local" => "127.0.0.1",
"production" => "123.456.789.0",
],
];
');
new Pickles\Config('/tmp/pickles.php');
}
/**
* @expectedException Exception
* @expectedExceptionMessage You must pass an environment (e.g. php script.php <environment>)
*/
public function testCLIEnvironmentMissingParameter()
{
$_SERVER['argc'] = 1;
new Pickles\Config('/tmp/pickles.php');
}
public function testEnvironmentMatchCLI()
{
$_SERVER['argc'] = 2;
$_SERVER['argv'][1] = 'local';
$config = new Pickles\Config('/tmp/pickles.php');
$this->assertEquals('local', $config['environment']);
}
public function testEnvironmentMatchExact()
{
$_SERVER['REQUEST_METHOD'] = 'GET';
$config = new Pickles\Config('/tmp/pickles.php');
$this->assertEquals('local', $config['environment']);
}
public function testEnvironmentMatchFuzzy()
{
$_SERVER['REQUEST_METHOD'] = 'GET';
$_SERVER['SERVER_NAME'] = '127.0.0.1';
file_put_contents('/tmp/pickles.php', '<?php
$config = [
"environments" => [
"local" => "/127\.0\.0\.[0-9]+/",
"production" => "123.456.789.0",
],
];
');
$config = new Pickles\Config('/tmp/pickles.php');
$this->assertEquals('local', $config['environment']);
}
/**
* @expectedException Exception
* @expectedExceptionMessage Unable to determine the environment.
*/
public function testEnvironmentNoMatch()
{
$_SERVER['REQUEST_METHOD'] = 'GET';
$_SERVER['SERVER_NAME'] = 'lolnope';
new Pickles\Config('/tmp/pickles.php');
}
public function testProductionDisplayErrors()
{
$_SERVER['REQUEST_METHOD'] = 'GET';
$_SERVER['HTTP_HOST'] = '123.456.789.0';
ini_set('display_errors', true);
$this->assertEquals('1', ini_get('display_errors'));
new Pickles\Config('/tmp/pickles.php');
$this->assertEquals('', ini_get('display_errors'));
}
public function testFlatten()
{
$_SERVER['REQUEST_METHOD'] = 'GET';
$_SERVER['HTTP_HOST'] = '123.456.789.0';
file_put_contents('/tmp/pickles.php', '<?php
$config = [
"environments" => [
"local" => "/127\.0\.0\.[0-9]+/",
"production" => "123.456.789.0",
],
"foo" => [
"local" => "barLocal",
"production" => "barProduction",
],
"nestedOne" => [
"nestedTwo" => [
"local" => "nestedLocal",
"production" => "nestedProduction",
],
],
];
');
$config = new Pickles\Config('/tmp/pickles.php');
$this->assertEquals('barProduction', $config['foo']);
$this->assertEquals('nestedProduction', $config['nestedOne']['nestedTwo']);
}
public function testGetInstance()
{
$_SERVER['REQUEST_METHOD'] = 'GET';
$_SERVER['HTTP_HOST'] = '123.456.789.0';
$config = Pickles\Config::getInstance('/tmp/pickles.php');
$this->assertInstanceOf('Pickles\\Config', $config);
}
}

View file

@ -0,0 +1,82 @@
<?php
class ObjectTest extends PHPUnit_Framework_TestCase
{
public static function setUpBeforeClass()
{
$_SERVER['REQUEST_METHOD'] = 'GET';
$_SERVER['SERVER_NAME'] = '127.0.0.1';
file_put_contents('/tmp/pickles.php', '<?php
$config = [
"environments" => [
"local" => "127.0.0.1",
"production" => "123.456.789.0",
],
"pickles" => [
"datasource" => "mysql",
],
"datasources" => [
"mysql" => [
"driver" => "pdo_mysql",
],
],
];
');
$config = Pickles\Config::getInstance('/tmp/pickles.php');
}
public static function tearDownAfterClass()
{
unlink('/tmp/pickles.php');
}
public function testConstructorWithoutObjects()
{
$object = new Pickles\Object();
$this->assertInstanceOf('Pickles\\Config', PHPUnit_Framework_Assert::readAttribute($object, 'config'));
}
public function testConstructorWithObjects()
{
$object = new Pickles\Object('cache');
$this->assertInstanceOf('Pickles\\Cache', $object->cache);
$object = new Pickles\Object(['cache', 'db']);
$this->assertInstanceOf('Pickles\\Cache', $object->cache);
$this->assertInstanceOf('Pickles\\Database', $object->db);
}
public function testGetInstanceWithoutClass()
{
$this->assertFalse(Pickles\Object::getInstance());
}
public function testProfiler()
{
file_put_contents('/tmp/pickles.php', '<?php
$config = [
"environments" => [
"local" => "127.0.0.1",
"production" => "123.456.789.0",
],
"pickles" => [
"datasource" => "mysql",
"profiler" => true,
"foo" => "bar",
],
"datasources" => [
"mysql" => [
"driver" => "pdo_mysql",
],
],
];
');
$config = Pickles\Config::getInstance('/tmp/pickles.php');
$object = new Pickles\Object();
}
}

View file

@ -0,0 +1,66 @@
<?php
class ProfilerTest extends PHPUnit_Framework_TestCase
{
public function testProfiler()
{
// Clears out any previous logging
Pickles\Profiler::report();
$_SERVER['REQUEST_METHOD'] = 'GET';
$_SERVER['SERVER_NAME'] = '127.0.0.1';
file_put_contents('/tmp/pickles.php', '<?php
$config = [
"environments" => [
"local" => "127.0.0.1",
"production" => "123.456.789.0",
],
"pickles" => [
"profiler" => true,
],
];
');
new Pickles\Config('/tmp/pickles.php');
Pickles\Profiler::log('i am a string');
Pickles\Profiler::log(['foo' => 'bar']);
Pickles\Profiler::log($this, 'testProfiler');
Pickles\Profiler::timer('swatch');
Pickles\Profiler::query('SELECT', ['foo' => 'bar'], ['results'], 1, 'EXPLAIN');
Pickles\Profiler::timer('swatch');
Pickles\Profiler::query('SELECT', ['foo' => 'bar'], ['results'], 1);
$report = Pickles\Profiler::report();
$this->assertEquals(7, count($report));
$this->assertEquals(7, count($report['logs']));
$this->assertEquals(5, count($report['logs'][0]));
$this->assertEquals('string', $report['logs'][0]['type']);
$this->assertEquals('i am a string', $report['logs'][0]['details']);
$this->assertEquals('array', $report['logs'][1]['type']);
$this->assertEquals(['foo' => 'bar'], $report['logs'][1]['details']);
$this->assertEquals('object', $report['logs'][2]['type']);
$this->assertEquals(['class' => 'ProfilerTest', 'method' => 'testProfiler()'], $report['logs'][2]['details']);
$this->assertEquals('timer', $report['logs'][3]['type']);
$this->assertEquals('swatch', $report['logs'][3]['details']['name']);
$this->assertEquals('start', $report['logs'][3]['details']['action']);
$this->assertEquals('database', $report['logs'][4]['type']);
$this->assertEquals('SELECT', $report['logs'][4]['details']['query']);
$this->assertEquals(['foo' => 'bar'], $report['logs'][4]['details']['parameters']);
$this->assertEquals(['results'], $report['logs'][4]['details']['results']);
$this->assertEquals(1, $report['logs'][4]['details']['execution_time']);
$this->assertEquals('EXPLAIN', $report['logs'][4]['details']['explain']);
$this->assertEquals('timer', $report['logs'][5]['type']);
$this->assertEquals('swatch', $report['logs'][5]['details']['name']);
$this->assertEquals('stop', $report['logs'][5]['details']['action']);
$this->assertEquals('database', $report['logs'][6]['type']);
$this->assertEquals('SELECT', $report['logs'][6]['details']['query']);
$this->assertEquals(['foo' => 'bar'], $report['logs'][6]['details']['parameters']);
$this->assertEquals(['results'], $report['logs'][6]['details']['results']);
$this->assertEquals(1, $report['logs'][6]['details']['execution_time']);
$this->assertFalse(isset($report['logs'][6]['details']['explain']));
}
}

View file

@ -0,0 +1,282 @@
<?php
namespace Pickles\App\Resources\v1
{
class resource extends \Pickles\Resource
{
public $https = [
'POST' => true,
];
public $auth = [
'DELETE' => true,
];
public $filter = [
'GET' => [
'foo' => 'trim',
'bar' => 'password_hash',
],
];
public $validate = [
'GET' => [
'missing',
'isBoolean' => ['filter:boolean' => 'Error'],
'isNotBoolean' => ['filter:boolean' => 'Error'],
'isEmail' => ['filter:email' => 'Error'],
'isNotEmail' => ['filter:email' => 'Error'],
'isFloat' => ['filter:float' => 'Error'],
'isNotFloat' => ['filter:float' => 'Error'],
'isInt' => ['filter:int' => 'Error'],
'isNotInt' => ['filter:int' => 'Error'],
'isIP' => ['filter:ip' => 'Error'],
'isNotIP' => ['filter:ip' => 'Error'],
'isURL' => ['filter:url' => 'Error'],
'isNotURL' => ['filter:url' => 'Error'],
'invalidRule' => ['filter' => 'Error'],
'lessThan' => ['length:<:10' => 'Error'],
'lessThanEqual' => ['length:<=:10' => 'Error'],
'equal' => ['length:==:10' => 'Error'],
'notEqual' => ['length:!=:10' => 'Error'],
'greaterThan' => ['length:>=:10' => 'Error'],
'greaterThanEqual' => ['length:>:10' => 'Error'],
'greaterLessThan' => ['length:><:10' => 'Error'],
'regex' => ['regex:/[a-z]+/' => 'Error'],
],
];
public function GET()
{
}
public function PUT()
{
return ['foo' => 'bar'];
}
public function ERROR()
{
throw new \Exception('Error');
}
}
}
namespace
{
class ResourceTest extends PHPUnit_Framework_TestCase
{
public function setUp()
{
$_SERVER['REQUEST_METHOD'] = 'GET';
$_SERVER['SERVER_NAME'] = '127.0.0.1';
file_put_contents('/tmp/pickles.php', '<?php
$config = [
"environments" => [
"local" => "127.0.0.1",
"production" => "123.456.789.0",
],
"pickles" => [
"namespace" => "",
"datasource" => "mysql",
],
"datasources" => [
"mysql" => [
"driver" => "pdo_mysql",
],
],
];
');
Pickles\Config::getInstance('/tmp/pickles.php');
}
public function testFilterAndValidate()
{
$response = json_encode([
'meta' => [
'status' => 400,
'message' => 'Missing or invalid parameters.',
'errors' => [
'missing' => ['The missing parameter is required.'],
'isNotBoolean' => ['Error'],
'isNotEmail' => ['Error'],
'isNotFloat' => ['Error'],
'isNotInt' => ['Error'],
'isNotIP' => ['Error'],
'isNotURL' => ['Error'],
'invalidRule' => ['Invalid filter, expecting boolean, email, float, int, ip or url.'],
'greaterLessThan' => ['Invalid operator, expecting <, <=, ==, !=, >= or >.'],
'regex' => ['Error'],
],
],
]);
$this->expectOutputString($response);
$_SERVER['REQUEST_METHOD'] = 'GET';
$_REQUEST['request'] = 'v1/resource/1';
$_GET = [
'foo' => ' bar ',
'bar' => 'unencrypted',
'isBoolean' => true,
'isNotBoolean' => 'invalid',
'isEmail' => 'foo@bar.com',
'isNotEmail' => 'nope',
'isFloat' => 1.234567890,
'isNotFloat' => 'five',
'isInt' => 22381,
'isNotInt' => 'pretzel',
'isIP' => '127.0.0.1',
'isNotIP' => 'home',
'isURL' => 'http://joshtronic.com',
'isNotURL' => 'doubleUdoubleUdoubleUdot',
'invalidRule' => 'invalid',
'lessThan' => '...',
'lessThanEqual' => '.......',
'equal' => '..........',
'notEqual' => '.......',
'greaterThan' => '............',
'greaterThanEqual' => '............',
'greaterLessThan' => '......',
'regex' => 'abc',
];
if (version_compare(PHP_VERSION, '5.5.0', '<'))
{
unset($_GET['bar']);
}
new Pickles\Router();
$this->assertEquals('bar', $_GET['foo']);
if (version_compare(PHP_VERSION, '5.5.0', '>='))
{
$this->assertFalse('unencrypted' == $_GET['bar']);
}
}
public function testHTTPS()
{
$response = json_encode([
'meta' => [
'status' => 400,
'message' => 'HTTPS is required.',
],
]);
$this->expectOutputString($response);
$_SERVER['REQUEST_METHOD'] = 'POST';
$_REQUEST['request'] = 'v1/resource/1';
new Pickles\Router();
}
public function testPUT()
{
$response = json_encode([
'meta' => [
'status' => 200,
'message' => 'OK',
],
'response' => [
'foo' => 'bar',
],
]);
$this->expectOutputString($response);
$_SERVER['REQUEST_METHOD'] = 'PUT';
$_REQUEST['request'] = 'v1/resource/1';
new Pickles\Router();
}
public function testMisconfiguredAuth()
{
$response = json_encode([
'meta' => [
'status' => 401,
'message' => 'Authentication is not configured properly.',
],
]);
$this->expectOutputString($response);
$_SERVER['REQUEST_METHOD'] = 'DELETE';
$_REQUEST['request'] = 'v1/resource/1';
new Pickles\Router();
}
public function testMethodNotAllowed()
{
$response = json_encode([
'meta' => [
'status' => 405,
'message' => 'Method not allowed.',
],
]);
$this->expectOutputString($response);
$_SERVER['REQUEST_METHOD'] = 'NOPE';
$_REQUEST['request'] = 'v1/resource/1';
new Pickles\Router();
}
public function testLowErrorCode()
{
$response = json_encode([
'meta' => [
'status' => 500,
'message' => 'Error',
],
]);
$this->expectOutputString($response);
$_SERVER['REQUEST_METHOD'] = 'ERROR';
$_REQUEST['request'] = 'v1/resource/1';
new Pickles\Router();
}
public function testProfiler()
{
$this->expectOutputRegex('/"profiler":{/');
file_put_contents('/tmp/pickles.php', '<?php
$config = [
"environments" => [
"local" => "127.0.0.1",
"production" => "123.456.789.0",
],
"pickles" => [
"namespace" => "",
"datasource" => "mysql",
"profiler" => true,
],
"datasources" => [
"mysql" => [
"driver" => "pdo_mysql",
],
],
];
');
Pickles\Config::getInstance('/tmp/pickles.php');
$_SERVER['REQUEST_METHOD'] = 'PUT';
$_REQUEST['request'] = 'v1/resource/1';
new Pickles\Router();
}
}
}

View file

@ -0,0 +1,101 @@
<?php
namespace Pickles\App\Resources\v1
{
class router extends \Pickles\Resource
{
}
}
namespace
{
class RouterTest extends PHPUnit_Framework_TestCase
{
public function testServerError()
{
$response = json_encode([
'meta' => [
'status' => 500,
'message' => 'Undefined index: request',
],
]);
$this->expectOutputString($response);
$_SERVER['REQUEST_METHOD'] = 'GET';
$_SERVER['SERVER_NAME'] = '127.0.0.1';
file_put_contents('/tmp/pickles.php', '<?php
$config = [
"environments" => [
"local" => "127.0.0.1",
"production" => "123.456.789.0",
],
"pickles" => [
"namespace" => "",
],
"datasources" => [],
];
');
Pickles\Config::getInstance('/tmp/pickles.php');
new Pickles\Router();
}
public function testNotFound()
{
$response = json_encode([
'meta' => [
'status' => 404,
'message' => 'Not Found.',
],
]);
$this->expectOutputString($response);
$_SERVER['REQUEST_METHOD'] = 'GET';
$_REQUEST['request'] = 'v1/doesnotexist';
new Pickles\Router();
}
// We're just testing that the class can be loaded, not that it will
// work. That logic is off in ResourceTest
public function testFoundWithUID()
{
Pickles\Object::$instances = [];
$_SERVER['REQUEST_METHOD'] = 'GET';
$_SERVER['SERVER_NAME'] = '127.0.0.1';
file_put_contents('/tmp/pickles.php', '<?php
$config = [
"environments" => [
"local" => "127.0.0.1",
"production" => "123.456.789.0",
],
"datasources" => [],
];
');
Pickles\Config::getInstance('/tmp/pickles.php');
$response = json_encode([
'meta' => [
'status' => 405,
'message' => 'Method not allowed.',
],
]);
$this->expectOutputString($response);
$_SERVER['REQUEST_METHOD'] = 'GET';
$_REQUEST['request'] = 'v1/router/1';
new Pickles\Router();
}
}
}

View file

@ -0,0 +1,125 @@
<?php
class StringTest extends PHPUnit_Framework_TestCase
{
/**
* @dataProvider providerFormatPhoneNumber
*/
public function testFormatPhoneNumber($a, $b)
{
$this->assertEquals(Pickles\String::formatPhoneNumber($a), $b);
}
public function providerFormatPhoneNumber()
{
return [
['1234567890', '123-456-7890'],
['123 456 7890', '123-456-7890'],
['123.456.7890', '123-456-7890'],
['123_456_7890', '123-456-7890'],
['1234567890', '123-456-7890'],
['1234-56-7890', '123-456-7890'],
['(123) 456-7890', '123-456-7890'],
['1234567890 x1000', '123-456-7890x1000'],
['(123) 456-7890_x10.00', '123-456-7890x1000'],
];
}
public function testIsEmpty()
{
$this->assertTrue(Pickles\String::isEmpty(''));
$this->assertTrue(Pickles\String::isEmpty(' '));
$this->assertTrue(Pickles\String::isEmpty(false));
$this->assertTrue(Pickles\String::isEmpty(null));
$this->assertTrue(Pickles\String::isEmpty(true, false));
$this->assertFalse(Pickles\String::isEmpty(0));
$this->assertFalse(Pickles\String::isEmpty('foo'));
$this->assertFalse(Pickles\String::isEmpty(' bar '));
$this->assertFalse(Pickles\String::isEmpty(true));
}
public function testRandom()
{
$this->assertEquals(strlen(Pickles\String::random()), 8);
$this->assertEquals(strlen(Pickles\String::random(16)), 16);
$this->assertEquals(preg_match('/[a-z0-9]/', Pickles\String::random(32, true, true)), 1);
$this->assertEquals(preg_match('/[a-z]/', Pickles\String::random(32, true, false)), 1);
$this->assertEquals(preg_match('/[0-9]/', Pickles\String::random(32, false, true)), 1);
$this->assertEquals(preg_match('/[0-9]/', Pickles\String::random(32, true, false)), 0);
$this->assertEquals(preg_match('/[a-z]/', Pickles\String::random(32, false, true)), 0);
$this->assertEquals(preg_match('/[a-z0-9]/', Pickles\String::random(32, false, false)), 0);
}
public function testRandomSimilarFalse()
{
$this->assertRegExp('/[a-hj-np-z2-9]{8}/', Pickles\String::random(8, true, true, false));
}
/**
* @dataProvider providerTruncate
*/
public function testTruncate($a, $b, $c, $d)
{
$this->assertEquals(Pickles\String::truncate($a, $b, $c), $d);
}
public function providerTruncate()
{
return [
['foo bar', 3, true, '<span title="foo bar">foo&hellip;</span>'],
['foo bar', 3, false, 'foo&hellip;'],
['foo bar', 7, true, 'foo bar'],
['foo bar', 8, true, 'foo bar'],
];
}
/**
* @dataProvider providerUpperWords
*/
public function testUpperWords($a, $b)
{
$this->assertEquals(Pickles\String::upperWords($a), $b);
}
public function providerUpperWords()
{
return [
['foo bar', 'Foo Bar'],
['FOO BAR', 'Foo Bar'],
['fOO bAR', 'Foo Bar'],
['foo@bar.com', 'foo@bar.com'],
['FOO@BAR.COM', 'FOO@BAR.COM'],
];
}
/**
* @dataProvider providerGenerateSlug
*/
public function testGenerateSlug($a, $b)
{
$this->assertEquals($b, Pickles\String::generateSlug($a));
}
public function providerGenerateSlug()
{
return [
['TEST STRING', 'test-string'],
['Test String', 'test-string'],
['TEST STRING', 'test-string'],
['#! Test String', 'test-string'],
['-test--string-', 'test-string'],
];
}
public function testPluralize()
{
$this->assertEquals('test', Pickles\String::pluralize('test', 1, false));
$this->assertEquals('1 test', Pickles\String::pluralize('test', 1, true));
$this->assertEquals('tests', Pickles\String::pluralize('test', 2, false));
$this->assertEquals('2 tests', Pickles\String::pluralize('test', 2, true));
}
}

182
tests/Pickles/TimeTest.php Normal file
View file

@ -0,0 +1,182 @@
<?php
class TimeTest extends PHPUnit_Framework_TestCase
{
public function setUp()
{
date_default_timezone_set('GMT');
}
/**
* @dataProvider providerAge
*/
public function testAge($a, $b)
{
$this->assertEquals(Pickles\Time::age($a), $b);
}
public function providerAge()
{
$time = strtotime('-25 years');
return [
[date('Y-m-d', $time), '25'],
[date('m/d/Y', $time), '25'],
[date('r', $time), '25'],
['today', '0'],
['400 days ago', '1'],
[true, Pickles\Time::age('1969-12-31')],
];
}
public function testAgePastTime()
{
$this->assertEquals(18, Pickles\Time::age(date('Y-m-d', strtotime('-18 years'))));
}
public function testAgeFutureTime()
{
$this->assertEquals(-18, Pickles\Time::age(date('Y-m-d', strtotime('18 years'))));
}
public function testAgeWrongFormat()
{
$this->assertEquals(17, Pickles\Time::age(date('Ymd', strtotime('December 31st -18 years'))));
}
public function testAgoJustNow()
{
$this->assertEquals('just now', Pickles\Time::ago(Pickles\Time::timestamp()));
}
public function testAgoPastTimeSeconds()
{
$this->assertEquals('seconds ago', Pickles\Time::ago(strtotime('-30 seconds')));
}
public function testAgoPastTimeMinute()
{
$this->assertEquals('a minute ago', Pickles\Time::ago(strtotime('-1 minutes')));
}
public function testAgoPastTimeMinutes()
{
$this->assertEquals('5 minutes ago', Pickles\Time::ago(strtotime('-5 minutes')));
}
public function testAgoPastTimeHour()
{
$this->assertEquals('an hour ago', Pickles\Time::ago(strtotime('-1 hours')));
}
public function testAgoPastTimeHours()
{
$this->assertEquals('2 hours ago', Pickles\Time::ago(strtotime('-2 hours')));
}
public function testAgoPastTimeDay()
{
$this->assertEquals('a day ago', Pickles\Time::ago(strtotime('-1 days')));
}
public function testAgoPastTimeDays()
{
$this->assertEquals('2 days ago', Pickles\Time::ago(strtotime('-2 days')));
}
public function testAgoPastTimeWeek()
{
$this->assertEquals('a week ago', Pickles\Time::ago(strtotime('-1 weeks')));
}
public function testAgoPastTimeWeeks()
{
$this->assertEquals('2 weeks ago', Pickles\Time::ago(strtotime('-2 weeks')));
}
public function testAgoPastTimeMonth()
{
$this->assertEquals('a month ago', Pickles\Time::ago(strtotime('-1 months')));
}
public function testAgoPastTimeMonths()
{
$this->assertEquals('2 months ago', Pickles\Time::ago(strtotime('-2 months')));
}
public function testAgoPastTimeYear()
{
$this->assertEquals('a year ago', Pickles\Time::ago(strtotime('-1 years')));
}
public function testAgoPastTimeYears()
{
$this->assertEquals('2 years ago', Pickles\Time::ago(strtotime('-2 years')));
}
public function testAgoFutureTimeSeconds()
{
$this->assertEquals('seconds from now', Pickles\Time::ago(strtotime('+30 seconds')));
}
public function testAgoFutureTimeMinutes()
{
$this->assertEquals('5 minutes from now', Pickles\Time::ago(strtotime('+5 minutes')));
}
public function testAgoFutureTimeHours()
{
$this->assertEquals('an hour from now', Pickles\Time::ago(strtotime('+1 hour')));
}
public function testAgoFutureTimeDays()
{
$this->assertEquals('a day from now', Pickles\Time::ago(strtotime('+1 day')));
}
public function testAgoFutureTimeWeeks()
{
$this->assertEquals('a week from now', Pickles\Time::ago(strtotime('+1 week')));
}
public function testAgoFutureTimeMonths()
{
$this->assertEquals('a month from now', Pickles\Time::ago(strtotime('+1 month')));
}
public function testAgoFutureTimeYears()
{
$this->assertEquals('a year from now', Pickles\Time::ago(strtotime('+1 year')));
}
public function testTimestamp()
{
$this->assertEquals(gmdate('Y-m-d H:i:s'), Pickles\Time::timestamp());
}
public function testRoundUpHour()
{
$this->assertEquals('an hour ago', Pickles\Time::ago(strtotime('-59 minutes -55 seconds')));
}
public function testRoundUpDay()
{
$this->assertEquals('a day ago', Pickles\Time::ago(strtotime('-23 hours -55 minutes')));
}
public function testRoundUpWeek()
{
$this->assertEquals('a week ago', Pickles\Time::ago(strtotime('-6 days -23 hours')));
}
public function testRoundUpMonth()
{
$this->assertEquals('a month ago', Pickles\Time::ago(strtotime('-29 days')));
}
public function testRoundUpYear()
{
$this->assertEquals('a year ago', Pickles\Time::ago(strtotime('-364 days')));
}
}

20
tests/bootstrap.php Normal file
View file

@ -0,0 +1,20 @@
<?php
require_once 'vendor/autoload.php';
$_SERVER['HTTP_HOST'] = 'testsite.com';
$_SERVER['SERVER_NAME'] = 'Test Server';
$_SERVER['SERVER_ADDR'] = '127.0.0.1';
function setUpRequest($request, $method = 'GET')
{
$_SERVER['REQUEST_URI'] = '/' . $request;
$_SERVER['REQUEST_METHOD'] = $method;
$_REQUEST['request'] = $request;
}
`mysql -e 'TRUNCATE TABLE test.pickles;'`;
`mysql -e 'TRUNCATE TABLE test.mypickles;'`;
`mysql -e 'TRUNCATE TABLE test.users;'`;
`echo 'flush_all' | nc localhost 11211`;

View file

@ -1,59 +0,0 @@
<?php
require_once 'classes/Convert.php';
define('JSON_AVAILABLE', true);
class ConvertTest extends PHPUnit_Framework_TestCase
{
/**
* @dataProvider providerToJSON
*/
public function testToJSON($a, $b)
{
$this->assertEquals(Convert::toJSON($a), $b);
}
public function providerToJSON()
{
$object = (object)'object';
$object->foo = 'foo';
$object->bar = 'bar';
return array(
array('', '""'),
array('foo', '"foo"'),
array(array('bar'), '["bar"]'),
array(array('foo', 'bar'), '["foo","bar"]'),
array(19810223, '19810223'),
array(array(1981, 02, 23), '[1981,2,23]'),
array(array('foo', 1981), '["foo",1981]'),
array(array('foo', array('bar')), '["foo",["bar"]]'),
array($object, '{"scalar":"object","foo":"foo","bar":"bar"}'),
array(true, 'true'),
array(false, 'false'),
array(null, 'null'),
);
}
/**
* @dataProvider providerArrayToXML
*/
public function testArrayToXML($a, $b, $c)
{
$this->assertEquals(Convert::arrayToXML($a, $b), $c);
}
public function providerArrayToXML()
{
return array(
array('foo', false, ''),
array(array('foo', 'bar'), false, '<0>foo</0><1>bar</1>'),
array(array('foo', 'bar'), true, "<0>foo</0>\n<1>bar</1>\n"),
array(array('foo' => 'bar'), false, '<foo>bar</foo>'),
array(array('children' => array('child' => array('foo', 'bar'))), false, '<children><child>foo</child><child>bar</child></children>'),
array(array('children' => array('child' => array('foo', 'bar'))), true, "<children>\n\t<child>foo</child>\n\t<child>bar</child>\n</children>\n"),
);
}
}
?>

View file

@ -1,32 +0,0 @@
<?php
require_once 'classes/Date.php';
class DateTest extends PHPUnit_Framework_TestCase
{
/**
* @dataProvider providerAge
*/
public function testAge($a, $b)
{
$this->assertEquals(Date::age($a), $b);
}
public function providerAge()
{
ini_set('date.timezone', 'America/New_York');
$time = strtotime('-25 years');
return array(
array(date('Y-m-d', $time), '25'),
array(date('m/d/Y', $time), '25'),
array(date('r', $time), '25'),
array('today', '0'),
array('400 days ago', '1'),
array(true, Date::age('1969-12-31')),
);
}
}
?>

View file

@ -1,112 +0,0 @@
<?php
require_once 'classes/String.php';
class StringTest extends PHPUnit_Framework_TestCase
{
/**
* @dataProvider providerFormatPhoneNumber
*/
public function testFormatPhoneNumber($a, $b)
{
$this->assertEquals(String::formatPhoneNumber($a), $b);
}
public function providerFormatPhoneNumber()
{
return array(
array('1234567890', '123-456-7890'),
array('123 456 7890', '123-456-7890'),
array('123.456.7890', '123-456-7890'),
array('123_456_7890', '123-456-7890'),
array('1234567890', '123-456-7890'),
array('1234-56-7890', '123-456-7890'),
array('(123) 456-7890', '123-456-7890'),
array('1234567890 x1000', '123-456-7890x1000'),
array('(123) 456-7890_x10.00', '123-456-7890x1000'),
);
}
/**
* @dataProvider providerGenerateGravatarHash
*/
public function testGenerateGravatarHash($a, $b)
{
$this->assertEquals(String::generateGravatarHash($a), $b);
}
public function providerGenerateGravatarHash()
{
return array(
array('foo@bar.com', 'f3ada405ce890b6f8204094deb12d8a8'),
array('FOO@BAR.COM', 'f3ada405ce890b6f8204094deb12d8a8'),
);
}
public function testIsEmpty()
{
$this->assertTrue(String::isEmpty(''));
$this->assertTrue(String::isEmpty(' '));
$this->assertTrue(String::isEmpty(false));
$this->assertTrue(String::isEmpty(null));
$this->assertTrue(String::isEmpty(true, false));
$this->assertFalse(String::isEmpty(0));
$this->assertFalse(String::isEmpty('foo'));
$this->assertFalse(String::isEmpty(' bar '));
$this->assertFalse(String::isEmpty(true));
}
public function testRandom()
{
$this->assertEquals(strlen(String::random()), 8);
$this->assertEquals(strlen(String::random(16)), 16);
$this->assertEquals(preg_match('/[A-Z0-9]/', String::random(32, true, true)), 1);
$this->assertEquals(preg_match('/[A-Z]/', String::random(32, true, false)), 1);
$this->assertEquals(preg_match('/[0-9]/', String::random(32, false, true)), 1);
$this->assertEquals(preg_match('/[0-9]/', String::random(32, true, false)), 0);
$this->assertEquals(preg_match('/[A-Z]/', String::random(32, false, true)), 0);
$this->assertEquals(preg_match('/[A-Z0-9]/', String::random(32, false, false)), 0);
}
/**
* @dataProvider providerTruncate
*/
public function testTruncate($a, $b, $c, $d)
{
$this->assertEquals(String::truncate($a, $b, $c), $d);
}
public function providerTruncate()
{
return array(
array('foo bar', 3, true, '<span title="foo bar" style="cursor:help">foo...</span>'),
array('foo bar', 3, false, 'foo...'),
array('foo bar', 7, true, 'foo bar'),
array('foo bar', 8, true, 'foo bar'),
);
}
/**
* @dataProvider providerUpperWords
*/
public function testUpperWords($a, $b)
{
$this->assertEquals(String::upperWords($a), $b);
}
public function providerUpperWords()
{
return array(
array('foo bar', 'Foo Bar'),
array('FOO BAR', 'Foo Bar'),
array('fOO bAR', 'Foo Bar'),
array('foo@bar.com', 'foo@bar.com'),
array('FOO@BAR.COM', 'FOO@BAR.COM'),
);
}
}
?>

57
tests/schema.sql Normal file
View file

@ -0,0 +1,57 @@
DROP TABLE IF EXISTS pickles;
CREATE TABLE `pickles` (
`id` int(1) unsigned NOT NULL AUTO_INCREMENT,
`field1` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`field2` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL,
`field3` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL,
`field4` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL,
`field5` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL,
`created_id` int(1) unsigned DEFAULT NULL,
`created_at` datetime DEFAULT NULL,
`updated_id` int(1) unsigned DEFAULT NULL,
`updated_at` datetime DEFAULT NULL,
`deleted_id` int(1) unsigned DEFAULT NULL,
`deleted_at` datetime DEFAULT NULL,
`is_deleted` tinyint(1) unsigned DEFAULT '0',
PRIMARY KEY (`id`),
KEY is_deleted (is_deleted)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
DROP TABLE IF EXISTS mypickles;
CREATE TABLE `mypickles` (
`id` int(1) unsigned NOT NULL AUTO_INCREMENT,
`field1` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`field2` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL,
`field3` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL,
`field4` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL,
`field5` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL,
`created_id` int(1) unsigned DEFAULT NULL,
`created_at` datetime DEFAULT NULL,
`updated_id` int(1) unsigned DEFAULT NULL,
`updated_at` datetime DEFAULT NULL,
`deleted_id` int(1) unsigned DEFAULT NULL,
`deleted_at` datetime DEFAULT NULL,
`is_deleted` tinyint(1) unsigned DEFAULT '0',
PRIMARY KEY (`id`),
KEY is_deleted (is_deleted)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
DROP TABLE IF EXISTS users;
CREATE TABLE `users` (
`id` int(1) unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`level` varchar(10) COLLATE utf8_unicode_ci NOT NULL DEFAULT 'USER',
`created_id` int(1) unsigned DEFAULT NULL,
`created_at` datetime NOT NULL,
`updated_id` int(1) unsigned DEFAULT NULL,
`updated_at` datetime DEFAULT NULL,
`deleted_id` int(1) unsigned DEFAULT NULL,
`deleted_at` datetime DEFAULT NULL,
`is_deleted` tinyint(1) unsigned DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
INSERT INTO users (id, username, created_at) VALUES (1000000, 'test', NOW());

15
tests/travis.sh Executable file
View file

@ -0,0 +1,15 @@
#!/bin/sh
VERSION=`phpenv version-name`
if [ "${VERSION}" = 'hhvm' ]
then
PHPINI=/etc/hhvm/php.ini
else
PHPINI=~/.phpenv/versions/$VERSION/etc/php.ini
echo "extension = memcache.so" >> $PHPINI
echo "extension = memcached.so" >> $PHPINI
echo "extension = redis.so" >> $PHPINI
fi

1
vendors/ayah vendored
View file

@ -1 +0,0 @@
ayah-1.1.7

View file

@ -1,482 +0,0 @@
<?php
/*
* Are You A Human
* PHP Integration Library
*
* @version 1.1.8
*
* - Documentation and latest version
* http://portal.areyouahuman.com/help
* - Get an AYAH Publisher Key
* https://portal.areyouahuman.com
* - Discussion group
* http://getsatisfaction.com/areyouahuman
*
* Copyright (c) 2013 AYAH LLC -- http://www.areyouahuman.com
*
* 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.
*
*/
// Only define the AYAH class if it does not already exist.
if ( ! class_exists('AYAH')):
class AYAH {
// Set defaults for values that can be specified via the config file or passed in via __construct.
protected $ayah_publisher_key = '';
protected $ayah_scoring_key = '';
protected $ayah_web_service_host = 'ws.areyouahuman.com';
protected $ayah_debug_mode = FALSE;
protected $ayah_use_curl = TRUE;
protected $session_secret;
protected $__valid_construct_params = array('publisher_key', 'scoring_key', 'web_service_host', 'debug_mode', 'use_curl');
protected $__message_buffer = array();
protected $__version_number = '1.1.7';
/**
* Constructor
* If the session secret exists in input, it grabs it
* @param $params associative array with keys publisher_key, scoring_key, web_service_host
*
*/
public function __construct($params = array())
{
// Try to load the ayah_config.php file.
if ( ! $this->__load_config_file())
{
$this->__log("DEBUG", __FUNCTION__, "The ayah_config.php file is missing.");
}
// Get and use any valid parameters that were passed in via the $params array.
foreach ((array)$this->__valid_construct_params as $partial_variable_name)
{
// Build the full variable name...and create an upper case version.
$variable_name = "ayah_" . $partial_variable_name;
$uc_variable_name = strtoupper($variable_name);
// Check to see if it was passed in via $params.
if (isset($params[$partial_variable_name]))
{
$this->{$variable_name} = $params[$partial_variable_name];
}
// Check to see if it was defined in the ayah_config file.
elseif (defined($uc_variable_name))
{
$this->{$variable_name} = constant($uc_variable_name);
}
}
// Generate some warnings/errors if needed variables are not set.
if ($this->ayah_publisher_key == "")
{
$this->__log("ERROR", __FUNCTION__, "Warning: Publisher key is not defined. This won't work.");
}
else
{
$this->__log("DEBUG", __FUNCTION__, "Publisher key: '$this->ayah_publisher_key'");
}
if ($this->ayah_scoring_key == "")
{
$this->__log("ERROR", __FUNCTION__, "Warning: Scoring key is not defined. This won't work.");
}
else
{
// For security reasons, don't output the scoring key as part of the debug info.
}
if ($this->ayah_web_service_host == "")
{
$this->__log("ERROR", __FUNCTION__, "Warning: Web service host is not defined. This won't work.");
}
else
{
$this->__log("DEBUG", __FUNCTION__, "AYAH Webservice host: '$this->ayah_web_service_host'");
}
// If available, set the session secret.
if(array_key_exists("session_secret", $_REQUEST)) {
$this->session_secret = $_REQUEST["session_secret"];
}
}
/**
* Returns the markup for the PlayThru
*
* @return string
*/
public function getPublisherHTML($config = array())
{
// Initialize.
$session_secret = "";
$fields = array('config' => $config);
$webservice_url = '/ws/setruntimeoptions/' . $this->ayah_publisher_key;
// If necessary, process the config data.
if ( ! empty($config))
{
// Log it.
$this->__log("DEBUG", __FUNCTION__, "Setting runtime options...config data='".implode(",", $config)."'");
// Add the gameid to the options url.
if (array_key_exists("gameid", $config))
{
$webservice_url .= '/' . $config['gameid'];
}
}
// Call the webservice and get the response.
$resp = $this->doHttpsPostReturnJSONArray($this->ayah_web_service_host, $webservice_url, $fields);
if ($resp)
{
// Get the session secret from the response.
$session_secret = $resp->session_secret;
// Build the url to the AYAH webservice.
$url = 'https://'; // The AYAH webservice API requires https.
$url.= $this->ayah_web_service_host; // Add the host.
$url.= "/ws/script/"; // Add the path to the API script.
$url.= urlencode($this->ayah_publisher_key); // Add the encoded publisher key.
$url.= (empty($session_secret))? "" : "/".$session_secret; // If set, add the session_secret.
// Build and return the needed HTML code.
return "<div id='AYAH'></div><script src='". $url ."' type='text/javascript' language='JavaScript'></script>";
}
else
{
// Build and log a detailed message.
$url = "https://".$this->ayah_web_service_host.$webservice_url;
$message = "Unable to connect to the AYAH webservice server. url='$url'";
$this->__log("ERROR", __FUNCTION__, $message);
// Build and display a helpful message to the site user.
$style = "padding: 10px; border: 1px solid #EED3D7; background: #F2DEDE; color: #B94A48;";
$message = "Unable to load the <i>Are You a Human</i> PlayThru&trade;. Please contact the site owner to report the problem.";
echo "<p style=\"$style\">$message</p>\n";
}
}
/**
* Check whether the user is a human
* Wrapper for the scoreGame API call
*
* @return boolean
*/
public function scoreResult() {
$result = false;
if ($this->session_secret) {
$fields = array(
'session_secret' => urlencode($this->session_secret),
'scoring_key' => $this->ayah_scoring_key
);
$resp = $this->doHttpsPostReturnJSONArray($this->ayah_web_service_host, "/ws/scoreGame", $fields);
if ($resp) {
$result = ($resp->status_code == 1);
}
}
else
{
$this->__log("DEBUG", __FUNCTION__, "Unable to score the result. Please check that your ayah_config.php file contains your correct publisher key and scoring key.");
}
return $result;
}
/**
* Records a conversion
* Called on the goal page that A and B redirect to
* A/B Testing Specific Function
*
* @return boolean
*/
public function recordConversion() {
// Build the url to the AYAH webservice..
$url = 'https://'; // The AYAH webservice API requires https.
$url.= $this->ayah_web_service_host; // Add the host.
$url.= "/ws/recordConversion/"; // Add the path to the API script.
$url.= urlencode($this->ayah_publisher_key); // Add the encoded publisher key.
if( isset( $this->session_secret ) ){
return '<iframe style="border: none;" height="0" width="0" src="' . $url . '"></iframe>';
} else {
$this->__log("ERROR", __FUNCTION__, 'AYAH Conversion Error: No Session Secret');
return FALSE;
}
}
/**
* Do a HTTPS POST, return some JSON decoded as array (Internal function)
* @param $host hostname
* @param $path path
* @param $fields associative array of fields
* return JSON decoded data structure or empty data structure
*/
protected function doHttpsPostReturnJSONArray($hostname, $path, $fields) {
$result = $this->doHttpsPost($hostname, $path, $fields);
if ($result) {
$result = $this->doJSONArrayDecode($result);
} else {
$this->__log("ERROR", __FUNCTION__, "Post to https://$hostname$path returned no result.");
$result = array();
}
return $result;
}
// Internal function; does an HTTPS post
protected function doHttpsPost($hostname, $path, $fields) {
$result = "";
// URLencode the post string
$fields_string = "";
foreach($fields as $key=>$value) {
if (is_array($value)) {
if ( ! empty($value)) {
foreach ($value as $k => $v) {
$fields_string .= $key . '['. $k .']=' . $v . '&';
}
} else {
$fields_string .= $key . '=&';
}
} else {
$fields_string .= $key.'='.$value.'&';
}
}
rtrim($fields_string,'&');
// Use cURL?
if ($this->__use_curl())
{
// Build the cURL url.
$curl_url = "https://" . $hostname . $path;
// Log it.
$this->__log("DEBUG", __FUNCTION__, "Using cURl: url='$curl_url', fields='$fields_string'");
// Initialize cURL session.
if ($ch = curl_init($curl_url))
{
// Set the cURL options.
curl_setopt($ch, CURLOPT_POST, count($fields));
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
// Execute the cURL request.
$result = curl_exec($ch);
// Close the curl session.
curl_close($ch);
}
else
{
// Log it.
$this->__log("DEBUG", __FUNCTION__, "Unable to initialize cURL: url='$curl_url'");
}
}
else
{
// Log it.
$this->__log("DEBUG", __FUNCTION__, "Using fsockopen(): fields='$fields_string'");
// Build a header
$http_request = "POST $path HTTP/1.1\r\n";
$http_request .= "Host: $hostname\r\n";
$http_request .= "Content-Type: application/x-www-form-urlencoded;\r\n";
$http_request .= "Content-Length: " . strlen($fields_string) . "\r\n";
$http_request .= "User-Agent: AreYouAHuman/PHP " . $this->get_version_number() . "\r\n";
$http_request .= "Connection: Close\r\n";
$http_request .= "\r\n";
$http_request .= $fields_string ."\r\n";
$result = '';
$errno = $errstr = "";
$fs = fsockopen("ssl://" . $hostname, 443, $errno, $errstr, 10);
if( false == $fs ) {
$this->__log("ERROR", __FUNCTION__, "Could not open socket");
} else {
fwrite($fs, $http_request);
while (!feof($fs)) {
$result .= fgets($fs, 4096);
}
$result = explode("\r\n\r\n", $result, 2);
$result = $result[1];
}
}
// Log the result.
$this->__log("DEBUG", __FUNCTION__, "result='$result'");
// Return the result.
return $result;
}
// Internal function: does a JSON decode of the string
protected function doJSONArrayDecode($string) {
$result = array();
if (function_exists("json_decode")) {
try {
$result = json_decode( $string);
} catch (Exception $e) {
$this->__log("ERROR", __FUNCTION__, "Exception when calling json_decode: " . $e->getMessage());
$result = null;
}
} elseif (file_Exists("json.php")) {
require_once('json.php');
$json = new Services_JSON();
$result = $json->decode($string);
if (!is_array($result)) {
$this->__log("ERROR", __FUNCTION__, "Expected array; got something else: $result");
$result = array();
}
} else {
$this->__log("ERROR", __FUNCTION__, "No JSON decode function available.");
}
return $result;
}
/**
* Get the current debug mode (TRUE or FALSE)
*
* @return boolean
*/
public function debug_mode($mode=null)
{
// Set it if the mode is passed.
if (null !== $mode)
{
// Save it.
$this->ayah_debug_mode = $mode;
// Display a message if debug_mode is TRUE.
if ($mode)
{
$version_number = $this->get_version_number();
$this->__log("DEBUG", "", "Debug mode is now on. (ayah.php version=$version_number)");
// Flush the buffer.
$this->__flush_message_buffer();
}
}
// If necessary, set the default.
if ( ! isset($this->ayah_debug_mode) or (null == $this->ayah_debug_mode)) $this->ayah_debug_mode = FALSE;
// Return TRUE or FALSE.
return ($this->ayah_debug_mode)? TRUE : FALSE;
}
/**
* Get the current version number
*
* @return string
*/
public function get_version_number()
{
return (isset($this->__version_number))? $this->__version_number : FALSE;
}
/**
* Determine whether or not cURL is available to use.
*
* @return boolean
*/
private function __use_curl()
{
if (FALSE === $this->ayah_use_curl)
{
return FALSE;
}
elseif (function_exists('curl_init') and function_exists('curl_exec'))
{
return TRUE;
}
return FALSE;
}
/**
* Load the config file.
*
* @return boolean
*/
private function __load_config_file()
{
// Initialize.
$name = 'ayah_config.php';
$locations = array(
'./',
dirname(__FILE__)."/",
);
// Look for the config file in each location.
foreach ($locations as $location)
{
if (file_exists($location.$name))
{
require_once($location.$name);
return TRUE;
}
}
// Could not find the config file.
return FALSE;
}
/**
* Log a message
*
* @return null
*/
protected function __log($type, $function, $message)
{
// Add a prefix to the message.
$message = __CLASS__ . "::$function: " . $message;
// Is it an error message?
if (FALSE !== stripos($type, "error"))
{
error_log($message);
}
// Build the full message.
$message_style = "padding: 10px; border: 1px solid #EED3D7; background: #F2DEDE; color: #B94A48;";
$full_message = "<p style=\"$message_style\"><strong>$type:</strong> $message</p>\n";
// Output to the screen too?
if ($this->debug_mode())
{
echo "$full_message";
}
else
{
// Add the message to the buffer in case we need it later.
$this->__message_buffer[] = $full_message;
}
}
private function __flush_message_buffer()
{
// Flush the buffer.
if ( ! empty($this->__message_buffer))
{
foreach ($this->__message_buffer as $buffered_message)
{
// Print the buffered message.
echo "$buffered_message";
}
}
}
}
endif; // if ( ! class_exists('AYAH')):

View file

@ -1,13 +0,0 @@
<?php
// Edit the two lines below to use the keys for your site.
// (Note: you can find your keys at http://portal.areyouahuman.com/dashboard)
define( 'AYAH_PUBLISHER_KEY', 'your_publisher_key_goes_here');
define( 'AYAH_SCORING_KEY', 'your_scoring_key_goes_here');
// Set defaults for values needed by the ayah.php file.
// (Note: you do not need to change these.)
define( 'AYAH_WEB_SERVICE_HOST', 'ws.areyouahuman.com');
define( 'AYAH_TIMEOUT', 0);
define( 'AYAH_DEBUG_MODE', FALSE);
define( 'AYAH_USE_CURL', TRUE);

View file

@ -1,811 +0,0 @@
<?php
/**
* @ignore
*/
if (!defined('IN_PHPBB'))
{
exit;
}
/**
* Converts to and from JSON format.
*
* JSON (JavaScript Object Notation) is a lightweight data-interchange
* format. It is easy for humans to read and write. It is easy for machines
* to parse and generate. It is based on a subset of the JavaScript
* Programming Language, Standard ECMA-262 3rd Edition - December 1999.
* This feature can also be found in Python. JSON is a text format that is
* completely language independent but uses conventions that are familiar
* to programmers of the C-family of languages, including C, C++, C#, Java,
* JavaScript, Perl, TCL, and many others. These properties make JSON an
* ideal data-interchange language.
*
* This package provides a simple encoder and decoder for JSON notation. It
* is intended for use with client-side Javascript applications that make
* use of HTTPRequest to perform server communication functions - data can
* be encoded into JSON notation for use in a client-side javascript, or
* decoded from incoming Javascript requests. JSON format is native to
* Javascript, and can be directly eval()'ed with no further parsing
* overhead
*
* All strings should be in ASCII or UTF-8 format!
*
* LICENSE: Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met: Redistributions of source code must retain the
* above copyright notice, this list of conditions and the following
* disclaimer. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* @category
* @package Services_JSON
* @author Michal Migurski <mike-json@teczno.com>
* @author Matt Knapp <mdknapp[at]gmail[dot]com>
* @author Brett Stimmerman <brettstimmerman[at]gmail[dot]com>
* @copyright 2005 Michal Migurski
* @version CVS: $Id: JSON.php,v 1.31 2006/06/28 05:54:17 migurski Exp $
* @license http://www.opensource.org/licenses/bsd-license.php
* @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198
*/
/**
* Marker constant for Services_JSON::decode(), used to flag stack state
*/
define('SERVICES_JSON_SLICE', 1);
/**
* Marker constant for Services_JSON::decode(), used to flag stack state
*/
define('SERVICES_JSON_IN_STR', 2);
/**
* Marker constant for Services_JSON::decode(), used to flag stack state
*/
define('SERVICES_JSON_IN_ARR', 3);
/**
* Marker constant for Services_JSON::decode(), used to flag stack state
*/
define('SERVICES_JSON_IN_OBJ', 4);
/**
* Marker constant for Services_JSON::decode(), used to flag stack state
*/
define('SERVICES_JSON_IN_CMT', 5);
/**
* Behavior switch for Services_JSON::decode()
*/
define('SERVICES_JSON_LOOSE_TYPE', 16);
/**
* Behavior switch for Services_JSON::decode()
*/
define('SERVICES_JSON_SUPPRESS_ERRORS', 32);
/**
* Converts to and from JSON format.
*
* Brief example of use:
*
* <code>
* // create a new instance of Services_JSON
* $json = new Services_JSON();
*
* // convert a complexe value to JSON notation, and send it to the browser
* $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4)));
* $output = $json->encode($value);
*
* print($output);
* // prints: ["foo","bar",[1,2,"baz"],[3,[4]]]
*
* // accept incoming POST data, assumed to be in JSON notation
* $input = file_get_contents('php://input', 1000000);
* $value = $json->decode($input);
* </code>
*/
class Services_JSON
{
/**
* constructs a new JSON instance
*
* @param int $use object behavior flags; combine with boolean-OR
*
* possible values:
* - SERVICES_JSON_LOOSE_TYPE: loose typing.
* "{...}" syntax creates associative arrays
* instead of objects in decode().
* - SERVICES_JSON_SUPPRESS_ERRORS: error suppression.
* Values which can't be encoded (e.g. resources)
* appear as NULL instead of throwing errors.
* By default, a deeply-nested resource will
* bubble up with an error, so all return values
* from encode() should be checked with isError()
*/
function Services_JSON($use = 0)
{
$this->use = $use;
}
/**
* convert a string from one UTF-16 char to one UTF-8 char
*
* Normally should be handled by mb_convert_encoding, but
* provides a slower PHP-only method for installations
* that lack the multibye string extension.
*
* @param string $utf16 UTF-16 character
* @return string UTF-8 character
* @access private
*/
function utf162utf8($utf16)
{
// oh please oh please oh please oh please oh please
if(function_exists('mb_convert_encoding')) {
return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
}
$bytes = (ord($utf16{0}) << 8) | ord($utf16{1});
switch(true) {
case ((0x7F & $bytes) == $bytes):
// this case should never be reached, because we are in ASCII range
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
return chr(0x7F & $bytes);
case (0x07FF & $bytes) == $bytes:
// return a 2-byte UTF-8 character
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
return chr(0xC0 | (($bytes >> 6) & 0x1F))
. chr(0x80 | ($bytes & 0x3F));
case (0xFFFF & $bytes) == $bytes:
// return a 3-byte UTF-8 character
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
return chr(0xE0 | (($bytes >> 12) & 0x0F))
. chr(0x80 | (($bytes >> 6) & 0x3F))
. chr(0x80 | ($bytes & 0x3F));
}
// ignoring UTF-32 for now, sorry
return '';
}
/**
* convert a string from one UTF-8 char to one UTF-16 char
*
* Normally should be handled by mb_convert_encoding, but
* provides a slower PHP-only method for installations
* that lack the multibye string extension.
*
* @param string $utf8 UTF-8 character
* @return string UTF-16 character
* @access private
*/
function utf82utf16($utf8)
{
// oh please oh please oh please oh please oh please
if(function_exists('mb_convert_encoding')) {
return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
}
switch(strlen($utf8)) {
case 1:
// this case should never be reached, because we are in ASCII range
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
return $utf8;
case 2:
// return a UTF-16 character from a 2-byte UTF-8 char
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
return chr(0x07 & (ord($utf8{0}) >> 2))
. chr((0xC0 & (ord($utf8{0}) << 6))
| (0x3F & ord($utf8{1})));
case 3:
// return a UTF-16 character from a 3-byte UTF-8 char
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
return chr((0xF0 & (ord($utf8{0}) << 4))
| (0x0F & (ord($utf8{1}) >> 2)))
. chr((0xC0 & (ord($utf8{1}) << 6))
| (0x7F & ord($utf8{2})));
}
// ignoring UTF-32 for now, sorry
return '';
}
/**
* encodes an arbitrary variable into JSON format
*
* @param mixed $var any number, boolean, string, array, or object to be encoded.
* see argument 1 to Services_JSON() above for array-parsing behavior.
* if var is a strng, note that encode() always expects it
* to be in ASCII or UTF-8 format!
*
* @return mixed JSON string representation of input var or an error if a problem occurs
* @access public
*/
function encode($var)
{
switch (gettype($var)) {
case 'boolean':
return $var ? 'true' : 'false';
case 'NULL':
return 'null';
case 'integer':
return (int) $var;
case 'double':
case 'float':
return (float) $var;
case 'string':
// STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
$ascii = '';
$strlen_var = strlen($var);
/*
* Iterate over every character in the string,
* escaping with a slash or encoding to UTF-8 where necessary
*/
for ($c = 0; $c < $strlen_var; ++$c) {
$ord_var_c = ord($var{$c});
switch (true) {
case $ord_var_c == 0x08:
$ascii .= '\b';
break;
case $ord_var_c == 0x09:
$ascii .= '\t';
break;
case $ord_var_c == 0x0A:
$ascii .= '\n';
break;
case $ord_var_c == 0x0C:
$ascii .= '\f';
break;
case $ord_var_c == 0x0D:
$ascii .= '\r';
break;
case $ord_var_c == 0x22:
case $ord_var_c == 0x2F:
case $ord_var_c == 0x5C:
// double quote, slash, slosh
$ascii .= '\\'.$var{$c};
break;
case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
// characters U-00000000 - U-0000007F (same as ASCII)
$ascii .= $var{$c};
break;
case (($ord_var_c & 0xE0) == 0xC0):
// characters U-00000080 - U-000007FF, mask 110XXXXX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$char = pack('C*', $ord_var_c, ord($var{$c + 1}));
$c += 1;
$utf16 = $this->utf82utf16($char);
$ascii .= sprintf('\u%04s', bin2hex($utf16));
break;
case (($ord_var_c & 0xF0) == 0xE0):
// characters U-00000800 - U-0000FFFF, mask 1110XXXX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$char = pack('C*', $ord_var_c,
ord($var{$c + 1}),
ord($var{$c + 2}));
$c += 2;
$utf16 = $this->utf82utf16($char);
$ascii .= sprintf('\u%04s', bin2hex($utf16));
break;
case (($ord_var_c & 0xF8) == 0xF0):
// characters U-00010000 - U-001FFFFF, mask 11110XXX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$char = pack('C*', $ord_var_c,
ord($var{$c + 1}),
ord($var{$c + 2}),
ord($var{$c + 3}));
$c += 3;
$utf16 = $this->utf82utf16($char);
$ascii .= sprintf('\u%04s', bin2hex($utf16));
break;
case (($ord_var_c & 0xFC) == 0xF8):
// characters U-00200000 - U-03FFFFFF, mask 111110XX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$char = pack('C*', $ord_var_c,
ord($var{$c + 1}),
ord($var{$c + 2}),
ord($var{$c + 3}),
ord($var{$c + 4}));
$c += 4;
$utf16 = $this->utf82utf16($char);
$ascii .= sprintf('\u%04s', bin2hex($utf16));
break;
case (($ord_var_c & 0xFE) == 0xFC):
// characters U-04000000 - U-7FFFFFFF, mask 1111110X
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$char = pack('C*', $ord_var_c,
ord($var{$c + 1}),
ord($var{$c + 2}),
ord($var{$c + 3}),
ord($var{$c + 4}),
ord($var{$c + 5}));
$c += 5;
$utf16 = $this->utf82utf16($char);
$ascii .= sprintf('\u%04s', bin2hex($utf16));
break;
}
}
return '"'.$ascii.'"';
case 'array':
/*
* As per JSON spec if any array key is not an integer
* we must treat the the whole array as an object. We
* also try to catch a sparsely populated associative
* array with numeric keys here because some JS engines
* will create an array with empty indexes up to
* max_index which can cause memory issues and because
* the keys, which may be relevant, will be remapped
* otherwise.
*
* As per the ECMA and JSON specification an object may
* have any string as a property. Unfortunately due to
* a hole in the ECMA specification if the key is a
* ECMA reserved word or starts with a digit the
* parameter is only accessible using ECMAScript's
* bracket notation.
*/
// treat as a JSON object
if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
$properties = array_map(array($this, 'name_value'),
array_keys($var),
array_values($var));
foreach($properties as $property) {
if(Services_JSON::isError($property)) {
return $property;
}
}
return '{' . join(',', $properties) . '}';
}
// treat it like a regular array
$elements = array_map(array($this, 'encode'), $var);
foreach($elements as $element) {
if(Services_JSON::isError($element)) {
return $element;
}
}
return '[' . join(',', $elements) . ']';
case 'object':
$vars = get_object_vars($var);
$properties = array_map(array($this, 'name_value'),
array_keys($vars),
array_values($vars));
foreach($properties as $property) {
if(Services_JSON::isError($property)) {
return $property;
}
}
return '{' . join(',', $properties) . '}';
default:
return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS)
? 'null'
: new Services_JSON_Error(gettype($var)." can not be encoded as JSON string");
}
}
/**
* array-walking function for use in generating JSON-formatted name-value pairs
*
* @param string $name name of key to use
* @param mixed $value reference to an array element to be encoded
*
* @return string JSON-formatted name-value pair, like '"name":value'
* @access private
*/
function name_value($name, $value)
{
$encoded_value = $this->encode($value);
if(Services_JSON::isError($encoded_value)) {
return $encoded_value;
}
return $this->encode(strval($name)) . ':' . $encoded_value;
}
/**
* reduce a string by removing leading and trailing comments and whitespace
*
* @param $str string string value to strip of comments and whitespace
*
* @return string string value stripped of comments and whitespace
* @access private
*/
function reduce_string($str)
{
$str = preg_replace(array(
// eliminate single line comments in '// ...' form
'#^\s*//(.+)$#m',
// eliminate multi-line comments in '/* ... */' form, at start of string
'#^\s*/\*(.+)\*/#Us',
// eliminate multi-line comments in '/* ... */' form, at end of string
'#/\*(.+)\*/\s*$#Us'
), '', $str);
// eliminate extraneous space
return trim($str);
}
/**
* decodes a JSON string into appropriate variable
*
* @param string $str JSON-formatted string
*
* @return mixed number, boolean, string, array, or object
* corresponding to given JSON input string.
* See argument 1 to Services_JSON() above for object-output behavior.
* Note that decode() always returns strings
* in ASCII or UTF-8 format!
* @access public
*/
function decode($str)
{
$str = $this->reduce_string($str);
switch (strtolower($str)) {
case 'true':
return true;
case 'false':
return false;
case 'null':
return null;
default:
$m = array();
if (is_numeric($str)) {
// Lookie-loo, it's a number
// This would work on its own, but I'm trying to be
// good about returning integers where appropriate:
// return (float)$str;
// Return float or int, as appropriate
return ((float)$str == (integer)$str)
? (integer)$str
: (float)$str;
} elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) {
// STRINGS RETURNED IN UTF-8 FORMAT
$delim = substr($str, 0, 1);
$chrs = substr($str, 1, -1);
$utf8 = '';
$strlen_chrs = strlen($chrs);
for ($c = 0; $c < $strlen_chrs; ++$c) {
$substr_chrs_c_2 = substr($chrs, $c, 2);
$ord_chrs_c = ord($chrs{$c});
switch (true) {
case $substr_chrs_c_2 == '\b':
$utf8 .= chr(0x08);
++$c;
break;
case $substr_chrs_c_2 == '\t':
$utf8 .= chr(0x09);
++$c;
break;
case $substr_chrs_c_2 == '\n':
$utf8 .= chr(0x0A);
++$c;
break;
case $substr_chrs_c_2 == '\f':
$utf8 .= chr(0x0C);
++$c;
break;
case $substr_chrs_c_2 == '\r':
$utf8 .= chr(0x0D);
++$c;
break;
case $substr_chrs_c_2 == '\\"':
case $substr_chrs_c_2 == '\\\'':
case $substr_chrs_c_2 == '\\\\':
case $substr_chrs_c_2 == '\\/':
if (($delim == '"' && $substr_chrs_c_2 != '\\\'') ||
($delim == "'" && $substr_chrs_c_2 != '\\"')) {
$utf8 .= $chrs{++$c};
}
break;
case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)):
// single, escaped unicode character
$utf16 = chr(hexdec(substr($chrs, ($c + 2), 2)))
. chr(hexdec(substr($chrs, ($c + 4), 2)));
$utf8 .= $this->utf162utf8($utf16);
$c += 5;
break;
case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F):
$utf8 .= $chrs{$c};
break;
case ($ord_chrs_c & 0xE0) == 0xC0:
// characters U-00000080 - U-000007FF, mask 110XXXXX
//see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$utf8 .= substr($chrs, $c, 2);
++$c;
break;
case ($ord_chrs_c & 0xF0) == 0xE0:
// characters U-00000800 - U-0000FFFF, mask 1110XXXX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$utf8 .= substr($chrs, $c, 3);
$c += 2;
break;
case ($ord_chrs_c & 0xF8) == 0xF0:
// characters U-00010000 - U-001FFFFF, mask 11110XXX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$utf8 .= substr($chrs, $c, 4);
$c += 3;
break;
case ($ord_chrs_c & 0xFC) == 0xF8:
// characters U-00200000 - U-03FFFFFF, mask 111110XX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$utf8 .= substr($chrs, $c, 5);
$c += 4;
break;
case ($ord_chrs_c & 0xFE) == 0xFC:
// characters U-04000000 - U-7FFFFFFF, mask 1111110X
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$utf8 .= substr($chrs, $c, 6);
$c += 5;
break;
}
}
return $utf8;
} elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) {
// array, or object notation
if ($str{0} == '[') {
$stk = array(SERVICES_JSON_IN_ARR);
$arr = array();
} else {
if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
$stk = array(SERVICES_JSON_IN_OBJ);
$obj = array();
} else {
$stk = array(SERVICES_JSON_IN_OBJ);
$obj = new stdClass();
}
}
array_push($stk, array('what' => SERVICES_JSON_SLICE,
'where' => 0,
'delim' => false));
$chrs = substr($str, 1, -1);
$chrs = $this->reduce_string($chrs);
if ($chrs == '') {
if (reset($stk) == SERVICES_JSON_IN_ARR) {
return $arr;
} else {
return $obj;
}
}
//print("\nparsing {$chrs}\n");
$strlen_chrs = strlen($chrs);
for ($c = 0; $c <= $strlen_chrs; ++$c) {
$top = end($stk);
$substr_chrs_c_2 = substr($chrs, $c, 2);
if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) {
// found a comma that is not inside a string, array, etc.,
// OR we've reached the end of the character list
$slice = substr($chrs, $top['where'], ($c - $top['where']));
array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false));
//print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
if (reset($stk) == SERVICES_JSON_IN_ARR) {
// we are in an array, so just push an element onto the stack
array_push($arr, $this->decode($slice));
} elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
// we are in an object, so figure
// out the property name and set an
// element in an associative array,
// for now
$parts = array();
if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
// "name":value pair
$key = $this->decode($parts[1]);
$val = $this->decode($parts[2]);
if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
$obj[$key] = $val;
} else {
$obj->$key = $val;
}
} elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
// name:value pair, where name is unquoted
$key = $parts[1];
$val = $this->decode($parts[2]);
if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
$obj[$key] = $val;
} else {
$obj->$key = $val;
}
}
}
} elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) {
// found a quote, and we are not inside a string
array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c}));
//print("Found start of string at {$c}\n");
} elseif (($chrs{$c} == $top['delim']) &&
($top['what'] == SERVICES_JSON_IN_STR) &&
((strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\\'))) % 2 != 1)) {
// found a quote, we're in a string, and it's not escaped
// we know that it's not escaped becase there is _not_ an
// odd number of backslashes at the end of the string so far
array_pop($stk);
//print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n");
} elseif (($chrs{$c} == '[') &&
in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
// found a left-bracket, and we are in an array, object, or slice
array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false));
//print("Found start of array at {$c}\n");
} elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) {
// found a right-bracket, and we're in an array
array_pop($stk);
//print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
} elseif (($chrs{$c} == '{') &&
in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
// found a left-brace, and we are in an array, object, or slice
array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false));
//print("Found start of object at {$c}\n");
} elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) {
// found a right-brace, and we're in an object
array_pop($stk);
//print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
} elseif (($substr_chrs_c_2 == '/*') &&
in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
// found a comment start, and we are in an array, object, or slice
array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false));
$c++;
//print("Found start of comment at {$c}\n");
} elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) {
// found a comment end, and we're in one now
array_pop($stk);
$c++;
for ($i = $top['where']; $i <= $c; ++$i)
$chrs = substr_replace($chrs, ' ', $i, 1);
//print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
}
}
if (reset($stk) == SERVICES_JSON_IN_ARR) {
return $arr;
} elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
return $obj;
}
}
}
}
/**
* @todo Ultimately, this should just call PEAR::isError()
*/
function isError($data, $code = null)
{
if (class_exists('pear')) {
return PEAR::isError($data, $code);
} elseif (is_object($data) && (get_class($data) == 'services_json_error' ||
is_subclass_of($data, 'services_json_error'))) {
return true;
}
return false;
}
}
if (class_exists('PEAR_Error')) {
class Services_JSON_Error extends PEAR_Error
{
function Services_JSON_Error($message = 'unknown error', $code = null,
$mode = null, $options = null, $userinfo = null)
{
parent::PEAR_Error($message, $code, $mode, $options, $userinfo);
}
}
} else {
/**
* @todo Ultimately, this class shall be descended from PEAR_Error
*/
class Services_JSON_Error
{
function Services_JSON_Error($message = 'unknown error', $code = null,
$mode = null, $options = null, $userinfo = null)
{
}
}
}

View file

@ -1,64 +0,0 @@
<!DOCTYPE html>
<?php
//******************************************************************************
/*
Name: sample.php
Purpose: Provide an example of how to integrate an AYAH PlayThru on PHP web form.
Requirements:
- your web server uses PHP5 (or higher).
- all the AYAH PHP library files are in the same directory as this file.
- the ayah_config.php contains a valid publisher key and scoring key.
- you have read the installation instructions page at:
http://portal.areyouahuman.com/installation/php
Notes: - if the Game Style for your PlayThru is set to "Lightbox", the
PlayThru will not display until after you click the submit button.
To change this setting, use the dashboard at:
http://portal.areyouahuman.com/dashboard.php
*/
//******************************************************************************
// Instantiate the AYAH object. You need to instantiate the AYAH object
// on each page that is using PlayThru.
require_once("ayah.php");
$ayah = new AYAH();
// Check to see if the user has submitted the form. You will need to replace
// 'my_submit_button_name' with the name of your 'Submit' button.
if (array_key_exists('my_submit_button_name', $_POST))
{
// Use the AYAH object to see if the user passed or failed the game.
$score = $ayah->scoreResult();
if ($score)
{
// This happens if the user passes the game. In this case,
// we're just displaying a congratulatory message.
echo "Congratulations: you are a human!";
}
else
{
// This happens if the user does not pass the game.
echo "Sorry, but we were not able to verify you as human. Please try again.";
}
}
?>
<!-- Now we're going to build the form that PlayThru is attached to.
In this example, the form submits to itself. -->
<form method="post" action="">
<p>Please enter your name: <input type="text" name="name" /></p>
<?php
// Use the AYAH object to get the HTML code needed to
// load and run PlayThru. You should place this code
// directly before your 'Submit' button.
echo $ayah->getPublisherHTML();
?>
<!-- Make sure the name of your 'Submit' matches the name you used on line 9. -->
<input type="Submit" name="my_submit_button_name" value=" Submit ">
</form>

View file

@ -1,202 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View file

@ -1,292 +0,0 @@
/*
* Copyright 2009 The Closure Compiler Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Contents
//
The Closure Compiler performs checking, instrumentation, and
optimizations on JavaScript code. The purpose of this README is to
explain how to build and run the Closure Compiler.
The Closure Compiler requires Java 6 or higher.
http://www.java.com/
//
// Building The Closure Compiler
//
There are three ways to get a Closure Compiler executable.
1) Use one we built for you.
Pre-built Closure binaries can be found at
http://code.google.com/p/closure-compiler/downloads/list
2) Check out the source and build it with Apache Ant.
First, check out the full source tree of the Closure Compiler. There
are instructions on how to do this at the project site.
http://code.google.com/p/closure-compiler/source/checkout
Apache Ant is a cross-platform build tool.
http://ant.apache.org/
At the root of the source tree, there is an Ant file named
build.xml. To use it, navigate to the same directory and type the
command
ant jar
This will produce a jar file called "build/compiler.jar".
3) Check out the source and build it with Eclipse.
Eclipse is a cross-platform IDE.
http://www.eclipse.org/
Under Eclipse's File menu, click "New > Project ..." and create a
"Java Project." You will see an options screen. Give the project a
name, select "Create project from existing source," and choose the
root of the checked-out source tree as the existing directory. Verify
that you are using JRE version 6 or higher.
Eclipse can use the build.xml file to discover rules. When you
navigate to the build.xml file, you will see all the build rules in
the "Outline" pane. Run the "jar" rule to build the compiler in
build/compiler.jar.
//
// Running The Closure Compiler
//
Once you have the jar binary, running the Closure Compiler is straightforward.
On the command line, type
java -jar compiler.jar
This starts the compiler in interactive mode. Type
var x = 17 + 25;
then hit "Enter", then hit "Ctrl-Z" (on Windows) or "Ctrl-D" (on Mac or Linux)
and "Enter" again. The Compiler will respond:
var x=42;
The Closure Compiler has many options for reading input from a file,
writing output to a file, checking your code, and running
optimizations. To learn more, type
java -jar compiler.jar --help
You can read more detailed documentation about the many flags at
http://code.google.com/closure/compiler/docs/gettingstarted_app.html
//
// Compiling Multiple Scripts
//
If you have multiple scripts, you should compile them all together with
one compile command.
java -jar compiler.jar --js=in1.js --js=in2.js ... --js_output_file=out.js
The Closure Compiler will concatenate the files in the order they're
passed at the command line.
If you need to compile many, many scripts together, you may start to
run into problems with managing dependencies between scripts. You
should check out the Closure Library. It contains functions for
enforcing dependencies between scripts, and a tool called calcdeps.py
that knows how to give scripts to the Closure Compiler in the right
order.
http://code.google.com/p/closure-library/
//
// Licensing
//
Unless otherwise stated, all source files are licensed under
the Apache License, Version 2.0.
-----
Code under:
src/com/google/javascript/rhino
test/com/google/javascript/rhino
URL: http://www.mozilla.org/rhino
Version: 1.5R3, with heavy modifications
License: Netscape Public License and MPL / GPL dual license
Description: A partial copy of Mozilla Rhino. Mozilla Rhino is an
implementation of JavaScript for the JVM. The JavaScript parser and
the parse tree data structures were extracted and modified
significantly for use by Google's JavaScript compiler.
Local Modifications: The packages have been renamespaced. All code not
relevant to parsing has been removed. A JsDoc parser and static typing
system have been added.
-----
Code in:
lib/rhino
Rhino
URL: http://www.mozilla.org/rhino
Version: Trunk
License: Netscape Public License and MPL / GPL dual license
Description: Mozilla Rhino is an implementation of JavaScript for the JVM.
Local Modifications: Minor changes to parsing JSDoc that usually get pushed
up-stream to Rhino trunk.
-----
Code in:
lib/args4j.jar
Args4j
URL: https://args4j.dev.java.net/
Version: 2.0.16
License: MIT
Description:
args4j is a small Java class library that makes it easy to parse command line
options/arguments in your CUI application.
Local Modifications: None.
-----
Code in:
lib/guava.jar
Guava Libraries
URL: http://code.google.com/p/guava-libraries/
Version: 13.0.1
License: Apache License 2.0
Description: Google's core Java libraries.
Local Modifications: None.
-----
Code in:
lib/jsr305.jar
Annotations for software defect detection
URL: http://code.google.com/p/jsr-305/
Version: svn revision 47
License: BSD License
Description: Annotations for software defect detection.
Local Modifications: None.
-----
Code in:
lib/jarjar.jar
Jar Jar Links
URL: http://jarjar.googlecode.com/
Version: 1.1
License: Apache License 2.0
Description:
A utility for repackaging Java libraries.
Local Modifications: None.
----
Code in:
lib/junit.jar
JUnit
URL: http://sourceforge.net/projects/junit/
Version: 4.10
License: Common Public License 1.0
Description: A framework for writing and running automated tests in Java.
Local Modifications: None.
---
Code in:
lib/protobuf-java.jar
Protocol Buffers
URL: http://code.google.com/p/protobuf/
Version: 2.4.1
License: New BSD License
Description: Supporting libraries for protocol buffers,
an encoding of structured data.
Local Modifications: None
---
Code in:
lib/ant.jar
lib/ant-launcher.jar
URL: http://ant.apache.org/bindownload.cgi
Version: 1.8.1
License: Apache License 2.0
Description:
Ant is a Java based build tool. In theory it is kind of like "make"
without make's wrinkles and with the full portability of pure java code.
Local Modifications: None
---
Code in:
lib/json.jar
URL: http://json.org/java/index.html
Version: JSON version 20090211
License: MIT license
Description:
JSON is a set of java files for use in transmitting data in JSON format.
Local Modifications: None
---
Code in:
tools/maven-ant-tasks-2.1.3.jar
URL: http://maven.apache.org
Version 2.1.3
License: Apache License 2.0
Description:
Maven Ant tasks are used to manage dependencies and to install/deploy to
maven repositories.
Local Modifications: None

Binary file not shown.

View file