Compare commits

...

72 Commits

Author SHA1 Message Date
Marcel Kapfer 36bef95804
Updated README 2018-01-04 00:50:36 +01:00
Marcel Kapfer 49cc36a5c8
Added feature graphic. 2018-01-04 00:36:51 +01:00
Marcel Kapfer 776789da6c Merge branch 'stable' of gitlab.com:mmk2410/rangitaki 2017-05-20 21:03:30 +02:00
Marcel Kapfer 9665f098db README: add Gitter chatroom badge 2017-05-20 21:01:42 +02:00
Marcel Kapfer (mmk2410) b775ab99eb Added tests for BlogListGenerator 2016-12-30 00:05:40 +01:00
Marcel Kapfer (mmk2410) 00d3149360 Hide url blogs from selection field in the rcc 2016-12-30 00:05:01 +01:00
Marcel Kapfer (mmk2410) 623395064f composer update 2016-12-30 00:04:12 +01:00
Marcel Kapfer (mmk2410) 9ac51e0523 Improved testability of BlogListGenerator 2016-12-29 21:59:55 +01:00
Marcel Kapfer (mmk2410) 89e756819d Made BlogListGenerator PSR-2 conform 2016-12-29 21:54:37 +01:00
Marcel Kapfer (mmk2410) 0bb2dede4d Nav item with link to external page 2016-12-29 09:40:35 +01:00
Marcel Kapfer (mmk2410) 65263d4ca0 Added emacs files to gitignore 2016-12-29 09:39:59 +01:00
Marcel Kapfer (mmk2410) 161cfc3187 Merge branch 'release-1.5.0' into stable 2016-08-03 18:34:51 +02:00
Marcel Kapfer (mmk2410) 72bbd8d046 Version bump to 1.5.0 2016-08-03 18:32:40 +02:00
Marcel Kapfer (mmk2410) 92451f15ea Update Script for 1.5.0 2016-08-03 18:29:16 +02:00
Marcel Kapfer (mmk2410) c1a7ede3bc Better code style 2016-08-03 17:19:59 +02:00
Marcel Kapfer (mmk2410) 1aa4b42c0c Prevented a few error logs 2016-08-03 17:16:58 +02:00
Marcel Kapfer (mmk2410) 54132c7218 added excerpt feature to config script 2016-08-03 16:38:50 +02:00
Marcel Kapfer (mmk2410) b439cf27d7 removed nearly useless debug script 2016-08-03 16:33:01 +02:00
Marcel Kapfer (mmk2410) bbdacffc7d Excerpt feature. https://phab.mmk2410.org/T121
Res T121
2016-08-02 19:53:08 +02:00
Marcel Kapfer (mmk2410) 72e11c425e theme recompile 2016-08-02 19:50:54 +02:00
Marcel Kapfer 34e9dd31e4 Merge branch 'correct-meta-tags' into 'master'
correct meta tags

Correct https://gitlab.com/mmk2410/rangitaki/merge_requests/2 

See merge request !3
2016-07-17 09:58:13 +00:00
Stefan 4aeb468fe1 correct meta tags 2016-07-17 08:42:46 +02:00
Marcel Kapfer (mmk2410) e6245524a4 better code style for ArticleGenerator::getArray 2016-06-06 22:22:16 +02:00
Marcel Kapfer (mmk2410) 17e4e5570e "temporary" fix for ArticleGenerator::getSummary 2016-06-06 22:21:38 +02:00
Marcel Kapfer (mmk2410) ad2ff5236b unit test for ArticleGenerator 2016-06-06 22:19:49 +02:00
Marcel Kapfer (mmk2410) 67186f6910 Unit test for Config.php 2016-06-05 22:37:05 +02:00
Marcel Kapfer (mmk2410) 25f1ff3188 still trying to make gitlab ci work 2016-06-04 16:46:36 +02:00
Marcel Kapfer (mmk2410) 6b7bf70ec1 Fixed .gitlab-ci.yml 2016-06-04 10:13:01 +02:00
Marcel Kapfer (mmk2410) 8dc9b50d38 Fixed .gitlab-ci.yml 2016-06-04 10:10:50 +02:00
Marcel Kapfer (mmk2410) cc053c88a1 Fixed .gitlab-ci.yml 2016-06-04 10:07:35 +02:00
Marcel Kapfer (mmk2410) d01570a451 Fixed .gitlab-ci.yml 2016-06-04 10:06:15 +02:00
Marcel Kapfer (mmk2410) 92166b921e Add .gitlab-ci.yml 2016-06-04 10:00:38 +02:00
Marcel Kapfer (mmk2410) 03a24c883b tests 2016-06-04 09:59:11 +02:00
Marcel Kapfer (mmk2410) f938e60c2e Merge branch 'master' of gitlab.com:mmk2410/rangitaki 2016-06-04 09:46:34 +02:00
Marcel Kapfer (mmk2410) 7532af8a80 init script for debugging 2016-06-04 09:45:59 +02:00
Marcel Kapfer (mmk2410) c20c0b4ff9 Merge branch 'stable' of gitlab.com:mmk2410/rangitaki into stable 2016-06-03 16:46:31 +02:00
Marcel Kapfer (mmk2410) 1d79aa4c21 Merge branch 'release-1.4.4' into stable 2016-06-03 16:45:54 +02:00
Marcel Kapfer (mmk2410) 39f022d2dd Version bump to 1.4.4 2016-06-03 16:41:53 +02:00
Marcel Kapfer (mmk2410) e994eb074a Update Script for 1.4.4 2016-06-03 16:39:47 +02:00
Marcel Kapfer (mmk2410) f1cfc0c08c feed: Switched to new PicoFeed implementation 2016-06-03 15:31:37 +02:00
Marcel Kapfer (mmk2410) 6d1a7c7e09 feed: New dependencies, YAML config 2016-06-03 15:30:41 +02:00
Marcel Kapfer (mmk2410) 9fa47ecfd5 Updated copyright text 2016-06-03 15:28:02 +02:00
Marcel Kapfer (mmk2410) 0baffcc5cf Check first if value exists 2016-06-03 15:25:59 +02:00
Marcel Kapfer (mmk2410) 352095a6d2 Fixed .gitignore to prevent hiding the rcc/feed directory.
Ref T118
2016-06-03 15:20:09 +02:00
Marcel Kapfer (mmk2410) 6c9aa05cbb Merge branch 'release-1.4.3' into stable 2016-05-21 21:22:49 +02:00
Marcel Kapfer (mmk2410) 7210e8e1e1 Version bump to 1.4.3 2016-05-21 21:20:47 +02:00
Marcel Kapfer (mmk2410) 8eab76ed20 Update script for version 1.4.3: fixes 2016-05-21 21:20:00 +02:00
Marcel Kapfer (mmk2410) 780db2ae07 Update script for version 1.4.3 2016-05-21 21:06:13 +02:00
Marcel Kapfer (mmk2410) 0c080a2237 Updated texts 2016-05-21 19:57:36 +02:00
Marcel Kapfer (mmk2410) fcb64f23eb nextDESIGN added to delivered themes 2016-05-21 19:51:56 +02:00
Marcel Kapfer (mmk2410) f497b7b87b [FIX] Background layer not removed if drawer closes 2016-05-21 19:49:33 +02:00
Marcel Kapfer (mmk2410) bdc617ffef [FIX] Missing space in drawer between "Blogs on" and blogname. 2016-05-21 19:46:33 +02:00
Marcel Kapfer (mmk2410) e05dc0b173 Merge branch 'release-1.4.2' into stable 2016-05-18 14:52:30 +02:00
Marcel Kapfer (mmk2410) a6019319a2 Version bump 1.4.2 2016-05-18 14:51:13 +02:00
Marcel Kapfer (mmk2410) 71f67d506e Update Script for 1.4.2 2016-05-18 14:47:51 +02:00
Marcel Kapfer (mmk2410) b67c9b3415 FIX: Password verification not implemented in RCC login page 2016-05-18 14:46:10 +02:00
Marcel Kapfer (mmk2410) e059544e90 Merge branch 'release-1.4.1' into stable 2016-05-18 13:37:42 +02:00
Marcel Kapfer (mmk2410) 3a8494417e Version bump to 1.4.1 2016-05-18 13:33:28 +02:00
Marcel Kapfer (mmk2410) d33ff8f984 Update script for 1.4.1 2016-05-18 13:32:44 +02:00
Marcel Kapfer (mmk2410) 007aea9b10 FIX: Missing nodejs dependencies 2016-05-18 07:39:41 +02:00
Marcel Kapfer (mmk2410) 52835db8db FIX: Go Back didn't work 2016-05-18 07:38:40 +02:00
Marcel Kapfer (mmk2410) fb937319db Store password as hash
Resolves T117
2016-05-17 22:37:36 +02:00
Marcel Kapfer (mmk2410) 5e45579ef1 Switch to HTTP Basic Auth
Resolves T115
2016-05-17 22:36:26 +02:00
Marcel Kapfer (mmk2410) 42f1992c97 Require SSL for the RCC.
Resolves T116
2016-05-17 22:34:33 +02:00
Marcel Kapfer (mmk2410) 655b982f9d FIX: Missing nodejs dependencies 2016-05-17 20:59:54 +02:00
Marcel Kapfer (mmk2410) 1b0c92bb31 FIX: Disqus not migrated to new config 2016-05-17 20:58:50 +02:00
Marcel Kapfer (mmk2410) e2d8082c1f Merge branch 'release-1.4.0' into stable 2016-05-07 17:43:03 +02:00
Marcel Kapfer (mmk2410) 23617b21bc Version bump to 1.4.0 2016-05-07 17:41:31 +02:00
Marcel Kapfer (mmk2410) 41c273b962 update script for 1.4.0 2016-05-07 17:32:30 +02:00
Marcel Kapfer (mmk2410) 60b094d5fa add composer's vendor directory 2016-05-07 12:59:40 +02:00
Marcel Kapfer (mmk2410) 01a3860d73 Merged CHANGELOG.txt and CHANGELOG.md 2016-05-03 17:35:42 +02:00
Marcel Kapfer (mmk2410) 331465857c README.md update 2016-04-17 10:45:57 +02:00
702 changed files with 45575 additions and 453 deletions

7
.gitignore vendored
View File

@ -1,6 +1 @@
nbproject/
.idea/
completer.hist
feed/
vendor/
node_modules/
*~

11
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,11 @@
image: php:7.0
before_script:
- bash ci/docker_install.sh > /dev/null
stages:
- test
test:
script:
- phpunit tests/

View File

@ -1,4 +1,42 @@
# Version 1.4.0-beta
# Changelog
- [S] = stable release
- [B] = beta release
- [D] = development release
- [S] release are always compared to the previous [S] release.
## Version 1.5.0 (2016-08-03) [S]
- **[FEATURE]** Ability to only show post excerpts on overview pages
- **[FIX]** Fixed twitter username not specified in connfig.yaml
- **[FIX]** Fixed wrong OpenGraph meta tags
- **[CODE]** Further improved code style
- **[CODE]** Added unit tests for Config.php and ArticleGenerator.php
- **[NOTE]** If you have own language file, please update them. See also the upgrade guide
## Version 1.4.4 (2016-06-03) [S]
- **[FIX]** Error when trying to create a feed
## Version 1.4.3 (2016-05-21) [S]
- **[FIX]** Missing space in drawer between "Blogs on" and blogname
- **[FIX]** Background layer was not removed if drawer was closed
- **[FEATURE]** nextDESIGN theme added to delivered themes
- **[NOTE]** The update script to 1.4.3 works with 1.4.0, 1.4.1 and 1.4.2
## Version 1.4.2 (2016-05-18) [S]
- [FIX]: Password verification not implemented in RCC login page
## Version 1.4.1 (2016-05-18) [S]
- Switch to HTTP Basic Auth for the RCC API
- Store password as hash
- Require SSL for using the RCC and the RCC API
- [FIX] Drawer "Go back" does not work
- [FIX] Missing nodejs dependencies
- [FIX] Disqus not completly migrated to new config
## Version 1.4.0 (2016-05-07) [S]
- Fix: Feeds contain no text
- Switch to YAML as config language
@ -12,3 +50,142 @@
- Building and minimizing with Gulp
- Open links in articles in a new tab
- Better code style: PSR-2
## Version 1.4.0-beta (2016-04-27) [B]
- Fix: Feeds contain no text
- Switch to YAML as config language
- Scripts for
- Switching from config.php to config.yaml
- Initializing RCC
- Initializing Rangitaki
- Rangitaki API
- Switch from JavaScript to CoffeeScript
- Switch from CSS to SASS
- Building and minimizing with Gulp
- Open links in articles in a new tab
- Better code style: PSR-2
## Version 1.3.0 (2016-02-16) [S]
- Respecting do-not-track
- Atom feed
- Title fix
- Switch to composer
## Version 1.2.1 (2016-01-11) [S]
- Support for PHP 7
## Version 1.2.0 (2015-12-24) [S]
- Pagination: Split your blog posts over several page
- JavaScript Extension Support
- RCC: Write Posts
- RCC: Delete Posts
- RCC: Upload Media
- RCC: Edit Posts
## Version 1.1.90 (2015-12-21) [B]
- BUGFIX: ArticleGenerator error when no tags set
- Pagination: Localized strings
## Version 1.1.2 (2015-12-20) [D]
- Pagination
- Code style imporvements
## Version 1.1.1 (2015-12-07) [D]
- BUGFIX: RCC: new post: post title was the blog title
- BUGFIX: RCC: new post filename just the date without the time.
- Code highlight css themable
- JavaScript extension support. Just put your extension into ./extensions/
- Link in RCC to go directly to the blog
- RCC: Delete posts
- RCC: Edit posts
## Version 1.1.0 (2015-11-22) [D]
- RCC: Write blog posts
- RCC: Media Upload
- Drawer: Key listener ('ESC' to close, 'm; to open)
- Drawer: Highlight Blogs when hovering
- Drawer: 'X' button
- Metatags / Title based on subblog and / or article
- Update script
## Version 1.0.0 (2015-08-22) [S]
- Post writing in Markdown with a few keywords for the title, tags, date and the author (all optional)
- Multiple blogs
- A Subpages for each article with a comment box (Disqus; can be disabled)
- Share buttons (FAB; can be disabled)
- Disqus integration (can be disabled)
- Fast and easy configuration
- Google Analytics (optional)
- Twitter and OpenGraph meta tags
- Different themes
- Easy localization (just 3 (!) strings)
- Custom footer
- Navigation drawer (can be disabled)
- Tags
- Set author and date
- Mobile-first
- Rangitaki Control Center (aka RCC; optional, Read the RCC Documentation)
- Online post upload
## Version 0.9.0 (2015-07-25) [B]
- BUGFIX: 'Blogs of {BLOG NAME}' always shown (even if there are no other blogs)
- pictures in articles not centred
- long links longer than article card (especially a problem on mobile devices)
- Localization strings are now grouped in one array
- Better code (in some parts)
## Version 0.8.0 (2015-07-14) [B]
- Bugfixes and other improvements
## Version 0.7.0 (2015-07-05) [D]
## Version 0.6.0 (2015-07-03) [D]
- Localization support. More information will follow soon
- Theme support. More information will follow (hopefully) soon
- Various improvements (Check the commits for more)
## Version 0.5.0 (2015-06-16) [D]
- Improvements to the Rangitaki Control Center (rcc)
- Material Design (Blog and rcc)
## Version 0.4 (2015-06-14) [D]
- Multiple Blogs
- Online post upload (optional)
- Tags
- Author
## Version 0.3 (2015-06-11) [D]
- Portation of all main features of Version 0.2.2
- Code highlighting
*The first release with the name Rangitaki.
The following releases are of pBlog.*
## Version 0.2.2 (2015-05-13) [S]
- Links are now underlined, when you hover over them
- Simplified it to add the disqus comments
- Added and configuration option for setting a favicon
- Added the option to use Google Analytics
## Version 0.2.1 / pBlog 2.1 (2015-03-29) [S]
- Fix problems when creating article links
TODO: previous releases

View File

@ -1,144 +0,0 @@
[S] = stable release
[B] = beta release
[D] = development release
[S] release are always compared to the previous [S] release.
Version 1.3.0 (2016-02-16) [S]
=============
- Respecting do-not-track
- Atom feed
- Title fix
- Switch to composer
Version 1.2.1 (2016-01-11) [S]
=============
- Support for PHP 7
Version 1.2.0 (2015-12-24) [S]
=============
- Pagination: Split your blog posts over several page
- JavaScript Extension Support
- RCC: Write Posts
- RCC: Delete Posts
- RCC: Upload Media
- RCC: Edit Posts
Version 1.1.90 (2015-12-21) [B]
==============
- BUGFIX: ArticleGenerator error when no tags set
- Pagination: Localized strings
Version 1.1.2 (2015-12-20) [D]
=============
- Pagination
- Code style imporvements
Version 1.1.1 (2015-12-07) [D]
=============
- BUGFIX: RCC: new post: post title was the blog title
- BUGFIX: RCC: new post filename just the date without the time.
- Code highlight css themable
- JavaScript extension support. Just put your extension into ./extensions/
- Link in RCC to go directly to the blog
- RCC: Delete posts
- RCC: Edit posts
Version 1.1.0 (2015-11-22) [D]
=============
- RCC: Write blog posts
- RCC: Media Upload
- Drawer: Key listener ('ESC' to close, 'm; to open)
- Drawer: Highlight Blogs when hovering
- Drawer: 'X' button
- Metatags / Title based on subblog and / or article
- Update script
Version 1.0.0 (2015-08-22) [S]
=============
- Post writing in Markdown with a few keywords for the title, tags, date and the author (all optional)
- Multiple blogs
- A Subpages for each article with a comment box (Disqus; can be disabled)
- Share buttons (FAB; can be disabled)
- Disqus integration (can be disabled)
- Fast and easy configuration
- Google Analytics (optional)
- Twitter and OpenGraph meta tags
- Different themes
- Easy localization (just 3 (!) strings)
- Custom footer
- Navigation drawer (can be disabled)
- Tags
- Set author and date
- Mobile-first
- Rangitaki Control Center (aka RCC; optional, Read the RCC Documentation)
- Online post upload
Version 0.9.0 (2015-07-25) [B]
=============
- BUGFIX: 'Blogs of {BLOG NAME}' always shown (even if there are no other blogs)
- pictures in articles not centred
- long links longer than article card (especially a problem on mobile devices)
- Localization strings are now grouped in one array
- Better code (in some parts)
Version 0.8.0 (2015-07-14) [B]
=============
- Bugfixes and other improvements
Version 0.7.0 (2015-07-05) [D]
=============
Version 0.6.0 (2015-07-03) [D]
=============
- Localization support. More information will follow soon
- Theme support. More information will follow (hopefully) soon
- Various improvements (Check the commits for more)
Version 0.5.0 (2015-06-16) [D]
=============
- Improvements to the Rangitaki Control Center (rcc)
- Material Design (Blog and rcc)
Version 0.4 (2015-06-14) [D]
===========
- Multiple Blogs
- Online post upload (optional)
- Tags
- Author
Version 0.3 (2015-06-11) [D]
===========
- Portation of all main features of Version 0.2.2
- Code highlighting
The first release with the name Rangitaki.
The following releases are of pBlog.
Version 0.2.2 (2015-05-13) [S]
=============
- Links are now underlined, when you hover over them
- Simplified it to add the disqus comments
- Added and configuration option for setting a favicon
- Added the option to use Google Analytics
Version 0.2.1 / pBlog 2.1 (2015-03-29) [S]
=============
- Fix problems when creating article links
TODO: previous releases

View File

@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2015 Marcel Kapfer
Copyright (c) 2015 - 2016 Marcel Kapfer
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -1,18 +1,20 @@
# Rangitaki PHP blogging engine
[![Join the chat at https://gitter.im/rangitaki/rangitaki](https://badges.gitter.im/canax/view.svg)](https://gitter.im/rangitaki/view?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
Rangitaki is a simple to use and easy to configure blogging engine, written in PHP and it has absolutely no database dependencies.
Tested with PHP version 5.5 until 7.0.
![Rangitaki](https://marcel-kapfer.de/blog/media/with-name.png)
![Rangitaki](https://gitlab.com/mmk2410/rangitaki/raw/master/feature-graphic.png)
[Website](https://marcel-kapfer.de/rangitaki)
[Wiki](https://gitlab.com/mmk2410/rangitaki/wikis/home)
[About](https://marcel-kapfer.de/rangitaki/about)
[About](https://gitlab.com/mmk2410/rangitaki/wikis/about)
[Documentation](https://marcel-kapfer.de/rangitaki/docs)
[Documentation](https://gitlab.com/mmk2410/rangitaki/wikis/docs)
[Quick Starting Guide](https://marcel-kapfer.de/rangitaki/docs/quick)
[Quick Starting Guide](https://gitlab.com/mmk2410/rangitaki/wikis/docs/quickstart)
## What is it?
@ -38,14 +40,14 @@ My goal for Rangitaki was (and still is) to create a blogging engine without dat
- JavaScript Extension Support
- Pagination support
- Atom feed generation
- Rangitaki Control Center (RCC; optional, read the [RCC Documentation](https://marcel-kapfer.de/rangitaki/docs/rcc))
- Rangitaki Control Center (RCC; optional, read the [RCC Documentation](https://gitlab.com/mmk2410/rangitaki/wikis/docs/rcc)
- Have a look under 'What is that RCC?' in this readme
## Did you say 'themes'?
Yes. Rangitaki has a theme support which makes it easy to customize your blog concerning design.
[Read the theme guide](https://marcel-kapfer.de/rangitaki/docs/themes)
[Read the theme guide](https://gitlab.com/mmk2410/rangitaki/wikis/docs/themes)
## What is that RCC?
@ -58,16 +60,7 @@ It has the following features:
- Media upload
- Atom feed generation
[Read the RCC documentation](https://marcel-kapfer.de/rangitaki/docs/rcc)
## Where can I see an example?
- Official Rangitaki blog [marcel-kapfer.de/rangitaki/blog](https://marcel-kapfer.de/rangitaki/blog)
- My personal blog
[marcel-kapfer.de/blog](https://marcel-kapfer.de/blog)
Would you like to see your Rangitaki blog here? Write me a message at [marcelmichaelkapfer@yahoo.co.nz](mailto:marcelmichaelkapfer@yahoo.co.nz)
[Read the RCC documentation](https://gitlab.com/mmk2410/rangitaki/wikis/docs/rcc)
## Used Libraries
@ -76,17 +69,23 @@ Would you like to see your Rangitaki blog here? Write me a message at [marcelmic
## Contributing
## Issues, Requests, etc.
For bug reports, feature requests and all other questions or recommendations feel free to create an issue here at [GitLab](https://gitlab.com/mmk2410/rangitaki/issues).
## Code
1. Fork it
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create New Pull Request
5. Create new merge request
Read also the [contributing documentation](https://marcel-kapfer.de/rangitaki/docs/contrib)
Read also the [contributing documentation](https://gitlab.com/mmk2410/rangitaki/wikis/docs/contribute)
## Social
You can follow my personal Twitter and Google+ account to receive news about the Rangitaki blogging engine.
You can follow me on Twitter or subscribe my blog to receive news about Rangitaki.
- [Twitter @mmk2410](https://twitter.com/mmk2410)
- [Google+ +MarcelKapfer](https://plus.google.com/+MarcelMichaelKapfer/posts)
- [Blog mmk2410.org](https://mmk2410.org/), you can view the current posts about Rangitaki on [this page](https://mmk2410.org/tag/rangitaki/).

View File

@ -39,6 +39,8 @@ $themes = getDir('./themes');
$yaml["design"]["theme"] = get("Which theme would you like to use? (" . $themes . ")", $yaml["design"]["theme"], "material-light");
$yaml["design"]["pagination"] =
get("Which posts should be displayed on one page (0 to disable)", $yaml["design"]["pagination"], "0");
$yaml["design"]["excerpt"] =
getBool("Should be overview pages only show a excerpt of the full posts? (on/off)", $yaml["design"]["excerpt"], "off");
$yaml["design"]["favicon"] = get("URL to your favicon", $yaml["design"]["favicon"], "https://example.com/fav.ico");
// rcc
@ -49,6 +51,9 @@ $yaml["rcc"]["api"] = "off";
$langs = getDir('./lang');
$yaml["language"] = get("Choose a language (" . $langs . ")", $yaml["language"], "en");
// social media
$yaml["social"]["twitter"] = get("Your Twitter username:", $yaml["social"]["twitter"], "");
$config->writeConfig($yaml);
function get($question, $value, $default)

View File

@ -23,8 +23,14 @@ if ($password == "") {
exit();
}
$options = [
'cost' => 12
];
$password = password_hash($password, PASSWORD_BCRYPT, $options);
$username = '$username = "' . $username . '";';
$password = '$password = "' . $password . '";';
$password = '$password = \'' . $password . '\';';
$file = '<?php' . "\n" . $username . "\n" . $password . "\n";

2
blogs/external.md Normal file
View File

@ -0,0 +1,2 @@
%TITLE: Docs
%URL: https://mmk2410.org/rangitaki/docs/

View File

@ -2,13 +2,8 @@
This is the Blog of the Blog Engine **Rangitaki**
Rangitaki is based on PHP, XML and Markdown. It is easy to install and to configure.
Rangitaki is based on PHP and Markdown. It is easy to install and to configure.
The latest Version of the 0.2 series is **0.2.2**
The latest version of Rangitaki is 1.4.3.
The latest Version of the development stream isn' ready yet.
** !IMPORTANT! Please read [this](index.php?article=About-the-Future-of-pBlog) for more information about the different versions of pBlog.**
You can find the source code on [GitHub](https://github.com/mmk2410/Rangitaki).
You can find the source code on [GitLab](https://gitlab.com/mmk2410/rangitaki).

15
ci/docker_install.sh Normal file
View File

@ -0,0 +1,15 @@
#!/bin/bash
# Only install dependencies for Docker
[[ ! -e /.dockerenv ]] && [[ ! -e /.dockerinit ]] && exit 0
set -xe
# Install git
apt-get update -yqq
apt-get install git -yqq
# Install phpunit
curl -o /usr/local/bin/phpunit https://phar.phpunit.de/phpunit.phar
chmod +x /usr/local/bin/phpunit

144
composer.lock generated
View File

@ -4,58 +4,8 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "bf0772b9501ce6231c06bfbcdb671d1d",
"content-hash": "49b3f5550e60b62ffeb5306a75a87d97",
"content-hash": "ccdcfdb56ed68253e2388261fbb6d1b3",
"packages": [
{
"name": "bshaffer/oauth2-server-php",
"version": "v1.8.0",
"source": {
"type": "git",
"url": "https://github.com/bshaffer/oauth2-server-php.git",
"reference": "058c98f73209f9c49495e1799d32c035196fe8b8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/bshaffer/oauth2-server-php/zipball/058c98f73209f9c49495e1799d32c035196fe8b8",
"reference": "058c98f73209f9c49495e1799d32c035196fe8b8",
"shasum": ""
},
"require": {
"php": ">=5.3.9"
},
"suggest": {
"aws/aws-sdk-php": "~2.8 is required to use the DynamoDB storage engine",
"firebase/php-jwt": "~2.2 is required to use JWT features",
"predis/predis": "Required to use the Redis storage engine",
"thobbs/phpcassa": "Required to use the Cassandra storage engine"
},
"type": "library",
"autoload": {
"psr-0": {
"OAuth2": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Brent Shaffer",
"email": "bshafs@gmail.com",
"homepage": "http://brentertainment.com"
}
],
"description": "OAuth2 Server for PHP",
"homepage": "http://github.com/bshaffer/oauth2-server-php",
"keywords": [
"auth",
"oauth",
"oauth2"
],
"time": "2015-09-18 18:05:10"
},
{
"name": "codeguy/upload",
"version": "1.3.2",
@ -101,7 +51,7 @@
"upload",
"validation"
],
"time": "2013-07-07 17:01:41"
"time": "2013-07-07T17:01:41+00:00"
},
{
"name": "container-interop/container-interop",
@ -128,22 +78,25 @@
"MIT"
],
"description": "Promoting the interoperability of container objects (DIC, SL, etc.)",
"time": "2014-12-30 15:22:37"
"time": "2014-12-30T15:22:37+00:00"
},
{
"name": "erusev/parsedown",
"version": "1.6.0",
"version": "1.6.1",
"source": {
"type": "git",
"url": "https://github.com/erusev/parsedown.git",
"reference": "3ebbd730b5c2cf5ce78bc1bf64071407fc6674b7"
"reference": "20ff8bbb57205368b4b42d094642a3e52dac85fb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/erusev/parsedown/zipball/3ebbd730b5c2cf5ce78bc1bf64071407fc6674b7",
"reference": "3ebbd730b5c2cf5ce78bc1bf64071407fc6674b7",
"url": "https://api.github.com/repos/erusev/parsedown/zipball/20ff8bbb57205368b4b42d094642a3e52dac85fb",
"reference": "20ff8bbb57205368b4b42d094642a3e52dac85fb",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"autoload": {
"psr-0": {
@ -167,20 +120,20 @@
"markdown",
"parser"
],
"time": "2015-10-04 16:44:32"
"time": "2016-11-02T15:56:58+00:00"
},
{
"name": "fguillot/picofeed",
"version": "v0.1.23",
"version": "v0.1.28",
"source": {
"type": "git",
"url": "https://github.com/fguillot/picoFeed.git",
"reference": "a7c3d420c239fe9ffc39b0d06b6e57db39ce3797"
"reference": "9da506c308bcb40b6fc630f9123466028c03170b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/fguillot/picoFeed/zipball/a7c3d420c239fe9ffc39b0d06b6e57db39ce3797",
"reference": "a7c3d420c239fe9ffc39b0d06b6e57db39ce3797",
"url": "https://api.github.com/repos/fguillot/picoFeed/zipball/9da506c308bcb40b6fc630f9123466028c03170b",
"reference": "9da506c308bcb40b6fc630f9123466028c03170b",
"shasum": ""
},
"require": {
@ -192,6 +145,11 @@
"php": ">=5.3.0",
"zendframework/zendxml": "^1.0"
},
"require-dev": {
"phpdocumentor/reflection-docblock": "2.0.4",
"phpunit/phpunit": "4.8.26",
"symfony/yaml": "2.8.7"
},
"suggest": {
"ext-curl": "PicoFeed will use cURL if present"
},
@ -215,20 +173,20 @@
],
"description": "Modern library to handle RSS/Atom feeds",
"homepage": "https://github.com/fguillot/picoFeed",
"time": "2016-04-17 22:31:55"
"time": "2016-12-29T00:06:41+00:00"
},
{
"name": "nikic/fast-route",
"version": "v0.6.0",
"version": "v1.1.0",
"source": {
"type": "git",
"url": "https://github.com/nikic/FastRoute.git",
"reference": "31fa86924556b80735f98b294a7ffdfb26789f22"
"reference": "f3dcf5130e634b6123d40727d612ec6aa4f61fb3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nikic/FastRoute/zipball/31fa86924556b80735f98b294a7ffdfb26789f22",
"reference": "31fa86924556b80735f98b294a7ffdfb26789f22",
"url": "https://api.github.com/repos/nikic/FastRoute/zipball/f3dcf5130e634b6123d40727d612ec6aa4f61fb3",
"reference": "f3dcf5130e634b6123d40727d612ec6aa4f61fb3",
"shasum": ""
},
"require": {
@ -258,7 +216,7 @@
"router",
"routing"
],
"time": "2015-06-18 19:15:47"
"time": "2016-10-20T17:36:47+00:00"
},
{
"name": "pimple/pimple",
@ -304,20 +262,20 @@
"container",
"dependency injection"
],
"time": "2015-09-11 15:10:35"
"time": "2015-09-11T15:10:35+00:00"
},
{
"name": "psr/http-message",
"version": "1.0",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-message.git",
"reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298"
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-message/zipball/85d63699f0dbedb190bbd4b0d2b9dc707ea4c298",
"reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298",
"url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
"shasum": ""
},
"require": {
@ -345,6 +303,7 @@
}
],
"description": "Common interface for HTTP messages",
"homepage": "https://github.com/php-fig/http-message",
"keywords": [
"http",
"http-message",
@ -353,29 +312,32 @@
"request",
"response"
],
"time": "2015-05-04 20:22:00"
"time": "2016-08-06T14:39:51+00:00"
},
{
"name": "slim/slim",
"version": "3.3.0",
"version": "3.7.0",
"source": {
"type": "git",
"url": "https://github.com/slimphp/Slim.git",
"reference": "939f2e85d57508de9cff241d10091cd972f221c3"
"reference": "4254e40d81559e35cdf856bcbaca5f3af468b7ef"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/slimphp/Slim/zipball/939f2e85d57508de9cff241d10091cd972f221c3",
"reference": "939f2e85d57508de9cff241d10091cd972f221c3",
"url": "https://api.github.com/repos/slimphp/Slim/zipball/4254e40d81559e35cdf856bcbaca5f3af468b7ef",
"reference": "4254e40d81559e35cdf856bcbaca5f3af468b7ef",
"shasum": ""
},
"require": {
"container-interop/container-interop": "^1.1",
"nikic/fast-route": "^0.6",
"nikic/fast-route": "^1.0",
"php": ">=5.5.0",
"pimple/pimple": "^3.0",
"psr/http-message": "^1.0"
},
"provide": {
"psr/http-message-implementation": "1.0"
},
"require-dev": {
"phpunit/phpunit": "^4.0",
"squizlabs/php_codesniffer": "^2.5"
@ -413,36 +375,42 @@
}
],
"description": "Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs",
"homepage": "http://slimframework.com",
"homepage": "https://slimframework.com",
"keywords": [
"api",
"framework",
"micro",
"router"
],
"time": "2016-03-10 21:37:40"
"time": "2016-12-20T20:30:47+00:00"
},
{
"name": "symfony/yaml",
"version": "v3.0.4",
"version": "v3.2.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
"reference": "0047c8366744a16de7516622c5b7355336afae96"
"reference": "a7095af4b97a0955f85c8989106c249fa649011f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/yaml/zipball/0047c8366744a16de7516622c5b7355336afae96",
"reference": "0047c8366744a16de7516622c5b7355336afae96",
"url": "https://api.github.com/repos/symfony/yaml/zipball/a7095af4b97a0955f85c8989106c249fa649011f",
"reference": "a7095af4b97a0955f85c8989106c249fa649011f",
"shasum": ""
},
"require": {
"php": ">=5.5.9"
},
"require-dev": {
"symfony/console": "~2.8|~3.0"
},
"suggest": {
"symfony/console": "For validating YAML files using the lint command"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.0-dev"
"dev-master": "3.2-dev"
}
},
"autoload": {
@ -469,7 +437,7 @@
],
"description": "Symfony Yaml Component",
"homepage": "https://symfony.com",
"time": "2016-03-04 07:55:57"
"time": "2016-12-10T10:07:06+00:00"
},
{
"name": "zendframework/zendxml",
@ -514,7 +482,7 @@
"xml",
"zf2"
],
"time": "2016-02-04 21:02:08"
"time": "2016-02-04T21:02:08+00:00"
}
],
"packages-dev": [],

View File

@ -9,15 +9,19 @@ blog:
intro: 'on'
disqus: rangitaki
analytics: ''
footer: "Rangitaki 2016 <a href=\"https://github.com/mmk2410/Rangitaki\" target=\"blank\">\n github.com/mmk2410/Rangitaki</a>"
footer: "Rangitaki 2016 <a href=\"https://gitlab.com/mmk2410/rangitaki\" target=\"blank\">\n gitlab.com/mmk2410/rangitaki</a>"
url: 'https://example.com/blog/'
design:
excerpt: "off"
fab: 'on'
drawer: 'on'
theme: material-light
pagination: 0
excerpt: 'off'
favicon: 'http://example.com/res/img/favicon.png'
rcc:
rcc: 'on'
api: 'on'
language: en
social:
twitter: ''

BIN
feature-graphic.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

View File

@ -25,7 +25,10 @@ date_default_timezone_set('UTC');
require __DIR__ . '/vendor/autoload.php'; // loading composer libs
require './res/php/Config.php';
require_once './res/php/BlogListGenerator.php';
use mmk2410\rbe\config\Config as Config;
use mmk2410\rbe\BlogListGenerator\BlogListGenerator as BlogListGenerator;
$configParser = new Config('config.yaml', 'vendor/autoload.php');
@ -33,7 +36,7 @@ $config = $configParser->getConfig();
require './lang/' . $config["language"] . ".php"; // Language file
require_once 'res/php/ArticleGenerator.php'; // The article generator
require_once './res/php/BlogListGenerator.php'; // and the blog list generator
// Getting some variables ($_GET and $_SERVER)
$getblog = filter_input(INPUT_GET, "blog"); // get the blog variable
@ -114,10 +117,9 @@ $feedurl = $config["blog"]["url"] . "/feed/" . $blog . ".atom";
<meta property="og:url" content="<?php echo $url; ?>"/>
<meta property="og:image" content="<?php echo $config['design']['favicon']; ?>"/>
<meta property="og:description" content="<?php echo $config['blog']['description']; ?>"/>
<meta property="og:locale:alternate" content="<?php echo $lang; ?>"/>
<!-- Twitter meta tags -->
<meta name="twitter:card" content="summary"/>
<meta name="twitter:site" content="<?php echo $twitter; ?>"/>
<meta name="twitter:site" content="<?php echo $config['social']['twitter']; ?>"/>
<meta name="twitter:title" content="<?php echo $hd_subblog_title; ?>"/>
<meta name="twitter:description" content="<?php echo $config['blog']['description']; ?>"/>
<meta name="twitter:image" content="<?php echo $config['design']['favicon']; ?>"/>
@ -183,7 +185,7 @@ if ($config["design"]["drawer"] == "on") {
echo "<section>";
// 1. Set localized string 2. Set blogtitle
echo "<div class='nav-item-static'>" .
$BLOGLANG['Blogs on'] . $config["blog"]["title"] .
$BLOGLANG['Blogs on'] . " " . $config["blog"]["title"] .
":</div>";
// iterating through the blogs/ directory
foreach ($blogs as $navblog) {
@ -193,8 +195,10 @@ if ($config["design"]["drawer"] == "on") {
if ($getblog == "") { // Run when on main blog
if ($navblog != "main.md") { // excluding main blog
// creating navigation item
BlogListGenerator::listBlog(
"./blogs/", $navblog, $config["blog"]["title"]
echo BlogListGenerator::listBlog(
"./blogs/",
$navblog,
$config["blog"]["title"]
);
}
} else {
@ -202,8 +206,10 @@ if ($config["design"]["drawer"] == "on") {
// -> this blog will be excluded
if ($getblog . ".md" != $navblog) {
// creating navigation item
BlogListGenerator::listBlog(
"./blogs/", $navblog, $blogmaintitle
echo BlogListGenerator::listBlog(
"./blogs/",
$navblog,
$blogmaintitle
);
}
}
@ -214,7 +220,7 @@ if ($config["design"]["drawer"] == "on") {
// If viewing a blog or a tag
?>
<!-- Set a back item instead of the blogs. -->
<a class="nav-item" onclick="goBack()">Go back</a>
<a class="nav-item" onclick="history.go(-1);">Go back</a>
<?php
}
if ($config["blog"]["home"] == "on") { // If a blog home is existend
@ -319,7 +325,11 @@ if ($config["design"]["drawer"] == "on") {
if (strlen($article) >= 3 && substr($article, -3) == ".md") {
// generate the article
ArticleGenerator::newArticle(
$articlesdir, $article, $getblog
$articlesdir,
$article,
$getblog,
$config["design"]["excerpt"],
$BLOGLANG["Read More"]
);
}
}
@ -337,12 +347,20 @@ if ($config["design"]["drawer"] == "on") {
if ($config["design"]["pagination"]) {
if ($posts_amount < $pag_max && $posts_amount >= $pag_min) {
ArticleGenerator::newArticle(
$articlesdir, $article, $getblog
$articlesdir,
$article,
$getblog,
$config["design"]["excerpt"],
$BLOGLANG["Read More"]
);
}
} else {
ArticleGenerator::newArticle(
$articlesdir, $article, $getblog
$articlesdir,
$article,
$getblog,
$config["design"]["excerpt"],
$BLOGLANG["Read More"]
);
}
}
@ -354,7 +372,11 @@ if ($config["design"]["drawer"] == "on") {
} elseif (isset($getarticle)) { // ARTICLE VIEW
// generate the requested article
ArticleGenerator::newArticle(
$articlesdir, $getarticle . ".md", $getblog
$articlesdir,
$getarticle . ".md",
$getblog,
'off',
$BLOGLANG["Read More"]
);
include './res/php/Disqus.php'; // include disques
} else { // SOMETHING STRANGE: THIS SHOULDN'T HAPPEN
@ -417,14 +439,14 @@ if ($config["design"]["drawer"] == "on") {
<script src="./res/js/app.js"></script> <!--include main javascript-->
<!-- JS extension support -->
<?php
if(file_exists("./extensions")) {
$extensions = scandir('./extensions');
foreach ($extensions as $extension) {
if (substr($extension, -3) == ".js") {
echo "<script src='./extensions/$extension'></script>";
}
if (file_exists("./extensions")) {
$extensions = scandir('./extensions');
foreach ($extensions as $extension) {
if (substr($extension, -3) == ".js") {
echo "<script src='./extensions/$extension'></script>";
}
}
}
?>
<?php
require './res/php/GoogleAnalytics.php'; // include google analytics

View File

@ -8,4 +8,5 @@ $BLOGLANG = [
"Check out" => "Schau dir das an:",
"Next Page" => "Nächste Seite",
"Previous Page" => "Vorherige Seite",
"Read More" => "Weiterlesen",
];

View File

@ -8,4 +8,5 @@ $BLOGLANG = [
"Check out" => "Check out:",
"Next Page" => "Next Page",
"Previous Page" => "Previous Page",
"Read More" => "Read More",
];

View File

@ -1,6 +1,6 @@
{
"name": "rangitaki",
"version": "1.4.0-beta",
"version": "1.5.0",
"description": "A simple PHP blogging engine without any database dependencies",
"main": "index.php",
"scripts": {
@ -21,6 +21,7 @@
},
"homepage": "https://gitlab.com/mmk2410/rangitaki#README",
"devDependencies": {
"coffee-script": "^1.10.0",
"del": "^2.2.0",
"gulp": "^3.9.1",
"gulp-coffee": "^2.3.2",
@ -30,6 +31,7 @@
"gulp-size": "^2.1.0",
"gulp-sourcemaps": "^2.0.0-alpha",
"gulp-uglify": "^1.5.3",
"merge-stream": "^1.0.0"
"merge-stream": "^1.0.0",
"node-sass": "^3.7.0"
}
}

View File

@ -1,52 +0,0 @@
<?php
/**
* PHP Version 7
*
* Authentication Helper Class
*
* @category Authentication
* @package Rbe
* @author Marcel Kapfer (mmk2410) <marcelmichaelkapfer@yahoo.co.nz>
* @license MIT License
* @link http://marcel-kapfer.de/rangitaki
*/
namespace mmk2410\rbe\digestAuth;
/**
* PHP Version 7
*
* Authentication Helper Class
*
* @category Authentication
* @package Rbe
* @author Marcel Kapfer (mmk2410) <marcelmichaelkapfer@yahoo.co.nz>
* @license MIT License
* @link http://marcel-kapfer.de/rangitaki
*/
class DigestAuth
{
/**
* parser for http digest
*
* @param $txt data to parse
*
* @return parsed data or FALSE
*/
public function httpDigestParse($txt)
{
// protect against missing data
$needed_parts = array('nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1, 'uri'=>1, 'response'=>1);
$data = array();
$keys = implode('|', array_keys($needed_parts));
preg_match_all('@(' . $keys . ')=(?:([\'"])([^\2]+?)\2|([^\s,]+))@', $txt, $matches, PREG_SET_ORDER);
foreach ($matches as $m) {
$data[$m[1]] = $m[3] ? $m[3] : $m[4];
unset($needed_parts[$m[1]]);
}
return $needed_parts ? false : $data;
}
}

View File

@ -1,39 +1,22 @@
<?php
// Marcel Kapfer (mmk2410)
// License: MIT License
// api digest auth
// HTTP Basic Auth for the API
require 'DigestAuth.php';
$basedir = "../../../";
require '../../ssl.php';
require '../../password.php';
use \mmk2410\rbe\digestAuth\DigestAuth as DigestAuth;
$realm = 'Restricted area';
$users = array($username => $password);
if (empty($_SERVER['PHP_AUTH_DIGEST'])) {
if (!isset($_SERVER['PHP_AUTH_USER'])) {
header('WWW-Authenticate: Basic realm="RCC API"');
header('HTTP/1.1 401 Unauthorized');
header('WWW-Authenticate: Digest realm="'.$realm.
'",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"');
die('Access to RCC API not granted');
}
// analyze the PHP_AUTH_DIGEST variable
if (!($data = DigestAuth::httpDigestParse($_SERVER['PHP_AUTH_DIGEST'])) ||
!isset($users[$data['username']])) {
die('Wrong Credentials!');
}
// generate the valid response
$A1 = md5($data['username'] . ':' . $realm . ':' . $users[$data['username']]);
$A2 = md5($_SERVER['REQUEST_METHOD'].':'.$data['uri']);
$valid_response = md5($A1.':'.$data['nonce'].':'.$data['nc'].':'.$data['cnonce'].':'.$data['qop'].':'.$A2);
if ($data['response'] != $valid_response) {
die('Wrong Credentials!');
echo "Access denied to the RCC API!";
exit;
} elseif ($_SERVER['PHP_AUTH_USER'] != $username ||
!password_verify($_SERVER['PHP_AUTH_PW'], $password)) {
header('HTTP/1.1 401 Unauthorized');
echo "Wrong credentials: Access denied!";
exit;
}

View File

@ -9,13 +9,13 @@ use \Psr\Http\Message\ResponseInterface as Response;
require '../../../vendor/autoload.php';
require '../../../res/php/Config.php';
include '../auth/auth.php';
use \mmk2410\rbe\config\Config as Config;
$config = new Config("../../../config.yaml", '../../../vendor/autoload.php');
$settings = $config->getConfig();
include '../auth/auth.php';
if ($settings["rcc"]["api"] == "on" && $settings["rcc"]["rcc"] == "on") {
$app = new \Slim\App();

View File

@ -10,13 +10,13 @@ require '../../../vendor/autoload.php';
require '../../../res/php/Config.php';
require '../../../res/php/ArticleGenerator.php';
include '../auth/auth.php';
use \mmk2410\rbe\config\Config as Config;
$config = new Config("../../../config.yaml", '../../../vendor/autoload.php');
$settings = $config->getConfig();
include '../auth/auth.php';
if ($settings["rcc"]["api"] == "on" && $settings["rcc"]["rcc"] == "on") {
$app = new \Slim\App();

View File

@ -10,13 +10,13 @@ require '../../../vendor/autoload.php';
require '../../../res/php/Config.php';
require '../../../res/php/ArticleGenerator.php';
include '../auth/auth.php';
use \mmk2410\rbe\config\Config as Config;
$config = new Config("../../../config.yaml", '../../../vendor/autoload.php');
$settings = $config->getConfig();
include '../auth/auth.php';
if ($settings["rcc"]["api"] == "on" && $settings["rcc"]["rcc"] == "on") {
$app = new \Slim\App();

View File

@ -6,13 +6,13 @@
* @package Rcc
* @author Marcel Kapfer (mmk2410) <marcelmichaelkapfer@yahoo.co.nz>
* @license MIT License
* @link https://github.com/mmk2410/rangitaki
* @link https://gitlab.com/mmk2410/rangitaki
*
* Feed Generator
*
* The MIT License
*
* Copyright 2015 mmk2410.
* Copyright 2015 - 2016 (c) mmk2410.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -36,27 +36,35 @@
date_default_timezone_set('UTC');
require "../../vendor/autoload.php";
require_once "../../config.php";
require "../../res/php/Config.php";
require_once "../../res/php/ArticleGenerator.php";
use PicoFeed\Syndication\Atom;
use PicoFeed\Syndication\AtomFeedBuilder;
use PicoFeed\Syndication\AtomItemBuilder;
use \mmk2410\rbe\config\Config as Config;
$config = new Config('../../config.yaml', '../../vendor/autoload.php');
$settings = $config->getConfig();
include '../ssl.php';
session_start();
if ($_SESSION['login']) {
$art_dir = "./../../articles/" . $_GET['blog'] . "/";
$feed_path = "./../../feed/" . $_GET['blog'] . ".atom";
$writer = new Atom();
if ($_GET['blog'] == "main") {
$blogtitle = $settings['blog']['title'];
} else {
$blogtitl = $settings['blog']['title'] . " - " . ucwords($_GET['blog']);
}
$writer->title = $blogtitle;
$writer->site_url = $blogurl;
$writer->feed_url = $blogurl . "/feed/" . $_GET['blog'] . ".atom";
$writer->author = array(
'name' => $blogauthor,
'url' => $blogurl,
'email' => ''
);
$feedBuilder = AtomFeedBuilder::create()
->withTitle($blogtitle)
->withAuthor($settings['blog']['author'])
->withFeedUrl($settings['blog']['url'] . "/feed/" . $_GET['blog'] . ".atom")
->withSiteUrl($settings['blog']['url'])
->withDate(new DateTime(date(DATE_ATOM)));
$articles = scandir($art_dir, 1);
@ -71,25 +79,45 @@ if ($_SESSION['login']) {
$text = Parsedown::instance()
->setBreaksEnabled(true)// with linebreaks
->text($file);
$writer->items[] = array(
'title' => ArticleGenerator::getTitle($art_dir, $article),
'updated' => strtotime(
ArticleGenerator::getDate($art_dir . $article)
),
'url' => $blogurl . "./?article=" .
substr($article, 0, strlen($article) - 3),
'summary'=> ArticleGenerator::getSummary(
$art_dir, $article
),
'content' => $text
);
if (new DateTime(date(DATE_ATOM, strtotime($datestring))) != null) {
$date = new DateTime(
date(
DATE_ATOM,
strtotime($datestring)
)
);
} else {
$date = new DateTime(date(DATE_ATOM));
}
$date = new DateTime(date(DATE_ATOM));
$feedBuilder
->withItem(AtomItemBuilder::create($feedBuilder)
->withTitle(
ArticleGenerator::getTitle($art_dir, $article)
)
->withUrl(
$settings['blog']['url'] . "./?article=" . substr($article, 0, strlen($article) - 3)
)
->withAuthor(
ArticleGenerator::getAuthor($art_dir, $article)
)
->withPublishedDate(
parseDate(ArticleGenerator::getDate($art_dir, $article))
)
->withUpdatedDate(
parseDate(ArticleGenerator::getDate($art_dir, $article))
)
->withSummary(
ArticleGenerator::getSummary($art_dir, $article)
)
->withContent($text));
$amount += 1;
}
}
}
$feed = $writer->execute();
$feed = $feedBuilder->build();
$file = fopen($feed_path, "w");
@ -102,4 +130,19 @@ if ($_SESSION['login']) {
echo "0";
}
?>
function parseDate($datestring)
{
$datetime = new DateTime(date(DATE_ATOM));
try {
$datetime = new DateTime(
date(
DATE_ATOM,
strtotime($datestring)
)
);
} catch (Exception $e) {
$datetime = new DateTime(date(DATE_ATOM));
}
return $datetime;
}

View File

@ -32,6 +32,19 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
require '../vendor/autoload.php';
require '../res/php/Config.php';
require "./../res/php/BlogListGenerator.php";
use \mmk2410\rbe\config\Config as Config;
use mmk2410\rbe\BlogListGenerator\BlogListGenerator as BlogListGenerator;
$config = new Config("../config.yaml", '../vendor/autoload.php');
$settings = $config->getConfig();
include './ssl.php';
?>
<!DOCTYPE html>
@ -64,12 +77,7 @@
<div class="main">
<?php
require '../res/php/Config.php';
use mmk2410\rbe\config\Config as Config;
$configParser = new Config('../config.yaml', '../vendor/autoload.php');
$config = $configParser->getConfig();
$config = $settings;
if ($config["rcc"]["rcc"] == "on") {
include 'password.php';
@ -100,9 +108,9 @@ if ($config["rcc"]["rcc"] == "on") {
<?php
} else {
if ($passwd == $password) {
if (password_verify($passwd, $password)) {
$_SESSION['login'] = true;
include_once "./../res/php/BlogListGenerator.php";
?>
<!-- Post Upload -->
@ -116,8 +124,10 @@ if ($config["rcc"]["rcc"] == "on") {
$blogs = scandir("../blogs/");
foreach ($blogs as $blog) {
if (strlen($blog) >= 3 && substr($blog, -3) == ".md") {
$blog = substr($blog, 0, -3);
echo "<option value='$blog'>$blog</option>";
if (BlogListGenerator::getExternalLink($blog, '../') == null) {
$blog = substr($blog, 0, -3);
echo "<option value='$blog'>$blog</option>";
}
}
}
?>
@ -141,8 +151,10 @@ if ($config["rcc"]["rcc"] == "on") {
$blogs = scandir("../blogs/");
foreach ($blogs as $blog) {
if (strlen($blog) >= 3 && substr($blog, -3) == ".md") {
$blog = substr($blog, 0, -3);
echo "<option value='$blog'>$blog</option>";
if (BlogListGenerator::getExternalLink($blog, '../') == null) {
$blog = substr($blog, 0, -3);
echo "<option value='$blog'>$blog</option>";
}
}
}
?>
@ -189,8 +201,10 @@ if ($config["rcc"]["rcc"] == "on") {
$blogs = scandir("../blogs/");
foreach ($blogs as $blog) {
if (strlen($blog) >= 3 && substr($blog, -3) == ".md") {
$blog = substr($blog, 0, -3);
echo "<option value='$blog'>$blog</option>";
if (BlogListGenerator::getExternalLink($blog, '../') == null) {
$blog = substr($blog, 0, -3);
echo "<option value='$blog'>$blog</option>";
}
}
}
?>
@ -212,8 +226,10 @@ if ($config["rcc"]["rcc"] == "on") {
$blogs = scandir("../blogs/");
foreach ($blogs as $blog) {
if (strlen($blog) >= 3 && substr($blog, -3) == ".md") {
$blog = substr($blog, 0, -3);
echo "<option value='$blog'>$blog</option>";
if (BlogListGenerator::getExternalLink($blog, '../') == null) {
$blog = substr($blog, 0, -3);
echo "<option value='$blog'>$blog</option>";
}
}
}
?>
@ -243,8 +259,10 @@ if ($config["rcc"]["rcc"] == "on") {
$blogs = scandir("../blogs/");
foreach ($blogs as $blog) {
if (strlen($blog) >= 3 && substr($blog, -3) == ".md") {
$blog = substr($blog, 0, -3);
echo "<option value='$blog'>$blog</option>";
if (BlogListGenerator::getExternalLink($blog, '../') == null) {
$blog = substr($blog, 0, -3);
echo "<option value='$blog'>$blog</option>";
}
}
}
?>

View File

@ -1,3 +1,3 @@
<?php
$username = "example";
$password = "example";
$username = "test";
$password = '$2y$12$nHitKTwHqU4GmI3ADVE05eH/723fCNgdQ65kQ53FyZUVVB03BjfCO';

11
rcc/ssl.php Normal file
View File

@ -0,0 +1,11 @@
<?php
// Marcel Kapfer (mmk2410) / Wilson O'Sullivan
// License: MIT License
// SSL Verification
if (isset($settings["rcc"]["debug"]) && $settings["rcc"]["debug"] != "on") {
if (empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on") {
header('HTTP/1.1 400 Bad Request');
exit();
}
}

View File

@ -1,3 +1,3 @@
body{margin-top:94px}.main{height:100%;margin-left:0}.overlay{opacity:0;position:fixed;top:0;left:0;background-color:black;width:100%;z-index:30;height:100%;display:none}.header{top:0;right:0;left:0;width:100%;height:64px;position:absolute}.title{color:#fff;font-size:23px;text-decoration:none;line-height:64px;vertical-align:middle;left:75px}.title>a{text-decoration:none;color:#fff}.fadeout{position:absolute;height:64px;top:0;right:0;width:40px}.nav-img{height:26px;padding:19px;cursor:pointer}.nav{width:300px;position:fixed;height:100%;top:0;left:-301px;z-index:40}.nav-item,.nav-item-static{text-decoration:none;text-indent:0;display:inline-block;height:48px;vertical-align:middle;width:284px;line-height:48px;padding-left:16px;transition:background-color 125ms ease-in-out 0ms}.nav-close{cursor:pointer}.nav-close-img{height:35px;padding:12px}.nav-item{cursor:pointer}.divider{width:100%}.card{margin-right:auto;margin-left:auto;width:75%;padding:24px;margin-bottom:40px;max-width:1160px}.card a{-moz-hyphens:auto;-epub-hyphens:auto;-ms-hyphens:auto;-webkit-hyphens:auto;hyphens:auto;word-wrap:break-word}.headline{display:block;padding-bottom:8px}.card img{max-width:100%;max-height:400px;display:block;margin-left:auto;margin-right:auto}.author{display:block}.fabmenu{position:fixed;bottom:20px;right:20px}.fab{height:60px;width:60px;border-radius:30px;cursor:pointer}.fab-img{width:28px;padding:15px}.subfab{height:45px;width:45px;border-radius:30px;margin-right:auto;margin-left:auto;margin-bottom:25px;display:none}.subfab-img{width:22px;padding:12px}.pag_buttons{margin-right:auto;margin-left:auto;width:calc(75% + 48px);margin-bottom:80px;max-width:1160px;text-align:right}.button{text-decoration:none;color:#fff;line-height:36px;min-width:64px;text-align:center;height:36px;padding:8px;margin-top:4px;margin-bottom:5px;cursor:pointer}.pag_next{margin-left:8px}.footer a{transition:border-bottom-color 150ms ease-in-out 100ms}.footer a:hover{border-bottom-color:#383838}@media screen and (min-width: 1440px){.nav{left:0;padding-top:64px}.nav-close-img{display:none}.nav-close{display:none}.nav-img{display:none}.header{left:300px}.main{margin-left:300px;width:calc(100% - 300px)}}@media screen and (max-width: 720px){.card{width:82%}.pag_buttons{width:calc(82% + 48px)}}
body{margin-top:94px}.main{height:100%;margin-left:0}.overlay{opacity:0;position:fixed;top:0;left:0;background-color:black;width:100%;z-index:30;height:100%;display:none}.header{top:0;right:0;left:0;width:100%;height:64px;position:absolute}.title{color:#fff;font-size:23px;text-decoration:none;line-height:64px;vertical-align:middle;left:75px}.title>a{text-decoration:none;color:#fff}.fadeout{position:absolute;height:64px;top:0;right:0;width:40px}.nav-img{height:26px;padding:19px;cursor:pointer}.nav{width:300px;position:fixed;height:100%;top:0;left:-301px;z-index:40}.nav-item,.nav-item-static{text-decoration:none;text-indent:0;display:inline-block;height:48px;vertical-align:middle;width:284px;line-height:48px;padding-left:16px;transition:background-color 125ms ease-in-out 0ms}.nav-close{cursor:pointer}.nav-close-img{height:35px;padding:12px}.nav-item{cursor:pointer}.divider{width:100%}.card{margin-right:auto;margin-left:auto;width:75%;padding:24px;margin-bottom:40px;max-width:1160px}.card a{-moz-hyphens:auto;-epub-hyphens:auto;-ms-hyphens:auto;-webkit-hyphens:auto;hyphens:auto;word-wrap:break-word}.headline{display:block;padding-bottom:8px}.card img{max-width:100%;max-height:400px;display:block;margin-left:auto;margin-right:auto}.author{display:block}.readmore{padding:12px 0 25px 0}.fabmenu{position:fixed;bottom:20px;right:20px}.fab{height:60px;width:60px;border-radius:30px;cursor:pointer}.fab-img{width:28px;padding:15px}.subfab{height:45px;width:45px;border-radius:30px;margin-right:auto;margin-left:auto;margin-bottom:25px;display:none}.subfab-img{width:22px;padding:12px}.pag_buttons{margin-right:auto;margin-left:auto;width:calc(75% + 48px);margin-bottom:80px;max-width:1160px;text-align:right}.button{text-decoration:none;color:#fff;line-height:36px;min-width:64px;text-align:center;height:36px;padding:8px;margin-top:4px;margin-bottom:5px;cursor:pointer}.pag_next{margin-left:8px}.footer a{transition:border-bottom-color 150ms ease-in-out 100ms}.footer a:hover{border-bottom-color:#383838}@media screen and (min-width: 1440px){.nav{left:0;padding-top:64px}.nav-close-img{display:none}.nav-close{display:none}.nav-img{display:none}.header{left:300px}.main{margin-left:300px;width:calc(100% - 300px)}}@media screen and (max-width: 720px){.card{width:82%}.pag_buttons{width:calc(82% + 48px)}}
/*# sourceMappingURL=rangitaki.css.map */

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
(function(){var n,t,a,e,r,i;r=function(){var e,r;return e=!1,$(".fabmenu").click(function(){return e?(a(),e=!1):(t(),e=!0)}),r=!1,$(".nav-img, .overlay, .nav-close").click(function(){return r?(n(),r=!1):(i(),r=!0)}),$(document).keyup(function(t){return r&&27===t.which?(n(),r=!1):r||77!==t.which?void 0:(i(),r=!0)}),$(".articletext a").attr("target","_blank")},$(document).ready(r),e=function(){return history.go(-1)},t=function(){return $(".subfab").fadeIn(125),$(".fab-img").fadeOut(60,function(){return $(".fab-img").attr("src","./res/img/close.svg"),$(".fab-img").fadeIn(60)})},a=function(){return $(".subfab").fadeOut(125),$(".fab-img").fadeOut(60,function(){return $(".fab-img").attr("src","./res/img/share.svg"),$(".fab-img").fadeIn(60)})},i=function(){return $(".nav").animate({left:"0px"},125),$(".overlay").show(),$(".overlay").animate({opacity:"0.4"},125)},n=function(){return $(".nav").animate({left:"-301px"},125),$(".overlay").animate({opacity:"0.0"},125,function(){return $(".overlay").hide})}}).call(this);
(function(){var n,t,a,e,r;e=function(){var e,i;return e=!1,$(".fabmenu").click(function(){return e?(a(),e=!1):(t(),e=!0)}),i=!1,$(".nav-img, .overlay, .nav-close").click(function(){return i?(n(),i=!1):(r(),i=!0)}),$(document).keyup(function(t){return i&&27===t.which?(n(),i=!1):i||77!==t.which?void 0:(r(),i=!0)}),$(".articletext a").attr("target","_blank")},$(document).ready(e),t=function(){return $(".subfab").fadeIn(125),$(".fab-img").fadeOut(60,function(){return $(".fab-img").attr("src","./res/img/close.svg"),$(".fab-img").fadeIn(60)})},a=function(){return $(".subfab").fadeOut(125),$(".fab-img").fadeOut(60,function(){return $(".fab-img").attr("src","./res/img/share.svg"),$(".fab-img").fadeIn(60)})},r=function(){return $(".nav").animate({left:"0px"},125),$(".overlay").show(),$(".overlay").animate({opacity:"0.4"},125)},n=function(){return $(".nav").animate({left:"-301px"},125),$(".overlay").animate({opacity:"0.0"},125,function(){return $(".overlay").css({display:"none"})})}}).call(this);

View File

@ -59,7 +59,7 @@ class ArticleGenerator
*
* @return Null
*/
function newArticle($directory, $articlefile, $blog)
function newArticle($directory, $articlefile, $blog, $excerpt, $readmore)
{
$article = file_get_contents($directory . $articlefile); // get the file
@ -96,12 +96,39 @@ class ArticleGenerator
echo "<div class='articletext'>";
// print only a excerpt of the post
// with at least 200 characters if possible.
if ( $excerpt == 'on' ) {
$emptyline = strpos($article, "\n\n");
if ( $emptyline !== false ) {
if ( $emptyline < 200) {
$emptyline2 = strpos($article, "\n\n", $emptyline);
if ( $emptyline2 !== false ) {
$article = substr($article, 0, $emptyline2);
} else {
$article = substr($article, 0, $emptyline);
}
} else {
$article = substr($article, 0, $emptyline);
}
} else {
// correct $excerpt for use in line 127.
$excerpt = 'off';
}
}
echo Parsedown::instance()
->setBreaksEnabled(true)
->text($article); // print now the article text as html
echo "</div>";
if ( $excerpt == 'on' ) {
echo "<div class='readmore'><a href='$link'>$readmore</a></div>";
}
if (isset($author)) {
echo "<span class='author'>$author</span>"; // print the author
}
@ -196,15 +223,15 @@ class ArticleGenerator
*/
static function getSummary($directory, $articlefile)
{
$text = getText($directory, $articlefile);
$text = ArticleGenerator::getText($directory, $articlefile);
$pos = stripos($text, ".");
$pos = stripos($text, "\n\n");
if ($pos) {
$offset = $pos + 1;
if ($pos !== false) {
$offset = $pos;
$pos = stripos($text, ".", $offset);
$summary = substr($text, 0, $pos) . ".";
return $summary;
return trim($summary);
} else {
return $text;
}
@ -275,6 +302,10 @@ class ArticleGenerator
public function getArray($directory, $articlefile)
{
$article = file_get_contents($directory . $articlefile);
$title = "";
$date = "";
$author = "";
$tags = array();
if (substr($article, 0, 6) == "%TITLE") { // get and remove the title
$title = substr($article, 8, strpos($article, "\n") - 8);

View File

@ -10,7 +10,7 @@
* @license MIT License
* @link http://marcel-kapfer.de/rangitaki
*/
namespace mmk2410\rbe\BlogListGenerator;
/**
* The blog list generator class is a collection of functions for generating
@ -37,7 +37,7 @@ class BlogListGenerator
*
* @return None
*/
function listBlog($directory, $blogname, $blogmaintitle)
public function listBlog($directory, $blogname, $blogmaintitle)
{
// get content of the blog file;
$blog = file_get_contents($directory . $blogname);
@ -46,18 +46,25 @@ class BlogListGenerator
// check if the first line includes a title
if (substr($blog, 0, 6) == "%TITLE") {
// grab the title
$blog = substr($blog, 8, strpos($blog, "\n") - 8);
$itemname = substr($blog, 8, strpos($blog, "\n") - 8);
// if on main blog
if ($blog == "main") {
if ($itemname == "main") {
// create a nav item to the main blog
echo "<a class='nav-item' href='./'>$blogmaintitle</a>";
$atag = "<a class='nav-item' href='./'>$blogmaintitle</a>";
} else {
// create a link to the blog
$link = "./?blog=" . substr($blogname, 0, -3);
// create a nav item to the blog
echo "<a class='nav-item' href='$link'>$blog</a>";
$atag = "<a class='nav-item' href='$link'>$itemname</a>";
}
$blog = substr($blog, strpos($blog, "\n") + 1);
}
// nav item as link to external page
if (substr($blog, 0, 4) == "%URL") {
$itemurl = substr($blog, 6, strpos($blog, "\n") - 6);
$atag = "<a class='nav-item' href='$itemurl'>$itemname</a>";
}
return $atag;
}
/**
@ -67,7 +74,7 @@ class BlogListGenerator
*
* @return string
*/
function getName($file)
public function getName($file)
{
// get the content of the blog file
$blog = file_get_contents($file);
@ -89,7 +96,7 @@ class BlogListGenerator
*
* @return int Amount of files
*/
static function getArticleAmount($blog)
public static function getArticleAmount($blog)
{
$directory = "./articles/" . $blog . "/";
if (!file_exists($directory)) {
@ -97,7 +104,7 @@ class BlogListGenerator
} else {
$i = 0;
$handle = opendir($directory);
while (($file = readdir($handle)) !== false ) {
while (($file = readdir($handle)) !== false) {
if (!in_array($file, array('.','..'))) {
$i++;
}
@ -105,5 +112,26 @@ class BlogListGenerator
return $i;
}
}
/**
* A function returning the external linkn of
* a blog.
*
* @param string $blog the blog name
* @param string $dir root directory of installation
*
* @return string link to external page else null
*/
public function getExternalLink($blog, $dir)
{
$path = $dir . "/blogs/" . $blog;
$blog = file_get_contents($path) . "\n";
if (substr($blog, 0, 6) == "%TITLE") {
$blog = substr($blog, strpos($blog, "\n") + 1);
}
if (substr($blog, 0, 4) == "%URL") {
return substr($blog, 6, strpos($blog, "\n") - 6);
}
return null;
}
}

View File

@ -22,7 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<?php if ($blogdisqus) { // check if disqus is enabled ?>
<?php if ($config['blog']['disqus']) { // check if disqus is enabled ?>
<section class="card">
<div id="disqus_thread"></div>
<script type="text/javascript">

View File

@ -11,6 +11,7 @@
* @link http://marcel-kapfer.de/rangitaki
*/
require_once "BlogListGenerator.php";
use mmk2410\rbe\BlogListGenerator\BlogListGenerator as BlogListGenerator;
require_once './res/php/Config.php';

View File

@ -64,9 +64,6 @@ main = () ->
$(document).ready main
goBack = () ->
history.go -1
fabFadeIn = () ->
$('.subfab').fadeIn 125
$('.fab-img').fadeOut 60, ->
@ -87,5 +84,4 @@ openNav = () ->
closeNav = () ->
$('.nav').animate {"left": "-301px"}, 125
$('.overlay').animate {"opacity": "0.0"}, 125, ->
$('.overlay').hide
$('.overlay').css {"display": "none"}

View File

@ -0,0 +1,194 @@
/*
*The MIT License
*
*Copyright 2015 mmk2410.
*
*Permission is hereby granted, free of charge, to any person obtaining a copy
*of this software and associated documentation files (the "Software"), to deal
*in the Software without restriction, including without limitation the rights
*to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
*copies of the Software, and to permit persons to whom the Software is
*furnished to do so, subject to the following conditions:
*
*The above copyright notice and this permission notice shall be included in
*all copies or substantial portions of the Software.
*
*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
*IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
*FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
*AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
*LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
*OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
*THE SOFTWARE.
/*
* Created on : Jun 18, 2015, 6:39:37 PM
* Author : mmk2410
$font: "Fira Sans", sans-serif
$background: #f0f0f0
$text-color: #383838
$primary-color: #4CAF50
$header-shadow: rgba(62, 62, 62, 0.45)
$white: #FFFFFF
$fadeout-color: rgba(30, 87, 153, 0)
$border: #e0e0e0
$active-color: #e2e2e2
$fab-shadow: rgba(62, 62, 62, 0.3)
$footer-background: #2D2D2D
body
font-family: $font
background: $background
color: $text-color
margin: 130px 0 0
::selection, ::-moz-selection
color: $background
background-color: $primary-color
.header
height: 55px
background-color: $primary-color
position: fixed
box-shadow: 2px 0 2px 2px $header-shadow
.title
line-height: 55px
color: $white
position: absolute
left: 0
margin-left: calc(20% + 24px)
> a
color: $white
text-decoration: none
.fadeout
height: 55px
background: -moz-linear-gradient(left, $fadeout-color 0%, $primary-color 100%)
background: -webkit-linear-gradient(left, $fadeout-color 0%, $primary-color 100%)
background: -o-linear-gradient(left, $fadeout-color 0%, $primary-color 100%)
background: -ms-linear-gradient(left, $fadeout-color 0%, $primary-color 100%)
background: linear-gradient(to right, $fadeout-color 0%, $primary-color 100%)
.nav-img
padding: 14px 19px
.nav
background-color: $white
border-right: 1px solid $border
.nav-item, .nav-item-static
color: $text-color
.nav-item
font-weight: 600
&:hover
color: $primary-color
&:active
background-color: $active-color
.divider
border-bottom: 1px solid $border
.card
background: none
border-radius: 0
box-shadow: none
margin: 0 20% 100px
width: auto
a
color: $primary-color
text-decoration: none
border-bottom: 1px solid transparent
transition: border-bottom-color 150ms ease-in-out 100ms
&:hover
border-bottom-color: #4CAF50
.headline
font-size: 30px
line-height: 50px
color: #383838 !important
text-decoration: none
border-bottom: none !important
&:hover
color: #4CAF50 !important
.date
font-size: 13px
.articletext
margin-top: 30px
font-size: 16px
line-height: 30px
.author, .tag
font-size: 13px
.fab
background-color: $primary-color
box-shadow: 0 1px 1.5px 1.5px $fab-shadow
.subfab
background-color: $white
box-shadow: 0 1px 1.5px 1.5px $fab-shadow
.button
color: $primary-color
border-bottom: 1px solid transparent
margin: 0
min-width: 0
padding: 0
line-height: 16px
height: 16px
transition-property: border-bottom-color
transition-delay: 50ms
transition-duration: 125ms
transition-timing-function: ease
-moz-transition-property: border-bottom-color
-moz-transition-delay: 50ms
-moz-transition-duration: 125ms
-moz-transition-timing-function: ease
-webkit-transition-property: border-bottom-color
-webkit-transition-delay: 50ms
-webkit-transition-duration: 125ms
-webkit-transition-timing-function: ease
&:hover
border-bottom-color: $primary-color
.pag_prev
float: left
.button:last-child
float: none
.footer
text-align: center
height: 60px
background-color: $footer-background
line-height: 60px
width: 100%
color: $white
a
color: $white
text-decoration: none
border-bottom: 1px solid transparent
&:hover
border-bottom-color: $white
.hljs
background: none
@media screen and (min-width: 1440px)
.title
margin-left: calc(20% - 40px)
.nav
padding-top: 55px
@media screen and (max-width: 800px)
body
margin-top: 80px
.title
margin-left: 20%
.card
margin: 0 5% 100px

View File

@ -153,6 +153,9 @@ body
.tag
.readmore
padding: 12px 0 25px 0
/* FAB */
.fabmenu

View File

@ -0,0 +1,91 @@
<?php
require_once 'PHPUnit/Autoload.php';
include 'res/php/ArticleGenerator.php';
class ArticleGeneratorTest extends \PHPUnit_Framework_TestCase
{
public function testGetArray()
{
$result = [
"title" => "The Rangitaki logo 2",
"date" => "24 July 2015",
"tags" => array(
"design", "artwork", "logo",
),
"author" => "",
"text" => "
This is the official Rangitaki logo.
![The Rangitaki logo](media/example.png)
It is saved in the example blog directory.
",
];
$this->assertEquals(
$result,
ArticleGenerator::getArray("articles/example/", "2015-07-25-example.md")
);
}
public function testGetText()
{
$result = "
This is the official Rangitaki logo.
![The Rangitaki logo](media/example.png)
It is saved in the example blog directory.
";
$this->assertEquals(
$result,
ArticleGenerator::getText("articles/example/", "2015-07-25-example.md")
);
}
public function testGetAuthor()
{
$result = "";
$this->assertEquals(
$result,
ArticleGenerator::getAuthor("articles/example/", "2015-07-25-example.md")
);
}
public function testGetSummary()
{
$result = "This is the official Rangitaki logo.";
$this->assertEquals(
$result,
ArticleGenerator::getSummary("articles/example/", "2015-07-25-example.md")
);
}
public function testGetTags()
{
$result = [ "design", "artwork", "logo" ];
$this->assertEquals(
$result,
ArticleGenerator::getTags("articles/example/", "2015-07-25-example.md")
);
}
public function testGetDate()
{
$result = "24 July 2015";
$this->assertEquals(
$result,
ArticleGenerator::getDate("articles/example/", "2015-07-25-example.md")
);
}
public function testGetTitle()
{
$result = "The Rangitaki logo 2";
$this->assertEquals(
$result,
ArticleGenerator::getTitle("articles/example/", "2015-07-25-example.md")
);
}
}

View File

@ -0,0 +1,39 @@
<?php
use PHPUnit\Framework\TestCase;
require 'res/php/BlogListGenerator.php';
use mmk2410\rbe\BlogListGenerator\BlogListGenerator as BlogListGenerator;
class BlogListGeneratorTest extends TestCase
{
public function testListBlog()
{
$this->assertEquals("<a class='nav-item' href='./?blog=example'>Example</a>",
BlogListGenerator::listBlog("./blogs/", "example.md", "Example Blog")
);
$this->assertEquals("<a class='nav-item' href='https://mmk2410.org/rangitaki/docs/'>Docs</a>",
BlogListGenerator::listBlog("./blogs/", "external.md", "Example Blog")
);
}
public function testGetName()
{
$this->assertEquals("Example", BlogListGenerator::getName("blogs/example.md"));
}
public function testGetArticleAmount()
{
$this->assertEquals(5, BlogListGenerator::getArticleAmount("example"));
}
public function testGetExternaleLink()
{
$this->assertEquals(null,
BlogListGenerator::getExternalLink("example.md", '.')
);
$this->assertEquals("https://mmk2410.org/rangitaki/docs/",
BlogListGenerator::getExternalLink("external.md", '.')
);
}
}

83
tests/ConfigTest.php Normal file
View File

@ -0,0 +1,83 @@
<?php
namespace mmk2410\rbe\tests\config;
require_once 'PHPUnit/Autoload.php';
require 'res/php/Config.php';
use \mmk2410\rbe\config\Config as Config;
class ConfigTest extends \PHPUnit_Framework_TestCase
{
public function testGetConfig()
{
$config = [
"blog" => array(
"title" => "Example Blog",
"author" => "John",
"description" => "A short description of your blog",
"home" => "on",
"homeurl" => "../",
"homename" => "Home",
"mainname" => "",
"intro" => "on",
"disqus" => "rangitaki",
"analytics" => "",
"footer" =>
"Rangitaki 2016 <a href=\"https://gitlab.com/mmk2410/rangitaki\" target=\"blank\">\n gitlab.com/mmk2410/rangitaki</a>", "url" => "https://example.com/blog/",
),
"design" => array(
"fab" => "on",
"drawer" => "on",
"theme" => "material-light",
"pagination" => 0,
"favicon" => "http://example.com/res/img/favicon.png",
),
"rcc" => array(
"rcc" => "on",
"api" => "on",
),
"language" => "en",
];
$configParser = new Config("./config.yaml", "./vendor/autoload.php");
$this->assertEquals($config, $configParser->getConfig());
}
public function testWriteReadConfig()
{
$changedConfig = [
"blog" => array(
"title" => "Examples Blog",
"author" => "Wilson O'Sullivan",
"description" => "A long description of your blog",
"home" => "on",
"homeurl" => "../",
"homename" => "Exit",
"mainname" => "",
"intro" => "on",
"disqus" => "",
"analytics" => "",
"footer" =>
"pBlog 1102 <a href=\"https://gitlab.com/mmk2410/rangitaki\" target=\"blank\">
\n gitlab.com/mmk2410/rangitaki</a>", "url" => "https://example.com/blog/",
),
"design" => array(
"fab" => "off",
"drawer" => "off",
"theme" => "material-dark",
"pagination" => "-1",
"favicon" => "http://sample.com/res/img/favicon.png",
),
"rcc" => array(
"rcc" => "on",
"api" => "off",
),
"language" => "en",
];
$configParser = new Config("/tmp/config-test.yaml", "./vendor/autoload.php");
$configParser->writeConfig($changedConfig);
$this->assertEquals($changedConfig, $configParser->getConfig());
}
}

3
themes/nextDESIGN.css Normal file
View File

@ -0,0 +1,3 @@
body{font-family:"Fira Sans",sans-serif;background:#f0f0f0;color:#383838;margin:130px 0 0}::selection,::-moz-selection{color:#f0f0f0;background-color:#4CAF50}.header{height:55px;background-color:#4CAF50;position:fixed;box-shadow:2px 0 2px 2px rgba(62,62,62,0.45)}.title{line-height:55px;color:#fff;position:absolute;left:0;margin-left:calc(20% + 24px)}.title>a{color:#fff;text-decoration:none}.fadeout{height:55px;background:-moz-linear-gradient(left, rgba(30,87,153,0) 0%, #4CAF50 100%);background:-webkit-linear-gradient(left, rgba(30,87,153,0) 0%, #4CAF50 100%);background:-o-linear-gradient(left, rgba(30,87,153,0) 0%, #4CAF50 100%);background:-ms-linear-gradient(left, rgba(30,87,153,0) 0%, #4CAF50 100%);background:linear-gradient(to right, rgba(30,87,153,0) 0%, #4CAF50 100%)}.nav-img{padding:14px 19px}.nav{background-color:#fff;border-right:1px solid #e0e0e0}.nav-item,.nav-item-static{color:#383838}.nav-item{font-weight:600}.nav-item:hover{color:#4CAF50}.nav-item:active{background-color:#e2e2e2}.divider{border-bottom:1px solid #e0e0e0}.card{background:none;border-radius:0;box-shadow:none;margin:0 20% 100px;width:auto}.card a{color:#4CAF50;text-decoration:none;border-bottom:1px solid transparent;transition:border-bottom-color 150ms ease-in-out 100ms}.card a:hover{border-bottom-color:#4CAF50}.headline{font-size:30px;line-height:50px;color:#383838 !important;text-decoration:none;border-bottom:none !important}.headline:hover{color:#4CAF50 !important}.date{font-size:13px}.articletext{margin-top:30px;font-size:16px;line-height:30px}.author,.tag{font-size:13px}.fab{background-color:#4CAF50;box-shadow:0 1px 1.5px 1.5px rgba(62,62,62,0.3)}.subfab{background-color:#fff;box-shadow:0 1px 1.5px 1.5px rgba(62,62,62,0.3)}.button{color:#4CAF50;border-bottom:1px solid transparent;margin:0;min-width:0;padding:0;line-height:16px;height:16px;transition-property:border-bottom-color;transition-delay:50ms;transition-duration:125ms;transition-timing-function:ease;-moz-transition-property:border-bottom-color;-moz-transition-delay:50ms;-moz-transition-duration:125ms;-moz-transition-timing-function:ease;-webkit-transition-property:border-bottom-color;-webkit-transition-delay:50ms;-webkit-transition-duration:125ms;-webkit-transition-timing-function:ease}.button:hover{border-bottom-color:#4CAF50}.pag_prev{float:left}.button:last-child{float:none}.footer{text-align:center;height:60px;background-color:#2D2D2D;line-height:60px;width:100%;color:#fff}.footer a{color:#fff;text-decoration:none;border-bottom:1px solid transparent}.footer a:hover{border-bottom-color:#fff}.hljs{background:none}@media screen and (min-width: 1440px){.title{margin-left:calc(20% - 40px)}.nav{padding-top:55px}}@media screen and (max-width: 800px){body{margin-top:80px}.title{margin-left:20%}.card{margin:0 5% 100px}}
/*# sourceMappingURL=nextDESIGN.css.map */

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,80 @@
#!/bin/bash
# Update script for Rangitaki from version 1.3.0 to 1.4.0
version="1.4.0"
new="./rbe-new"
echo "Downloading version $version from GitLab..."
git clone https://gitlab.com/mmk2410/rangitaki.git "$new"
if [[ $1 == "--debug" ]]; then
cd $new
git checkout master
cd ../
fi
echo "Updating ressources..."
rm -rf ./res/
mv $new/res/ ./
echo "Updating extensions..."
rm ./extensions/example.js
mv $new/extensions/* ./extensions/
echo "Importing binaries..."
mv $new/bin/ ./
echo "Importing source files..."
mv $new/src/ ./
echo "Updating extensions..."
rm ./themes/material-light.css
rm ./themes/material-dark.css
rm ./themes/background-img.css
mv $new/themes/* ./themes/
echo "Updating RCC..."
rm -rf ./rcc
mv $new/rcc ./
rm ./rcc/password.php
echo "Updating core..."
rm ./index.php
mv $new/index.php ./
echo "Preparing composer..."
rm -rf ./vendor/
rm composer.lock
rm composer.json
mv $new/vendor ./
mv $new/composer.lock ./
mv $new/composer.json ./
echo "Preparing npm..."
mv $new/package.json ./
echo "Updating Changelog..."
if [ -f ./CHANGELOG.txt ]; then
rm CHANGELOG.txt
fi
mv $new/CHANGELOG.md ./
echo "Preparing gulp..."
mv $new/gulpfile.coffee ./
echo "Cleaning up..."
if [[ $1 != "--debug" ]]; then
rm -rf $new
fi
echo "Update config file..."
php bin/config.php
if [ -d "./update-scripts" ]; then
echo "Remove obsolete update scripts folder."
rm -rf "./update-scripts"
fi
echo "Your Rangitaki installation is updated to version $version"

70
update-scripts/1-4-0_1-4-1.sh Executable file
View File

@ -0,0 +1,70 @@
#!/bin/bash
# Update script for Rangitaki from version 1.4.0 to 1.4.1
version="1.4.1"
new="./rbe-new"
echo -n "Downloading version $version from GitLab... "
git clone -q https://gitlab.com/mmk2410/rangitaki.git "$new"
if [[ $1 == "--debug" ]]; then
cd $new
git checkout master
cd ../
fi
echo "done"
echo -n "Updating ressources... "
rm -rf ./res/
mv $new/res/ ./
echo "done"
echo -n "Updating binaries... "
rm -rf ./bin
mv $new/bin/ ./
echo "done"
echo -n "Updating source files... "
rm -rf ./src
mv $new/src/ ./
echo "done"
echo -n "Updating RCC... "
rm -rf ./rcc
mv $new/rcc ./
rm ./rcc/password.php
echo "done"
echo -n "Updating core... "
rm ./index.php
mv $new/index.php ./
echo "done"
echo -n "Updating npm... "
mv $new/package.json ./
echo "done"
echo -n "Updating Changelog... "
if [ -f ./CHANGELOG.txt ]; then
rm CHANGELOG.txt
fi
mv $new/CHANGELOG.md ./
echo "done"
if [[ $1 != "--debug" ]]; then
echo -n "Cleaning up... "
rm -rf $new
echo "done"
fi
if [ -d "./update-scripts" ]; then
echo -n "Remove obsolete update scripts folder... "
rm -rf "./update-scripts"
echo "done"
fi
echo "$version" > ./VERSION
echo "Your Rangitaki installation is updated to version $version"

48
update-scripts/1-4-1_1-4-2.sh Executable file
View File

@ -0,0 +1,48 @@
#!/bin/bash
# Update script for Rangitaki from version 1.4.0 to 1.4.1
version="1.4.2"
new="./rbe-new"
echo -n "Downloading version $version from GitLab... "
git clone -q https://gitlab.com/mmk2410/rangitaki.git "$new"
if [[ $1 == "--debug" ]]; then
cd $new
git checkout master
cd ../
fi
echo "done"
echo -n "Updating RCC... "
mv ./rcc/password.php ./
rm -rf ./rcc
mv $new/rcc ./
rm ./rcc/password.php
mv ./password.php ./rcc/
echo "done"
echo -n "Updating Changelog... "
if [ -f ./CHANGELOG.txt ]; then
rm CHANGELOG.txt
fi
mv $new/CHANGELOG.md ./
echo "done"
if [[ $1 != "--debug" ]]; then
echo -n "Cleaning up... "
rm -rf $new
echo "done"
fi
if [ -d "./update-scripts" ]; then
echo -n "Remove obsolete update scripts folder... "
rm -rf "./update-scripts"
echo "done"
fi
echo "$version" > ./VERSION
echo "Your Rangitaki installation is updated to version $version"

78
update-scripts/1-4-2_1-4-3.sh Executable file
View File

@ -0,0 +1,78 @@
#!/bin/bash
# Update script for Rangitaki from version 1.4.2 to 1.4.3
# Also works from 1.4.0 to 1.4.3
version="1.4.3"
new="./rbe-new"
echo -n "Downloading version $version from GitLab... "
git clone -q https://gitlab.com/mmk2410/rangitaki.git "$new"
if [[ $1 == "--debug" ]]; then
cd $new
git checkout -q master
cd ../
fi
echo "done"
echo -n "Updating ressources... "
rm -rf ./res/
mv $new/res/ ./
echo "done"
echo -n "Updating source files... "
rm ./src/coffee/app.coffee
mv $new/src/coffee/app.coffee ./src/coffee/
mv $new/src/sass-themes/nextDESIGN.sass ./src/sass-themes/
echo "done"
echo -n "Updating RCC... "
rm -rf ./rcc
mv $new/rcc ./
rm ./rcc/password.php
echo "done"
echo -n "Updating core... "
rm ./index.php
mv $new/index.php ./
echo "done"
echo -n "Updating binaries... "
rm -rf ./bin
mv $new/bin/ ./
echo "done"
echo -n "Updating themes... "
rm ./themes/material-light.css*
rm ./themes/material-dark.css*
rm ./themes/background-img.css*
mv $new/themes/* ./themes/
echo "done"
echo -n "Updating npm... "
mv $new/package.json ./
echo "done"
echo -n "Updating Changelog... "
if [ -f ./CHANGELOG.txt ]; then
rm CHANGELOG.txt
fi
mv $new/CHANGELOG.md ./
echo "done"
echo -n "Cleaning up... "
if [[ $1 != "--debug" ]]; then
echo -n "Cleaning up... "
rm -rf $new
echo "done"
fi
if [ -d "./update-scripts" ]; then
echo -n "Remove obsolete update scripts folder... "
rm -rf "./update-scripts"
echo "done"
fi
echo "Your Rangitaki installation is updated to version $version"

51
update-scripts/1-4-3_1-4-4.sh Executable file
View File

@ -0,0 +1,51 @@
#!/bin/bash
# Update script for Rangitaki from version 1.4.3 to 1.4.4
version="1.4.4"
new="./rbe-new"
echo -n "Downloading version $version from GitLab... "
git clone -q https://gitlab.com/mmk2410/rangitaki.git "$new"
if [[ $1 == "--debug" ]]; then
cd $new
git checkout -q master
cd ../
fi
echo "done"
echo -n "Updating RCC... "
mv ./rcc/password.php ./password.php
rm -rf ./rcc/
mv $new/rcc ./
rm ./rcc/password.php
mv ./password.php ./rcc/password.php
echo "done"
echo -n "Updating npm... "
mv $new/package.json ./
echo "done"
echo -n "Updating Changelog... "
if [ -f ./CHANGELOG.txt ]; then
rm CHANGELOG.txt
fi
mv $new/CHANGELOG.md ./
echo "done"
echo -n "Cleaning up... "
if [[ $1 != "--debug" ]]; then
echo -n "Cleaning up... "
rm -rf $new
echo "done"
fi
if [ -d "./update-scripts" ]; then
echo -n "Remove obsolete update scripts folder... "
rm -rf "./update-scripts"
echo "done"
fi
echo "Your Rangitaki installation is updated to version $version"

84
update-scripts/1-4-4_1-5-0.sh Executable file
View File

@ -0,0 +1,84 @@
#!/bin/bash
# Update script for Rangitaki from version 1.4.4 to 1.5.0
version="1.5.0"
new="./rbe-new"
echo -n "Downloading version $version from GitLab... "
git clone -q https://gitlab.com/mmk2410/rangitaki.git "$new"
if [[ $1 == "--debug" ]]; then
cd $new
git checkout -q master
cd ../
fi
echo "done"
echo -n "Updating ressources... "
rm -rf ./res/
mv $new/res/ ./
echo "done"
echo -n "Updating languages... "
rm -rf ./lang/de.php
rm -rf ./lang/en.php
mv $new/lang/* ./lang/
echo "done"
echo -n "Updating source files... "
rm ./src/sass/rangitaki.sass
mv $new/src/sass/rangitaki.sass ./src/sass/
echo "done"
echo -n "Updating core... "
rm ./index.php
mv $new/index.php ./
echo "done"
echo -n "Updating binaries... "
rm -rf ./bin
mv $new/bin/ ./
echo "done"
echo -n "Updating themes... "
rm ./themes/material-light.css*
rm ./themes/material-dark.css*
rm ./themes/background-img.css*
rm ./themes/nextDESIGN.css*
mv $new/themes/* ./themes/
echo "done"
echo -n "Updating npm... "
mv $new/package.json ./
echo "done"
echo -n 'Updating config script... '
echo "social:" >> ./config.yaml
echo " twitter: ''" >> ./config.yaml
sed -i "s/design:/design:\n excerpt: 'off'/" config.yaml
echo "done"
echo -n "Updating Changelog... "
if [ -f ./CHANGELOG.txt ]; then
rm CHANGELOG.txt
fi
mv $new/CHANGELOG.md ./
echo "done"
echo -n "Cleaning up... "
if [[ $1 != "--debug" ]]; then
echo -n "Cleaning up... "
rm -rf $new
echo "done"
fi
if [ -d "./update-scripts" ]; then
echo -n "Remove obsolete update scripts folder... "
rm -rf "./update-scripts"
echo "done"
fi
echo "Your Rangitaki installation is updated to version $version"
echo "Run php ./bin/init.php to use set the values for the new features."

7
vendor/autoload.php vendored Normal file
View File

@ -0,0 +1,7 @@
<?php
// autoload.php @generated by Composer
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInitd1db2574a85c0ba6f142743249ba228f::getLoader();

1
vendor/bin/picofeed vendored Symbolic link
View File

@ -0,0 +1 @@
../fguillot/picofeed/picofeed

19
vendor/codeguy/upload/LICENSE vendored Normal file
View File

@ -0,0 +1,19 @@
Copyright (c) 2012 Josh Lockhart
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

75
vendor/codeguy/upload/README.md vendored Normal file
View File

@ -0,0 +1,75 @@
# Upload
## Usage
This component simplifies file validation and uploading. Assume a file is uploaded with this HTML form:
<form action="" method="POST" enctype="multipart/form-data">
<input type="file" name="foo" value=""/>
<input type="submit" value="Upload File"/>
</form>
When the HTML form is submitted, the server-side PHP code can validate and upload the file like this:
<?php
$storage = new \Upload\Storage\FileSystem('/path/to/directory');
$file = new \Upload\File('foo', $storage);
// Optionally you can rename the file on upload
$new_filename = uniqid();
$file->setName($new_filename);
// Validate file upload
// MimeType List => http://www.webmaster-toolkit.com/mime-types.shtml
$file->addValidations(array(
// Ensure file is of type "image/png"
new \Upload\Validation\Mimetype('image/png'),
// Ensure file is no larger than 5M (use "B", "K", M", or "G")
new \Upload\Validation\Size('5M')
));
// Access data about the file that has been uploaded
$data = array(
'name' => $file->getNameWithExtension(),
'extension' => $file->getExtension(),
'mime' => $file->getMimetype(),
'size' => $file->getSize(),
'md5' => $file->getMd5(),
'dimensions' => $file->getDimensions()
);
// Try to upload file
try {
// Success!
$file->upload();
} catch (\Exception $e) {
// Fail!
$errors = $file->getErrors();
}
## How to Install
Install composer in your project:
curl -s https://getcomposer.org/installer | php
Create a composer.json file in your project root:
{
"require": {
"codeguy/upload": "*"
}
}
Install via composer:
php composer.phar install
## Author
[Josh Lockhart](https://github.com/codeguy)
## License
MIT Public License

25
vendor/codeguy/upload/composer.json vendored Normal file
View File

@ -0,0 +1,25 @@
{
"name": "codeguy/upload",
"type": "library",
"description": "Handle file uploads with extensible validation and storage strategies",
"keywords": ["upload", "validation", "file"],
"homepage": "http://github.com/codeguy/Upload",
"license": "MIT",
"authors": [
{
"name": "Josh Lockhart",
"email": "info@joshlockhart.com",
"homepage": "https://github.com/codeguy/"
}
],
"require": {
"php": ">=5.3.0",
"ext-fileinfo": "*"
},
"require-dev": {
"phpunit/phpunit": "3.7.*"
},
"autoload": {
"psr-0": { "Upload": "src" }
}
}

21
vendor/codeguy/upload/phpunit.xml vendored Normal file
View File

@ -0,0 +1,21 @@
<phpunit backupGlobals="true"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
bootstrap="tests/bootstrap.php">
<testsuites>
<testsuite name="Upload Test Suite">
<directory>./tests/</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>./src/Upload/</directory>
</whitelist>
</filter>
</phpunit>

View File

@ -0,0 +1,77 @@
<?php
/**
* Upload
*
* @author Josh Lockhart <info@joshlockhart.com>
* @copyright 2012 Josh Lockhart
* @link http://www.joshlockhart.com
* @version 1.0.0
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
namespace Upload;
/**
* Autoloader
*
* This class provides a default PSR-0 autoloader if not using Composer.
*
* @author Josh Lockhart <info@joshlockhart.com>
* @since 1.0.0
* @package Upload
*/
class Autoloader
{
/**
* The project's base directory
* @var string
*/
static protected $base;
/**
* Register autoloader
*/
static public function register()
{
self::$base = dirname(__FILE__) . '/../';
spl_autoload_register(array(new self, 'autoload'));
}
/**
* Autoload classname
* @param string $className The class to load
*/
static public function autoload($className)
{
$className = ltrim($className, '\\');
$fileName = '';
$namespace = '';
if ($lastNsPos = strripos($className, '\\')) {
$namespace = substr($className, 0, $lastNsPos);
$className = substr($className, $lastNsPos + 1);
$fileName = str_replace('\\', DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR;
}
$fileName .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
require self::$base . $fileName;
}
}

View File

@ -0,0 +1,7 @@
<?php
namespace Upload\Exception;
class UploadException extends \RuntimeException
{
}

View File

@ -0,0 +1,381 @@
<?php
/**
* Upload
*
* @author Josh Lockhart <info@joshlockhart.com>
* @copyright 2012 Josh Lockhart
* @link http://www.joshlockhart.com
* @version 1.0.0
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
namespace Upload;
/**
* File
*
* This class provides the implementation for an uploaded file. It exposes
* common attributes for the uploaded file (e.g. name, extension, media type)
* and allows you to attach validations to the file that must pass for the
* upload to succeed.
*
* @author Josh Lockhart <info@joshlockhart.com>
* @since 1.0.0
* @package Upload
*/
class File extends \SplFileInfo
{
/********************************************************************************
* Static Properties
*******************************************************************************/
/**
* Upload error code messages
* @var array
*/
protected static $errorCodeMessages = array(
1 => 'The uploaded file exceeds the upload_max_filesize directive in php.ini',
2 => 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form',
3 => 'The uploaded file was only partially uploaded',
4 => 'No file was uploaded',
6 => 'Missing a temporary folder',
7 => 'Failed to write file to disk',
8 => 'A PHP extension stopped the file upload'
);
/**
* Lookup hash to convert file units to bytes
* @var array
*/
protected static $units = array(
'b' => 1,
'k' => 1024,
'm' => 1048576,
'g' => 1073741824
);
/********************************************************************************
* Instance Properties
*******************************************************************************/
/**
* Storage delegate
* @var \Upload\Storage\Base
*/
protected $storage;
/**
* Validations
* @var array[\Upload\Validation\Base]
*/
protected $validations;
/**
* Validation errors
* @var array
*/
protected $errors;
/**
* Original file name provided by client (for internal use only)
* @var string
*/
protected $originalName;
/**
* File name (without extension)
* @var string
*/
protected $name;
/**
* File extension (without leading dot)
* @var string
*/
protected $extension;
/**
* File mimetype (e.g. "image/png")
* @var string
*/
protected $mimetype;
/**
* Upload error code (for internal use only)
* @var int
* @link http://www.php.net/manual/en/features.file-upload.errors.php
*/
protected $errorCode;
/**
* Constructor
* @param string $key The file's key in $_FILES superglobal
* @param \Upload\Storage\Base $storage The method with which to store file
* @throws \Upload\Exception\UploadException If file uploads are disabled in the php.ini file
* @throws \InvalidArgumentException If $_FILES key does not exist
*/
public function __construct($key, \Upload\Storage\Base $storage)
{
if (!isset($_FILES[$key])) {
throw new \InvalidArgumentException("Cannot find uploaded file identified by key: $key");
}
$this->storage = $storage;
$this->validations = array();
$this->errors = array();
$this->originalName = $_FILES[$key]['name'];
$this->errorCode = $_FILES[$key]['error'];
parent::__construct($_FILES[$key]['tmp_name']);
}
/**
* Get name
* @return string
*/
public function getName()
{
if (!isset($this->name)) {
$this->name = pathinfo($this->originalName, PATHINFO_FILENAME);
}
return $this->name;
}
/**
* Set name (without extension)
* @param string $name
* @return \Upload\File Self
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get file name with extension
* @return string
*/
public function getNameWithExtension()
{
return sprintf('%s.%s', $this->getName(), $this->getExtension());
}
/**
* Get file extension (without leading dot)
* @return string
*/
public function getExtension()
{
if (!isset($this->extension)) {
$this->extension = strtolower(pathinfo($this->originalName, PATHINFO_EXTENSION));
}
return $this->extension;
}
/**
* Get mimetype
* @return string
*/
public function getMimetype()
{
if (!isset($this->mimeType)) {
$finfo = new \finfo(FILEINFO_MIME);
$mimetype = $finfo->file($this->getPathname());
$mimetypeParts = preg_split('/\s*[;,]\s*/', $mimetype);
$this->mimetype = strtolower($mimetypeParts[0]);
unset($finfo);
}
return $this->mimetype;
}
/**
* Get md5
* @return string
*/
public function getMd5()
{
return md5_file($this->getPathname());
}
/**
* Get image dimensions
* @return array formatted array of dimensions
*/
public function getDimensions()
{
list($width, $height) = getimagesize($this->getPathname());
return array(
'width' => $width,
'height' => $height
);
}
/********************************************************************************
* Validate
*******************************************************************************/
/**
* Add file validations
* @param \Upload\Validation\Base|array[\Upload\Validation\Base] $validations
*/
public function addValidations($validations)
{
if (!is_array($validations)) {
$validations = array($validations);
}
foreach ($validations as $validation) {
if ($validation instanceof \Upload\Validation\Base) {
$this->validations[] = $validation;
}
}
}
/**
* Get file validations
* @return array[\Upload\Validation\Base]
*/
public function getValidations()
{
return $this->validations;
}
/**
* Validate file
* @return bool True if valid, false if invalid
*/
public function validate()
{
// Validate is uploaded OK
if ($this->isOk() === false) {
$this->errors[] = self::$errorCodeMessages[$this->errorCode];
}
// Validate is uploaded file
if ($this->isUploadedFile() === false) {
$this->errors[] = 'The uploaded file was not sent with a POST request';
}
// User validations
foreach ($this->validations as $validation) {
if ($validation->validate($this) === false) {
$this->errors[] = $validation->getMessage();
}
}
return empty($this->errors);
}
/**
* Get file validation errors
* @return array[String]
*/
public function getErrors()
{
return $this->errors;
}
/**
* Add file validation error
* @param string
* @return \Upload\File Self
*/
public function addError($error)
{
$this->errors[] = $error;
return $this;
}
/********************************************************************************
* Upload
*******************************************************************************/
/**
* Upload file (delegated to storage object)
* @param string $newName Give the file it a new name
* @return bool
* @throws \Upload\Exception\UploadException If file does not validate
*/
public function upload($newName = null)
{
if ($this->validate() === false) {
throw new \Upload\Exception\UploadException('File validation failed');
}
// Update the name, leaving out the extension
if (is_string($newName)) {
$this->name = pathinfo($newName, PATHINFO_FILENAME);
}
return $this->storage->upload($this, $newName);
}
/********************************************************************************
* Helpers
*******************************************************************************/
/**
* Is this file uploaded with a POST request?
*
* This is a separate method so that it can be stubbed in unit tests to avoid
* the hard dependency on the `is_uploaded_file` function.
*
* @return bool
*/
public function isUploadedFile()
{
return is_uploaded_file($this->getPathname());
}
/**
* Is this file OK?
*
* This method inspects the upload error code to see if the upload was
* successful or if it failed for a variety of reasons.
*
* @link http://www.php.net/manual/en/features.file-upload.errors.php
* @return bool
*/
public function isOk()
{
return ($this->errorCode === UPLOAD_ERR_OK);
}
/**
* Convert human readable file size (e.g. "10K" or "3M") into bytes
* @param string $input
* @return int
*/
public static function humanReadableToBytes($input)
{
$number = (int)$input;
$unit = strtolower(substr($input, -1));
if (isset(self::$units[$unit])) {
$number = $number * self::$units[$unit];
}
return $number;
}
}

View File

@ -0,0 +1,45 @@
<?php
/**
* Upload
*
* @author Josh Lockhart <info@joshlockhart.com>
* @copyright 2012 Josh Lockhart
* @link http://www.joshlockhart.com
* @version 1.0.0
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
namespace Upload\Storage;
/**
* Upload Storage Base
*
* This class defines the interface that must be implemented by each
* concrete Upload storage subclass.
*
* @author Josh Lockhart <info@joshlockhart.com>
* @since 1.0.0
*/
abstract class Base
{
abstract public function upload(\Upload\File $file, $newName = null);
}

View File

@ -0,0 +1,114 @@
<?php
/**
* Upload
*
* @author Josh Lockhart <info@joshlockhart.com>
* @copyright 2012 Josh Lockhart
* @link http://www.joshlockhart.com
* @version 1.0.0
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
namespace Upload\Storage;
/**
* FileSystem Storage
*
* This class uploads files to a designated directory on the filesystem.
*
* @author Josh Lockhart <info@joshlockhart.com>
* @since 1.0.0
* @package Upload
*/
class FileSystem extends \Upload\Storage\Base
{
/**
* Upload directory
* @var string
*/
protected $directory;
/**
* Overwrite existing files?
* @var bool
*/
protected $overwrite;
/**
* Constructor
* @param string $directory Relative or absolute path to upload directory
* @param bool $overwrite Should this overwrite existing files?
* @throws \InvalidArgumentException If directory does not exist
* @throws \InvalidArgumentException If directory is not writable
*/
public function __construct($directory, $overwrite = false)
{
if (!is_dir($directory)) {
throw new \InvalidArgumentException('Directory does not exist');
}
if (!is_writable($directory)) {
throw new \InvalidArgumentException('Directory is not writable');
}
$this->directory = rtrim($directory, '/') . DIRECTORY_SEPARATOR;
$this->overwrite = $overwrite;
}
/**
* Upload
* @param \Upload\File $file The file object to upload
* @param string $newName Give the file it a new name
* @return bool
* @throws \RuntimeException If overwrite is false and file already exists
*/
public function upload(\Upload\File $file, $newName = null)
{
if (is_string($newName)) {
$fileName = strpos($newName, '.') ? $newName : $newName.'.'.$file->getExtension();
} else {
$fileName = $file->getNameWithExtension();
}
$newFile = $this->directory . $fileName;
if ($this->overwrite === false && file_exists($newFile)) {
$file->addError('File already exists');
throw new \Upload\Exception\UploadException('File already exists');
}
return $this->moveUploadedFile($file->getPathname(), $newFile);
}
/**
* Move uploaded file
*
* This method allows us to stub this method in unit tests to avoid
* hard dependency on the `move_uploaded_file` function.
*
* @param string $source The source file
* @param string $destination The destination file
* @return bool
*/
protected function moveUploadedFile($source, $destination)
{
return move_uploaded_file($source, $destination);
}
}

View File

@ -0,0 +1,75 @@
<?php
/**
* Upload
*
* @author Josh Lockhart <info@joshlockhart.com>
* @copyright 2012 Josh Lockhart
* @link http://www.joshlockhart.com
* @version 1.0.0
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
namespace Upload\Validation;
/**
* Upload Validation Base
*
* This class provides the common implementation and abstract interface
* for all concrete Upload validation subclasses.
*
* @author Josh Lockhart <info@joshlockhart.com>
* @since 1.0.0
* @package Upload
*/
abstract class Base
{
/**
* The error message for this validation
* @var string
*/
protected $message;
/**
* Set error message
* @param string $message
*/
public function setMessage($message)
{
$this->message = $message;
}
/**
* Get error message
* @return string
*/
public function getMessage()
{
return $this->message;
}
/**
* Validate file
* @param \Upload\File $file
* @return bool True if file is valid, false if file is not valid
*/
abstract public function validate(\Upload\File $file);
}

View File

@ -0,0 +1,95 @@
<?php
/**
* Upload
*
* @author Josh Lockhart <info@joshlockhart.com>
* @copyright 2012 Josh Lockhart
* @link http://www.joshlockhart.com
* @version 1.0.0
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
namespace Upload\Validation;
/**
* Validate File Extension
*
* This class validates an uploads file extension. It takes file extension with out dot
* or array of extensions. For example: 'png' or array('jpg', 'png', 'gif').
*
* WARING! Validation only by file extension not very secure.
*
* @author Alex Kucherenko <kucherenko.email@gmail.com>
* @package Upload
*/
class Extension extends \Upload\Validation\Base
{
/**
* Array of cceptable file extensions without leading dots
* @var array
*/
protected $allowedExtensions;
/**
* Error message
* @var string
*/
protected $message = 'Invalid file extension. Must be one of: %s';
/**
* Constructor
*
* @param string|array $allowedExtensions Allowed file extensions
* @example new \Upload\Validation\Extension(array('png','jpg','gif'))
* @example new \Upload\Validation\Extension('png')
*/
public function __construct($allowedExtensions)
{
if (is_string($allowedExtensions)) {
$allowedExtensions = array($allowedExtensions);
}
array_filter($allowedExtensions, function ($val) {
return strtolower($val);
});
$this->allowedExtensions = $allowedExtensions;
}
/**
* Validate
* @param \Upload\File $file
* @return bool
*/
public function validate(\Upload\File $file)
{
$fileExtension = strtolower($file->getExtension());
$isValid = true;
if (!in_array($fileExtension, $this->allowedExtensions)) {
$this->setMessage(sprintf($this->message, implode(', ', $this->allowedExtensions)));
$isValid = false;
}
return $isValid;
}
}

View File

@ -0,0 +1,77 @@
<?php
/**
* Upload
*
* @author Josh Lockhart <info@joshlockhart.com>
* @copyright 2012 Josh Lockhart
* @link http://www.joshlockhart.com
* @version 1.0.0
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
namespace Upload\Validation;
/**
* Validate Upload Media Type
*
* This class validates an upload's media type (e.g. "image/png").
*
* @author Josh Lockhart <info@joshlockhart.com>
* @since 1.0.0
* @package Upload
*/
class Mimetype extends \Upload\Validation\Base
{
/**
* Valid media types
* @var array
*/
protected $mimetypes;
/**
* Error message
* @var string
*/
protected $message = 'Invalid mimetype';
/**
* Constructor
* @param array $mimetypes Array of valid mimetypes
*/
public function __construct($mimetypes)
{
if (!is_array($mimetypes)) {
$mimetypes = array($mimetypes);
}
$this->mimetypes = $mimetypes;
}
/**
* Validate
* @param \Upload\File $file
* @return bool
*/
public function validate(\Upload\File $file)
{
return in_array($file->getMimetype(), $this->mimetypes);
}
}

View File

@ -0,0 +1,104 @@
<?php
/**
* Upload
*
* @author Josh Lockhart <info@joshlockhart.com>
* @copyright 2012 Josh Lockhart
* @link http://www.joshlockhart.com
* @version 1.0.0
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
namespace Upload\Validation;
/**
* Validate Upload File Size
*
* This class validates an uploads file size using maximum and (optionally)
* minimum file size bounds (inclusive). Specify acceptable file sizes
* as an integer (in bytes) or as a human-readable string (e.g. "5MB").
*
* @author Josh Lockhart <info@joshlockhart.com>
* @since 1.0.0
* @package Upload
*/
class Size extends \Upload\Validation\Base
{
/**
* Minimum acceptable file size (bytes)
* @var int
*/
protected $minSize;
/**
* Maximum acceptable file size (bytes)
* @var int
*/
protected $maxSize;
/**
* Error message
* @var string
*/
protected $message = 'Invalid file size';
/**
* Constructor
* @param int $maxSize Maximum acceptable file size in bytes (inclusive)
* @param int $minSize Minimum acceptable file size in bytes (inclusive)
*/
public function __construct($maxSize, $minSize = 0)
{
if (is_string($maxSize)) {
$maxSize = \Upload\File::humanReadableToBytes($maxSize);
}
$this->maxSize = $maxSize;
if (is_string($minSize)) {
$minSize = \Upload\File::humanReadableToBytes($minSize);
}
$this->minSize = $minSize;
}
/**
* Validate
* @param \Upload\File $file
* @return bool
*/
public function validate(\Upload\File $file)
{
$fileSize = $file->getSize();
$isValid = true;
if ($fileSize < $this->minSize) {
$this->setMessage('File size is too small');
$isValid = false;
}
if ($fileSize > $this->maxSize) {
$this->setMessage('File size is too large');
$isValid = false;
}
return $isValid;
}
}

176
vendor/codeguy/upload/tests/FileTest.php vendored Normal file
View File

@ -0,0 +1,176 @@
<?php
class FileTest extends PHPUnit_Framework_TestCase
{
protected $assetsDirectory;
protected $storage;
/********************************************************************************
* Setup
*******************************************************************************/
public function setUp()
{
$this->assetsDirectory = dirname(__FILE__) . '/assets';
$_FILES['foo'] = array(
'name' => 'foo.txt',
'tmp_name' => $this->assetsDirectory . '/foo.txt',
'error' => UPLOAD_ERR_OK
);
}
public function getNewFile()
{
if (is_null($this->storage)) {
// Prepare storage
$this->storage = $this->getMock(
'\Upload\Storage\FileSystem',
array('upload'),
array($this->assetsDirectory)
);
$this->storage->expects($this->any())
->method('upload')
->will($this->returnValue(true));
}
// Prepare file
$file = $this->getMock(
'\Upload\File',
array('isUploadedFile'),
array('foo', $this->storage)
);
$file->expects($this->any())
->method('isUploadedFile')
->will($this->returnValue(true));
return $file;
}
/********************************************************************************
* Tests
*******************************************************************************/
/**
* @expectedException \InvalidArgumentException
*/
public function testConstructionWithInvalidKey()
{
$file = new \Upload\File('bar', new \Upload\Storage\FileSystem($this->assetsDirectory));
}
public function testGetName()
{
$file = $this->getNewFile();
$this->assertEquals('foo', $file->getName());
}
public function testGetNameWithExtension()
{
$file = $this->getNewFile();
$this->assertEquals('foo.txt', $file->getNameWithExtension());
}
public function testGetNameWithExtensionUsingCustomName()
{
$file = $this->getNewFile();
$file->setName('bar');
$this->assertEquals('bar.txt', $file->getNameWithExtension());
}
public function testGetMimetype()
{
$file = $this->getNewFile();
$this->assertEquals('text/plain', $file->getMimetype());
}
public function testAddValidationErrors()
{
$file = $this->getNewFile();
$file->addError('Error');
$this->assertEquals(1, count($file->getErrors()));
}
public function testIsValidIfNoValidations()
{
$file = $this->getNewFile();
$this->assertEmpty($file->getErrors());
}
public function testWillUploadIfNoValidations()
{
$file = $this->getNewFile();
$this->assertTrue($file->upload());
}
public function testAddValidations()
{
$file = $this->getNewFile();
$file->addValidations(new \Upload\Validation\Mimetype(array(
'text/plain'
)));
$this->assertEquals(1, count($file->getValidations()));
}
public function testWillUploadWithPassingValidations()
{
$file = $this->getNewFile();
$file->addValidations(new \Upload\Validation\Mimetype(array(
'text/plain'
)));
$this->assertTrue($file->upload());
}
/**
* @expectedException \Upload\Exception\UploadException
*/
public function testWillNotUploadWithFailingValidations()
{
$file = $this->getNewFile();
$file->addValidations(new \Upload\Validation\Mimetype(array(
'image/png'
)));
$file->upload();
}
public function testPopulatesErrorsWithFailingValidations()
{
$file = $this->getNewFile();
$file->addValidations(new \Upload\Validation\Mimetype(array(
'image/png'
)));
try {
$file->upload();
} catch(\Upload\Exception\UploadException $e) {
$this->assertEquals(1, count($file->getErrors()));
}
}
public function testValidationFailsIfUploadErrorCode()
{
$_FILES['foo']['error'] = 4;
$file = $this->getNewFile();
$this->assertFalse($file->validate());
}
public function testValidationFailsIfNotUploadedFile()
{
$file = $this->getMock(
'\Upload\File',
array('isUploadedFile'),
array('foo', new \Upload\Storage\FileSystem($this->assetsDirectory))
);
$file->expects($this->any())
->method('isUploadedFile')
->will($this->returnValue(false));
$this->assertFalse($file->validate());
}
public function testParsesHumanFriendlyFileSizes()
{
$this->assertEquals(100, \Upload\File::humanReadableToBytes('100'));
$this->assertEquals(102400, \Upload\File::humanReadableToBytes('100K'));
$this->assertEquals(104857600, \Upload\File::humanReadableToBytes('100M'));
$this->assertEquals(107374182400, \Upload\File::humanReadableToBytes('100G'));
$this->assertEquals(100, \Upload\File::humanReadableToBytes('100F')); // <-- Unrecognized. Assume bytes.
}
}

View File

@ -0,0 +1,79 @@
<?php
class FileSystemTest extends PHPUnit_Framework_TestCase
{
/**
* Setup (each test)
*/
public function setUp()
{
// Path to test assets
$this->assetsDirectory = dirname(__DIR__) . '/assets';
// Reset $_FILES superglobal
$_FILES['foo'] = array(
'name' => 'foo.txt',
'tmp_name' => $this->assetsDirectory . '/foo.txt',
'error' => 0
);
}
public function testInstantiationWithValidDirectory()
{
try {
$storage = $this->getMock(
'\Upload\Storage\FileSystem',
array('upload'),
array($this->assetsDirectory)
);
} catch(\InvalidArgumentException $e) {
$this->fail('Unexpected argument thrown during instantiation with valid directory');
}
}
/**
* @expectedException \InvalidArgumentException
*/
public function testInstantiationWithInvalidDirectory()
{
$storage = $this->getMock(
'\Upload\Storage\FileSystem',
array('upload'),
array('/foo')
);
}
/**
* Test won't overwrite existing file
* @expectedException \RuntimeException
*/
public function testWillNotOverwriteFile()
{
$storage = new \Upload\Storage\FileSystem($this->assetsDirectory, false);
$file = new \Upload\File('foo', $storage);
$file->upload();
}
/**
* Test will overwrite existing file
*/
public function testWillOverwriteFile()
{
$storage = $this->getMock(
'\Upload\Storage\FileSystem',
array('moveUploadedFile'),
array($this->assetsDirectory, true)
);
$storage->expects($this->any())
->method('moveUploadedFile')
->will($this->returnValue(true));
$file = $this->getMock(
'\Upload\File',
array('isUploadedFile'),
array('foo', $storage)
);
$file->expects($this->any())
->method('isUploadedFile')
->will($this->returnValue(true));
$this->assertTrue($file->upload());
}
}

View File

@ -0,0 +1,43 @@
<?php
class ExtensionTest extends PHPUnit_Framework_TestCase
{
/**
* Setup (each test)
*/
public function setUp()
{
// Path to test assets
$this->assetsDirectory = dirname(__DIR__) . '/assets';
// Create stubbed storage instance
$this->storage = $this->getMock(
'\Upload\Storage\FileSystem',
array('upload'),
array($this->assetsDirectory)
);
$this->storage->expects($this->any())
->method('upload')
->will($this->returnValue(true));
// Reset $_FILES superglobal
$_FILES['foo'] = array(
'name' => 'foo.txt',
'tmp_name' => $this->assetsDirectory . '/foo.txt',
'error' => 0
);
}
public function testValidExtension()
{
$file = new \Upload\File('foo', $this->storage);
$validation = new \Upload\Validation\Extension('txt');
$this->assertTrue($validation->validate($file));
}
public function testInvalidExtension()
{
$file = new \Upload\File('foo', $this->storage);
$validation = new \Upload\Validation\Extension('csv');
$this->assertFalse($validation->validate($file));
}
}

View File

@ -0,0 +1,47 @@
<?php
class MimetypeTest extends PHPUnit_Framework_TestCase
{
/**
* Setup (each test)
*/
public function setUp()
{
// Path to test assets
$this->assetsDirectory = dirname(__DIR__) . '/assets';
// Create stubbed storage instance
$this->storage = $this->getMock(
'\Upload\Storage\FileSystem',
array('upload'),
array($this->assetsDirectory)
);
$this->storage->expects($this->any())
->method('upload')
->will($this->returnValue(true));
// Reset $_FILES superglobal
$_FILES['foo'] = array(
'name' => 'foo.txt',
'tmp_name' => $this->assetsDirectory . '/foo.txt',
'error' => 0
);
}
public function testValidMimetype()
{
$file = new \Upload\File('foo', $this->storage);
$validation = new \Upload\Validation\Mimetype(array(
'text/plain'
));
$this->assertTrue($validation->validate($file));
}
public function testInvalidMimetype()
{
$file = new \Upload\File('foo', $this->storage);
$validation = new \Upload\Validation\Mimetype(array(
'image/png'
));
$this->assertFalse($validation->validate($file));
}
}

View File

@ -0,0 +1,57 @@
<?php
class SizeTest extends PHPUnit_Framework_TestCase
{
/**
* Setup (each test)
*/
public function setUp()
{
// Path to test assets
$this->assetsDirectory = dirname(__DIR__) . '/assets';
// Create stubbed storage instance
$this->storage = $this->getMock(
'\Upload\Storage\FileSystem',
array('upload'),
array($this->assetsDirectory)
);
$this->storage->expects($this->any())
->method('upload')
->will($this->returnValue(true));
// Reset $_FILES superglobal
$_FILES['foo'] = array(
'name' => 'foo.txt',
'tmp_name' => $this->assetsDirectory . '/foo.txt',
'error' => 0
);
}
public function testValidFileSize()
{
$file = new \Upload\File('foo', $this->storage);
$validation = new \Upload\Validation\Size(500);
$this->assertTrue($validation->validate($file));
}
public function testValidFileSizeWithHumanReadableArgument()
{
$file = new \Upload\File('foo', $this->storage);
$validation = new \Upload\Validation\Size('500B');
$this->assertTrue($validation->validate($file));
}
public function testInvalidFileSize()
{
$file = new \Upload\File('foo', $this->storage);
$validation = new \Upload\Validation\Size(400);
$this->assertFalse($validation->validate($file));
}
public function testInvalidFileSizeWithHumanReadableArgument()
{
$file = new \Upload\File('foo', $this->storage);
$validation = new \Upload\Validation\Size('400B');
$this->assertFalse($validation->validate($file));
}
}

View File

@ -0,0 +1,6 @@
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

View File

@ -0,0 +1,3 @@
<?php
require dirname(__FILE__) . '/../src/Upload/Autoloader.php';
\Upload\Autoloader::register();

441
vendor/composer/ClassLoader.php vendored Normal file
View File

@ -0,0 +1,441 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer\Autoload;
/**
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
*
* $loader = new \Composer\Autoload\ClassLoader();
*
* // register classes with namespaces
* $loader->add('Symfony\Component', __DIR__.'/component');
* $loader->add('Symfony', __DIR__.'/framework');
*
* // activate the autoloader
* $loader->register();
*
* // to enable searching the include path (eg. for PEAR packages)
* $loader->setUseIncludePath(true);
*
* In this example, if you try to use a class in the Symfony\Component
* namespace or one of its children (Symfony\Component\Console for instance),
* the autoloader will first look for the class under the component/
* directory, and it will then fallback to the framework/ directory if not
* found before giving up.
*
* This class is loosely based on the Symfony UniversalClassLoader.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
* @see http://www.php-fig.org/psr/psr-0/
* @see http://www.php-fig.org/psr/psr-4/
*/
class ClassLoader
{
// PSR-4
private $prefixLengthsPsr4 = array();
private $prefixDirsPsr4 = array();
private $fallbackDirsPsr4 = array();
// PSR-0
private $prefixesPsr0 = array();
private $fallbackDirsPsr0 = array();
private $useIncludePath = false;
private $classMap = array();
private $classMapAuthoritative = false;
private $missingClasses = array();
private $apcuPrefix;
public function getPrefixes()
{
if (!empty($this->prefixesPsr0)) {
return call_user_func_array('array_merge', $this->prefixesPsr0);
}
return array();
}
public function getPrefixesPsr4()
{
return $this->prefixDirsPsr4;
}
public function getFallbackDirs()
{
return $this->fallbackDirsPsr0;
}
public function getFallbackDirsPsr4()
{
return $this->fallbackDirsPsr4;
}
public function getClassMap()
{
return $this->classMap;
}
/**
* @param array $classMap Class to filename map
*/
public function addClassMap(array $classMap)
{
if ($this->classMap) {
$this->classMap = array_merge($this->classMap, $classMap);
} else {
$this->classMap = $classMap;
}
}
/**
* Registers a set of PSR-0 directories for a given prefix, either
* appending or prepending to the ones previously set for this prefix.
*
* @param string $prefix The prefix
* @param array|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
*/
public function add($prefix, $paths, $prepend = false)
{
if (!$prefix) {
if ($prepend) {
$this->fallbackDirsPsr0 = array_merge(
(array) $paths,
$this->fallbackDirsPsr0
);
} else {
$this->fallbackDirsPsr0 = array_merge(
$this->fallbackDirsPsr0,
(array) $paths
);
}
return;
}
$first = $prefix[0];
if (!isset($this->prefixesPsr0[$first][$prefix])) {
$this->prefixesPsr0[$first][$prefix] = (array) $paths;
return;
}
if ($prepend) {
$this->prefixesPsr0[$first][$prefix] = array_merge(
(array) $paths,
$this->prefixesPsr0[$first][$prefix]
);
} else {
$this->prefixesPsr0[$first][$prefix] = array_merge(
$this->prefixesPsr0[$first][$prefix],
(array) $paths
);
}
}
/**
* Registers a set of PSR-4 directories for a given namespace, either
* appending or prepending to the ones previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param array|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories
*
* @throws \InvalidArgumentException
*/
public function addPsr4($prefix, $paths, $prepend = false)
{
if (!$prefix) {
// Register directories for the root namespace.
if ($prepend) {
$this->fallbackDirsPsr4 = array_merge(
(array) $paths,
$this->fallbackDirsPsr4
);
} else {
$this->fallbackDirsPsr4 = array_merge(
$this->fallbackDirsPsr4,
(array) $paths
);
}
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
// Register directories for a new namespace.
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
} elseif ($prepend) {
// Prepend directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
(array) $paths,
$this->prefixDirsPsr4[$prefix]
);
} else {
// Append directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
$this->prefixDirsPsr4[$prefix],
(array) $paths
);
}
}
/**
* Registers a set of PSR-0 directories for a given prefix,
* replacing any others previously set for this prefix.
*
* @param string $prefix The prefix
* @param array|string $paths The PSR-0 base directories
*/
public function set($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr0 = (array) $paths;
} else {
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
}
}
/**
* Registers a set of PSR-4 directories for a given namespace,
* replacing any others previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param array|string $paths The PSR-4 base directories
*
* @throws \InvalidArgumentException
*/
public function setPsr4($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr4 = (array) $paths;
} else {
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
}
}
/**
* Turns on searching the include path for class files.
*
* @param bool $useIncludePath
*/
public function setUseIncludePath($useIncludePath)
{
$this->useIncludePath = $useIncludePath;
}
/**
* Can be used to check if the autoloader uses the include path to check
* for classes.
*
* @return bool
*/
public function getUseIncludePath()
{
return $this->useIncludePath;
}
/**
* Turns off searching the prefix and fallback directories for classes
* that have not been registered with the class map.
*
* @param bool $classMapAuthoritative
*/
public function setClassMapAuthoritative($classMapAuthoritative)
{
$this->classMapAuthoritative = $classMapAuthoritative;
}
/**
* Should class lookup fail if not found in the current class map?
*
* @return bool
*/
public function isClassMapAuthoritative()
{
return $this->classMapAuthoritative;
}
/**
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
*
* @param string|null $apcuPrefix
*/
public function setApcuPrefix($apcuPrefix)
{
$this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null;
}
/**
* The APCu prefix in use, or null if APCu caching is not enabled.
*
* @return string|null
*/
public function getApcuPrefix()
{
return $this->apcuPrefix;
}
/**
* Registers this instance as an autoloader.
*
* @param bool $prepend Whether to prepend the autoloader or not
*/
public function register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
}
/**
* Unregisters this instance as an autoloader.
*/
public function unregister()
{
spl_autoload_unregister(array($this, 'loadClass'));
}
/**
* Loads the given class or interface.
*
* @param string $class The name of the class
* @return bool|null True if loaded, null otherwise
*/
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
includeFile($file);
return true;
}
}
/**
* Finds the path to the file where the class is defined.
*
* @param string $class The name of the class
*
* @return string|false The path if found, false otherwise
*/
public function findFile($class)
{
// class map lookup
if (isset($this->classMap[$class])) {
return $this->classMap[$class];
}
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
return false;
}
if (null !== $this->apcuPrefix) {
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
if ($hit) {
return $file;
}
}
$file = $this->findFileWithExtension($class, '.php');
// Search for Hack files if we are running on HHVM
if (false === $file && defined('HHVM_VERSION')) {
$file = $this->findFileWithExtension($class, '.hh');
}
if (null !== $this->apcuPrefix) {
apcu_add($this->apcuPrefix.$class, $file);
}
if (false === $file) {
// Remember that this class does not exist.
$this->missingClasses[$class] = true;
}
return $file;
}
private function findFileWithExtension($class, $ext)
{
// PSR-4 lookup
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
$first = $class[0];
if (isset($this->prefixLengthsPsr4[$first])) {
foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) {
if (0 === strpos($class, $prefix)) {
foreach ($this->prefixDirsPsr4[$prefix] as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
return $file;
}
}
}
}
}
// PSR-4 fallback dirs
foreach ($this->fallbackDirsPsr4 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
return $file;
}
}
// PSR-0 lookup
if (false !== $pos = strrpos($class, '\\')) {
// namespaced class name
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
} else {
// PEAR-like class name
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
}
if (isset($this->prefixesPsr0[$first])) {
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
if (0 === strpos($class, $prefix)) {
foreach ($dirs as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
}
}
}
// PSR-0 fallback dirs
foreach ($this->fallbackDirsPsr0 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
// PSR-0 include paths.
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
return $file;
}
return false;
}
}
/**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*/
function includeFile($file)
{
include $file;
}

21
vendor/composer/LICENSE vendored Normal file
View File

@ -0,0 +1,21 @@
Copyright (c) 2016 Nils Adermann, Jordi Boggiano
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

9
vendor/composer/autoload_classmap.php vendored Normal file
View File

@ -0,0 +1,9 @@
<?php
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
);

10
vendor/composer/autoload_files.php vendored Normal file
View File

@ -0,0 +1,10 @@
<?php
// autoload_files.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'253c157292f75eb38082b5acb06f3f01' => $vendorDir . '/nikic/fast-route/src/functions.php',
);

14
vendor/composer/autoload_namespaces.php vendored Normal file
View File

@ -0,0 +1,14 @@
<?php
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'ZendXml\\' => array($vendorDir . '/zendframework/zendxml/library'),
'Upload' => array($vendorDir . '/codeguy/upload/src'),
'Pimple' => array($vendorDir . '/pimple/pimple/src'),
'PicoFeed' => array($vendorDir . '/fguillot/picofeed/lib'),
'Parsedown' => array($vendorDir . '/erusev/parsedown'),
);

14
vendor/composer/autoload_psr4.php vendored Normal file
View File

@ -0,0 +1,14 @@
<?php
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Symfony\\Component\\Yaml\\' => array($vendorDir . '/symfony/yaml'),
'Slim\\' => array($vendorDir . '/slim/slim/Slim'),
'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src'),
'Interop\\Container\\' => array($vendorDir . '/container-interop/container-interop/src/Interop/Container'),
'FastRoute\\' => array($vendorDir . '/nikic/fast-route/src'),
);

70
vendor/composer/autoload_real.php vendored Normal file
View File

@ -0,0 +1,70 @@
<?php
// autoload_real.php @generated by Composer
class ComposerAutoloaderInitd1db2574a85c0ba6f142743249ba228f
{
private static $loader;
public static function loadClassLoader($class)
{
if ('Composer\Autoload\ClassLoader' === $class) {
require __DIR__ . '/ClassLoader.php';
}
}
public static function getLoader()
{
if (null !== self::$loader) {
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInitd1db2574a85c0ba6f142743249ba228f', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
spl_autoload_unregister(array('ComposerAutoloaderInitd1db2574a85c0ba6f142743249ba228f', 'loadClassLoader'));
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
if ($useStaticLoader) {
require_once __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInitd1db2574a85c0ba6f142743249ba228f::getInitializer($loader));
} else {
$map = require __DIR__ . '/autoload_namespaces.php';
foreach ($map as $namespace => $path) {
$loader->set($namespace, $path);
}
$map = require __DIR__ . '/autoload_psr4.php';
foreach ($map as $namespace => $path) {
$loader->setPsr4($namespace, $path);
}
$classMap = require __DIR__ . '/autoload_classmap.php';
if ($classMap) {
$loader->addClassMap($classMap);
}
}
$loader->register(true);
if ($useStaticLoader) {
$includeFiles = Composer\Autoload\ComposerStaticInitd1db2574a85c0ba6f142743249ba228f::$files;
} else {
$includeFiles = require __DIR__ . '/autoload_files.php';
}
foreach ($includeFiles as $fileIdentifier => $file) {
composerRequired1db2574a85c0ba6f142743249ba228f($fileIdentifier, $file);
}
return $loader;
}
}
function composerRequired1db2574a85c0ba6f142743249ba228f($fileIdentifier, $file)
{
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
require $file;
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
}
}

97
vendor/composer/autoload_static.php vendored Normal file
View File

@ -0,0 +1,97 @@
<?php
// autoload_static.php @generated by Composer
namespace Composer\Autoload;
class ComposerStaticInitd1db2574a85c0ba6f142743249ba228f
{
public static $files = array (
'253c157292f75eb38082b5acb06f3f01' => __DIR__ . '/..' . '/nikic/fast-route/src/functions.php',
);
public static $prefixLengthsPsr4 = array (
'S' =>
array (
'Symfony\\Component\\Yaml\\' => 23,
'Slim\\' => 5,
),
'P' =>
array (
'Psr\\Http\\Message\\' => 17,
),
'I' =>
array (
'Interop\\Container\\' => 18,
),
'F' =>
array (
'FastRoute\\' => 10,
),
);
public static $prefixDirsPsr4 = array (
'Symfony\\Component\\Yaml\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/yaml',
),
'Slim\\' =>
array (
0 => __DIR__ . '/..' . '/slim/slim/Slim',
),
'Psr\\Http\\Message\\' =>
array (
0 => __DIR__ . '/..' . '/psr/http-message/src',
),
'Interop\\Container\\' =>
array (
0 => __DIR__ . '/..' . '/container-interop/container-interop/src/Interop/Container',
),
'FastRoute\\' =>
array (
0 => __DIR__ . '/..' . '/nikic/fast-route/src',
),
);
public static $prefixesPsr0 = array (
'Z' =>
array (
'ZendXml\\' =>
array (
0 => __DIR__ . '/..' . '/zendframework/zendxml/library',
),
),
'U' =>
array (
'Upload' =>
array (
0 => __DIR__ . '/..' . '/codeguy/upload/src',
),
),
'P' =>
array (
'Pimple' =>
array (
0 => __DIR__ . '/..' . '/pimple/pimple/src',
),
'PicoFeed' =>
array (
0 => __DIR__ . '/..' . '/fguillot/picofeed/lib',
),
'Parsedown' =>
array (
0 => __DIR__ . '/..' . '/erusev/parsedown',
),
),
);
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInitd1db2574a85c0ba6f142743249ba228f::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInitd1db2574a85c0ba6f142743249ba228f::$prefixDirsPsr4;
$loader->prefixesPsr0 = ComposerStaticInitd1db2574a85c0ba6f142743249ba228f::$prefixesPsr0;
}, null, ClassLoader::class);
}
}

500
vendor/composer/installed.json vendored Normal file
View File

@ -0,0 +1,500 @@
[
{
"name": "zendframework/zendxml",
"version": "1.0.2",
"version_normalized": "1.0.2.0",
"source": {
"type": "git",
"url": "https://github.com/zendframework/ZendXml.git",
"reference": "7b64507bc35d841c9c5802d67f6f87ef8e1a58c9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/zendframework/ZendXml/zipball/7b64507bc35d841c9c5802d67f6f87ef8e1a58c9",
"reference": "7b64507bc35d841c9c5802d67f6f87ef8e1a58c9",
"shasum": ""
},
"require": {
"php": "^5.3.3 || ^7.0"
},
"require-dev": {
"phpunit/phpunit": "^3.7 || ^4.0",
"squizlabs/php_codesniffer": "^1.5"
},
"time": "2016-02-04T21:02:08+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-0": {
"ZendXml\\": "library/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"description": "Utility library for XML usage, best practices, and security in PHP",
"homepage": "http://packages.zendframework.com/",
"keywords": [
"security",
"xml",
"zf2"
]
},
{
"name": "container-interop/container-interop",
"version": "1.1.0",
"version_normalized": "1.1.0.0",
"source": {
"type": "git",
"url": "https://github.com/container-interop/container-interop.git",
"reference": "fc08354828f8fd3245f77a66b9e23a6bca48297e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/container-interop/container-interop/zipball/fc08354828f8fd3245f77a66b9e23a6bca48297e",
"reference": "fc08354828f8fd3245f77a66b9e23a6bca48297e",
"shasum": ""
},
"time": "2014-12-30T15:22:37+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"Interop\\Container\\": "src/Interop/Container/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "Promoting the interoperability of container objects (DIC, SL, etc.)"
},
{
"name": "pimple/pimple",
"version": "v3.0.2",
"version_normalized": "3.0.2.0",
"source": {
"type": "git",
"url": "https://github.com/silexphp/Pimple.git",
"reference": "a30f7d6e57565a2e1a316e1baf2a483f788b258a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/silexphp/Pimple/zipball/a30f7d6e57565a2e1a316e1baf2a483f788b258a",
"reference": "a30f7d6e57565a2e1a316e1baf2a483f788b258a",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"time": "2015-09-11T15:10:35+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.0.x-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-0": {
"Pimple": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
}
],
"description": "Pimple, a simple Dependency Injection Container",
"homepage": "http://pimple.sensiolabs.org",
"keywords": [
"container",
"dependency injection"
]
},
{
"name": "codeguy/upload",
"version": "1.3.2",
"version_normalized": "1.3.2.0",
"source": {
"type": "git",
"url": "https://github.com/codeguy/Upload.git",
"reference": "6a9e5e1fb58d65346d0e557db2d46fb25efd3e37"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/codeguy/Upload/zipball/6a9e5e1fb58d65346d0e557db2d46fb25efd3e37",
"reference": "6a9e5e1fb58d65346d0e557db2d46fb25efd3e37",
"shasum": ""
},
"require": {
"ext-fileinfo": "*",
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "3.7.*"
},
"time": "2013-07-07T17:01:41+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-0": {
"Upload": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Josh Lockhart",
"email": "info@joshlockhart.com",
"homepage": "http://www.joshlockhart.com/"
}
],
"description": "Handle file uploads with extensible validation and storage strategies",
"homepage": "http://github.com/codeguy/Upload",
"keywords": [
"file",
"upload",
"validation"
]
},
{
"name": "erusev/parsedown",
"version": "1.6.1",
"version_normalized": "1.6.1.0",
"source": {
"type": "git",
"url": "https://github.com/erusev/parsedown.git",
"reference": "20ff8bbb57205368b4b42d094642a3e52dac85fb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/erusev/parsedown/zipball/20ff8bbb57205368b4b42d094642a3e52dac85fb",
"reference": "20ff8bbb57205368b4b42d094642a3e52dac85fb",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"time": "2016-11-02T15:56:58+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-0": {
"Parsedown": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Emanuil Rusev",
"email": "hello@erusev.com",
"homepage": "http://erusev.com"
}
],
"description": "Parser for Markdown.",
"homepage": "http://parsedown.org",
"keywords": [
"markdown",
"parser"
]
},
{
"name": "fguillot/picofeed",
"version": "v0.1.28",
"version_normalized": "0.1.28.0",
"source": {
"type": "git",
"url": "https://github.com/fguillot/picoFeed.git",
"reference": "9da506c308bcb40b6fc630f9123466028c03170b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/fguillot/picoFeed/zipball/9da506c308bcb40b6fc630f9123466028c03170b",
"reference": "9da506c308bcb40b6fc630f9123466028c03170b",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-iconv": "*",
"ext-libxml": "*",
"ext-simplexml": "*",
"ext-xml": "*",
"php": ">=5.3.0",
"zendframework/zendxml": "^1.0"
},
"require-dev": {
"phpdocumentor/reflection-docblock": "2.0.4",
"phpunit/phpunit": "4.8.26",
"symfony/yaml": "2.8.7"
},
"suggest": {
"ext-curl": "PicoFeed will use cURL if present"
},
"time": "2016-12-29T00:06:41+00:00",
"bin": [
"picofeed"
],
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-0": {
"PicoFeed": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Frédéric Guillot"
}
],
"description": "Modern library to handle RSS/Atom feeds",
"homepage": "https://github.com/fguillot/picoFeed"
},
{
"name": "nikic/fast-route",
"version": "v1.1.0",
"version_normalized": "1.1.0.0",
"source": {
"type": "git",
"url": "https://github.com/nikic/FastRoute.git",
"reference": "f3dcf5130e634b6123d40727d612ec6aa4f61fb3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nikic/FastRoute/zipball/f3dcf5130e634b6123d40727d612ec6aa4f61fb3",
"reference": "f3dcf5130e634b6123d40727d612ec6aa4f61fb3",
"shasum": ""
},
"require": {
"php": ">=5.4.0"
},
"time": "2016-10-20T17:36:47+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"FastRoute\\": "src/"
},
"files": [
"src/functions.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Nikita Popov",
"email": "nikic@php.net"
}
],
"description": "Fast request router for PHP",
"keywords": [
"router",
"routing"
]
},
{
"name": "psr/http-message",
"version": "1.0.1",
"version_normalized": "1.0.1.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-message.git",
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"time": "2016-08-06T14:39:51+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Psr\\Http\\Message\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interface for HTTP messages",
"homepage": "https://github.com/php-fig/http-message",
"keywords": [
"http",
"http-message",
"psr",
"psr-7",
"request",
"response"
]
},
{
"name": "slim/slim",
"version": "3.7.0",
"version_normalized": "3.7.0.0",
"source": {
"type": "git",
"url": "https://github.com/slimphp/Slim.git",
"reference": "4254e40d81559e35cdf856bcbaca5f3af468b7ef"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/slimphp/Slim/zipball/4254e40d81559e35cdf856bcbaca5f3af468b7ef",
"reference": "4254e40d81559e35cdf856bcbaca5f3af468b7ef",
"shasum": ""
},
"require": {
"container-interop/container-interop": "^1.1",
"nikic/fast-route": "^1.0",
"php": ">=5.5.0",
"pimple/pimple": "^3.0",
"psr/http-message": "^1.0"
},
"provide": {
"psr/http-message-implementation": "1.0"
},
"require-dev": {
"phpunit/phpunit": "^4.0",
"squizlabs/php_codesniffer": "^2.5"
},
"time": "2016-12-20T20:30:47+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"Slim\\": "Slim"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Rob Allen",
"email": "rob@akrabat.com",
"homepage": "http://akrabat.com"
},
{
"name": "Josh Lockhart",
"email": "hello@joshlockhart.com",
"homepage": "https://joshlockhart.com"
},
{
"name": "Gabriel Manricks",
"email": "gmanricks@me.com",
"homepage": "http://gabrielmanricks.com"
},
{
"name": "Andrew Smith",
"email": "a.smith@silentworks.co.uk",
"homepage": "http://silentworks.co.uk"
}
],
"description": "Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs",
"homepage": "https://slimframework.com",
"keywords": [
"api",
"framework",
"micro",
"router"
]
},
{
"name": "symfony/yaml",
"version": "v3.2.1",
"version_normalized": "3.2.1.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
"reference": "a7095af4b97a0955f85c8989106c249fa649011f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/yaml/zipball/a7095af4b97a0955f85c8989106c249fa649011f",
"reference": "a7095af4b97a0955f85c8989106c249fa649011f",
"shasum": ""
},
"require": {
"php": ">=5.5.9"
},
"require-dev": {
"symfony/console": "~2.8|~3.0"
},
"suggest": {
"symfony/console": "For validating YAML files using the lint command"
},
"time": "2016-12-10T10:07:06+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.2-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Symfony\\Component\\Yaml\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Yaml Component",
"homepage": "https://symfony.com"
}
]

View File

@ -0,0 +1,3 @@
composer.lock
composer.phar
/vendor/

View File

@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2013 container-interop
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,85 @@
# Container Interoperability
[![Latest Stable Version](https://poser.pugx.org/container-interop/container-interop/v/stable.png)](https://packagist.org/packages/container-interop/container-interop)
*container-interop* tries to identify and standardize features in *container* objects (service locators,
dependency injection containers, etc.) to achieve interopererability.
Through discussions and trials, we try to create a standard, made of common interfaces but also recommendations.
If PHP projects that provide container implementations begin to adopt these common standards, then PHP
applications and projects that use containers can depend on the common interfaces instead of specific
implementations. This facilitates a high-level of interoperability and flexibility that allows users to consume
*any* container implementation that can be adapted to these interfaces.
The work done in this project is not officially endorsed by the [PHP-FIG](http://www.php-fig.org/), but it is being
worked on by members of PHP-FIG and other good developers. We adhere to the spirit and ideals of PHP-FIG, and hope
this project will pave the way for one or more future PSRs.
## Installation
You can install this package through Composer:
```json
{
"require": {
"container-interop/container-interop": "~1.0"
}
}
```
The packages adheres to the [SemVer](http://semver.org/) specification, and there will be full backward compatibility
between minor versions.
## Standards
### Available
- [`ContainerInterface`](src/Interop/Container/ContainerInterface.php).
[Description](docs/ContainerInterface.md) [Meta Document](docs/ContainerInterface-meta.md).
Describes the interface of a container that exposes methods to read its entries.
- [*Delegate lookup feature*](docs/Delegate-lookup.md).
[Meta Document](docs/Delegate-lookup-meta.md).
Describes the ability for a container to delegate the lookup of its dependencies to a third-party container. This
feature lets several containers work together in a single application.
### Proposed
View open [request for comments](https://github.com/container-interop/container-interop/labels/RFC)
## Compatible projects
### Projects implementing `ContainerInterface`
- [Acclimate](https://github.com/jeremeamia/acclimate-container)
- [dcp-di](https://github.com/estelsmith/dcp-di)
- [Mouf](http://mouf-php.com)
- [Njasm Container](https://github.com/njasm/container)
- [PHP-DI](http://php-di.org)
- [PimpleInterop](https://github.com/moufmouf/pimple-interop)
- [XStatic](https://github.com/jeremeamia/xstatic)
### Projects implementing the *delegate lookup* feature
- [Mouf](http://mouf-php.com)
- [PHP-DI](http://php-di.org)
- [PimpleInterop](https://github.com/moufmouf/pimple-interop)
## Workflow
Everyone is welcome to join and contribute.
The general workflow looks like this:
1. Someone opens a discussion (GitHub issue) to suggest an interface
1. Feedback is gathered
1. The interface is added to a development branch
1. We release alpha versions so that the interface can be experimented with
1. Discussions and edits ensue until the interface is deemed stable by a general consensus
1. A new minor version of the package is released
We try to not break BC by creating new interfaces instead of editing existing ones.
While we currently work on interfaces, we are open to anything that might help towards interoperability, may that
be code, best practices, etc.

View File

@ -0,0 +1,11 @@
{
"name": "container-interop/container-interop",
"type": "library",
"description": "Promoting the interoperability of container objects (DIC, SL, etc.)",
"license": "MIT",
"autoload": {
"psr-4": {
"Interop\\Container\\": "src/Interop/Container/"
}
}
}

View File

@ -0,0 +1,114 @@
# ContainerInterface Meta Document
## Introduction
This document describes the process and discussions that lead to the `ContainerInterface`.
Its goal is to explain the reasons behind each decision.
## Goal
The goal set by `ContainerInterface` is to standardize how frameworks and libraries make use of a
container to obtain objects and parameters.
By standardizing such a behavior, frameworks and libraries using the `ContainerInterface`
could work with any compatible container.
That would allow end users to choose their own container based on their own preferences.
It is important to distinguish the two usages of a container:
- configuring entries
- fetching entries
Most of the time, those two sides are not used by the same party.
While it is often end users who tend to configure entries, it is generally the framework that fetch
entries to build the application.
This is why this interface focuses only on how entries can be fetched from a container.
## Interface name
The interface name has been thoroughly discussed and was decided by a vote.
The list of options considered with their respective votes are:
- `ContainerInterface`: +8
- `ProviderInterface`: +2
- `LocatorInterface`: 0
- `ReadableContainerInterface`: -5
- `ServiceLocatorInterface`: -6
- `ObjectFactory`: -6
- `ObjectStore`: -8
- `ConsumerInterface`: -9
[Full results of the vote](https://github.com/container-interop/container-interop/wiki/%231-interface-name:-Vote)
The complete discussion can be read in [the issue #1](https://github.com/container-interop/container-interop/issues/1).
## Interface methods
The choice of which methods the interface would contain was made after a statistical analysis of existing containers.
The results of this analysis are available [in this document](https://gist.github.com/mnapoli/6159681).
The summary of the analysis showed that:
- all containers offer a method to get an entry by its id
- a large majority name such method `get()`
- for all containers, the `get()` method has 1 mandatory parameter of type string
- some containers have an optional additional argument for `get()`, but it doesn't same the same purpose between containers
- a large majority of the containers offer a method to test if it can return an entry by its id
- a majority name such method `has()`
- for all containers offering `has()`, the method has exactly 1 parameter of type string
- a large majority of the containers throw an exception rather than returning null when an entry is not found in `get()`
- a large majority of the containers don't implement `ArrayAccess`
The question of whether to include methods to define entries has been discussed in
[issue #1](https://github.com/container-interop/container-interop/issues/1).
It has been judged that such methods do not belong in the interface described here because it is out of its scope
(see the "Goal" section).
As a result, the `ContainerInterface` contains two methods:
- `get()`, returning anything, with one mandatory string parameter. Should throw an exception if the entry is not found.
- `has()`, returning a boolean, with one mandatory string parameter.
### Number of parameters in `get()` method
While `ContainerInterface` only defines one mandatory parameter in `get()`, it is not incompatible with
existing containers that have additional optional parameters. PHP allows an implementation to offer more parameters
as long as they are optional, because the implementation *does* satisfy the interface.
This issue has been discussed in [issue #6](https://github.com/container-interop/container-interop/issues/6).
### Type of the `$id` parameter
The type of the `$id` parameter in `get()` and `has()` has been discussed in
[issue #6](https://github.com/container-interop/container-interop/issues/6).
While `string` is used in all the containers that were analyzed, it was suggested that allowing
anything (such as objects) could allow containers to offer a more advanced query API.
An example given was to use the container as an object builder. The `$id` parameter would then be an
object that would describe how to create an instance.
The conclusion of the discussion was that this was beyond the scope of getting entries from a container without
knowing how the container provided them, and it was more fit for a factory.
## Contributors
Are listed here all people that contributed in the discussions or votes, by alphabetical order:
- [Amy Stephen](https://github.com/AmyStephen)
- [David Négrier](https://github.com/moufmouf)
- [Don Gilbert](https://github.com/dongilbert)
- [Jason Judge](https://github.com/judgej)
- [Jeremy Lindblom](https://github.com/jeremeamia)
- [Marco Pivetta](https://github.com/Ocramius)
- [Matthieu Napoli](https://github.com/mnapoli)
- [Paul M. Jones](https://github.com/pmjones)
- [Stephan Hochdörfer](https://github.com/shochdoerfer)
- [Taylor Otwell](https://github.com/taylorotwell)
## Relevant links
- [`ContainerInterface.php`](https://github.com/container-interop/container-interop/blob/master/src/Interop/Container/ContainerInterface.php)
- [List of all issues](https://github.com/container-interop/container-interop/issues?labels=ContainerInterface&milestone=&page=1&state=closed)
- [Vote for the interface name](https://github.com/container-interop/container-interop/wiki/%231-interface-name:-Vote)

View File

@ -0,0 +1,153 @@
Container interface
===================
This document describes a common interface for dependency injection containers.
The goal set by `ContainerInterface` is to standardize how frameworks and libraries make use of a
container to obtain objects and parameters (called *entries* in the rest of this document).
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD",
"SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be
interpreted as described in [RFC 2119][].
The word `implementor` in this document is to be interpreted as someone
implementing the `ContainerInterface` in a depency injection-related library or framework.
Users of dependency injections containers (DIC) are refered to as `user`.
[RFC 2119]: http://tools.ietf.org/html/rfc2119
1. Specification
-----------------
### 1.1 Basics
- The `Interop\Container\ContainerInterface` exposes two methods : `get` and `has`.
- `get` takes one mandatory parameter: an entry identifier. It MUST be a string.
A call to `get` can return anything (a *mixed* value), or throws an exception if the identifier
is not known to the container. Two successive calls to `get` with the same
identifier SHOULD return the same value. However, depending on the `implementor`
design and/or `user` configuration, different values might be returned, so
`user` SHOULD NOT rely on getting the same value on 2 successive calls.
While `ContainerInterface` only defines one mandatory parameter in `get()`, implementations
MAY accept additional optional parameters.
- `has` takes one unique parameter: an entry identifier. It MUST return `true`
if an entry identifier is known to the container and `false` if it is not.
### 1.2 Exceptions
Exceptions directly thrown by the container MUST implement the
[`Interop\Container\Exception\ContainerException`](../src/Interop/Container/Exception/ContainerException.php).
A call to the `get` method with a non-existing id should throw a
[`Interop\Container\Exception\NotFoundException`](../src/Interop/Container/Exception/NotFoundException.php).
### 1.3 Additional features
This section describes additional features that MAY be added to a container. Containers are not
required to implement these features to respect the ContainerInterface.
#### 1.3.1 Delegate lookup feature
The goal of the *delegate lookup* feature is to allow several containers to share entries.
Containers implementing this feature can perform dependency lookups in other containers.
Containers implementing this feature will offer a greater lever of interoperability
with other containers. Implementation of this feature is therefore RECOMMENDED.
A container implementing this feature:
- MUST implement the `ContainerInterface`
- MUST provide a way to register a delegate container (using a constructor parameter, or a setter,
or any possible way). The delegate container MUST implement the `ContainerInterface`.
When a container is configured to use a delegate container for dependencies:
- Calls to the `get` method should only return an entry if the entry is part of the container.
If the entry is not part of the container, an exception should be thrown
(as requested by the `ContainerInterface`).
- Calls to the `has` method should only return `true` if the entry is part of the container.
If the entry is not part of the container, `false` should be returned.
- If the fetched entry has dependencies, **instead** of performing
the dependency lookup in the container, the lookup is performed on the *delegate container*.
Important! By default, the lookup SHOULD be performed on the delegate container **only**, not on the container itself.
It is however allowed for containers to provide exception cases for special entries, and a way to lookup
into the same container (or another container) instead of the delegate container.
2. Package
----------
The interfaces and classes described as well as relevant exception are provided as part of the
[container-interop/container-interop](https://packagist.org/packages/container-interop/container-interop) package.
3. `Interop\Container\ContainerInterface`
-----------------------------------------
```php
<?php
namespace Interop\Container;
use Interop\Container\Exception\ContainerException;
use Interop\Container\Exception\NotFoundException;
/**
* Describes the interface of a container that exposes methods to read its entries.
*/
interface ContainerInterface
{
/**
* Finds an entry of the container by its identifier and returns it.
*
* @param string $id Identifier of the entry to look for.
*
* @throws NotFoundException No entry was found for this identifier.
* @throws ContainerException Error while retrieving the entry.
*
* @return mixed Entry.
*/
public function get($id);
/**
* Returns true if the container can return an entry for the given identifier.
* Returns false otherwise.
*
* @param string $id Identifier of the entry to look for.
*
* @return boolean
*/
public function has($id);
}
```
4. `Interop\Container\Exception\ContainerException`
---------------------------------------------------
```php
<?php
namespace Interop\Container\Exception;
/**
* Base interface representing a generic exception in a container.
*/
interface ContainerException
{
}
```
5. `Interop\Container\Exception\NotFoundException`
---------------------------------------------------
```php
<?php
namespace Interop\Container\Exception;
/**
* No entry was found in the container.
*/
interface NotFoundException extends ContainerException
{
}
```

View File

@ -0,0 +1,259 @@
Delegate lookup feature Meta Document
=====================================
1. Summary
----------
This document describes the *delegate lookup feature*.
Containers are not required to implement this feature to respect the `ContainerInterface`.
However, containers implementing this feature will offer a greater lever of interoperability
with other containers, allowing multiple containers to share entries in the same application.
Implementation of this feature is therefore recommanded.
2. Why Bother?
--------------
The [`ContainerInterface`](../src/Interop/Container/ContainerInterface.php) ([meta doc](ContainerInterface.md))
standardizes how frameworks and libraries make use of a container to obtain objects and parameters.
By standardizing such a behavior, frameworks and libraries relying on the `ContainerInterface`
could work with any compatible container.
That would allow end users to choose their own container based on their own preferences.
The `ContainerInterface` is also enough if we want to have several containers side-by-side in the same
application. For instance, this is what the [CompositeContainer](https://github.com/jeremeamia/acclimate-container/blob/master/src/CompositeContainer.php)
class of [Acclimate](https://github.com/jeremeamia/acclimate-container) is designed for:
![Side by side containers](images/side_by_side_containers.png)
However, an instance in container 1 cannot reference an instance in container 2.
It would be better if an instance of container 1 could reference an instance in container 2,
and the opposite should be true.
![Interoperating containers](images/interoperating_containers.png)
In the sample above, entry 1 in container 1 is referencing entry 3 in container 2.
3. Scope
--------
### 3.1 Goals
The goal of the *delegate lookup* feature is to allow several containers to share entries.
4. Approaches
-------------
### 4.1 Chosen Approach
Containers implementing this feature can perform dependency lookups in other containers.
A container implementing this feature:
- must implement the `ContainerInterface`
- must provide a way to register a *delegate container* (using a constructor parameter, or a setter, or any
possible way). The *delegate container* must implement the `ContainerInterface`.
When a *delegate container* is configured on a container:
- Calls to the `get` method should only return an entry if the entry is part of the container.
If the entry is not part of the container, an exception should be thrown (as required in the `ContainerInterface`).
- Calls to the `has` method should only return *true* if the entry is part of the container.
If the entry is not part of the container, *false* should be returned.
- Finally, the important part: if the entry we are fetching has dependencies,
**instead** of perfoming the dependency lookup in the container, the lookup is performed on the *delegate container*.
Important! By default, the lookup should be performed on the delegate container **only**, not on the container itself.
It is however allowed for containers to provide exception cases for special entries, and a way to lookup into
the same container (or another container) instead of the delegate container.
### 4.2 Typical usage
The *delegate container* will usually be a composite container. A composite container is a container that
contains several other containers. When performing a lookup on a composite container, the inner containers are
queried until one container returns an entry.
An inner container implementing the *delegate lookup feature* will return entries it contains, but if these
entries have dependencies, the dependencies lookup calls will be performed on the composite container, giving
a chance to all containers to answer.
Interestingly enough, the order in which containers are added in the composite container matters. Indeed,
the first containers to be added in the composite container can "override" the entries of containers with
lower priority.
![Containers priority](images/priority.png)
In the example above, "container 2" contains a controller "myController" and the controller is referencing an
"entityManager" entry. "Container 1" contains also an entry named "entityManager".
Without the *delegate lookup* feature, when requesting the "myController" instance to container 2, it would take
in charge the instanciation of both entries.
However, using the *delegate lookup* feature, here is what happens when we ask the composite controller for the
"myController" instance:
- The composite controller asks container 1 if if contains the "myController" instance. The answer is no.
- The composite controller asks container 2 if if contains the "myController" instance. The answer is yes.
- The composite controller performs a `get` call on container 2 for the "myController" instance.
- Container 2 sees that "myController" has a dependency on "entityManager".
- Container 2 delegates the lookup of "entityManager" to the composite controller.
- The composite controller asks container 1 if if contains the "entityManager" instance. The answer is yes.
- The composite controller performs a `get` call on container 1 for the "entityManager" instance.
In the end, we get a controller instanciated by container 2 that references an entityManager instanciated
by container 1.
### 4.3 Alternative: the fallback strategy
The first proposed approach we tried was to perform all the lookups in the "local" container,
and if a lookup fails in the container, to use the delegate container. In this scenario, the
delegate container is used in "fallback" mode.
This strategy has been described in @moufmouf blog post: http://mouf-php.com/container-interop-whats-next (solution 1).
It was also discussed [here](https://github.com/container-interop/container-interop/pull/8#issuecomment-33570697) and
[here](https://github.com/container-interop/container-interop/pull/20#issuecomment-56599631).
Problems with this strategy:
- Heavy problem regarding infinite loops
- Unable to overload a container entry with the delegate container entry
### 4.4 Alternative: force implementing an interface
The first proposed approach was to develop a `ParentAwareContainerInterface` interface.
It was proposed here: https://github.com/container-interop/container-interop/pull/8
The interface would have had the behaviour of the delegate lookup feature but would have forced the addition of
a `setParentContainter` method:
```php
interface ParentAwareContainerInterface extends ReadableContainerInterface {
/**
* Sets the parent container associated to that container. This container will call
* the parent container to fetch dependencies.
*
* @param ContainerInterface $container
*/
public function setParentContainer(ContainerInterface $container);
}
```
The interface idea was first questioned by @Ocramius [here](https://github.com/container-interop/container-interop/pull/8#issuecomment-51721777).
@Ocramius expressed the idea that an interface should not contain setters, otherwise, it is forcing implementation
details on the class implementing the interface.
Then @mnapoli made a proposal for a "convention" [here](https://github.com/container-interop/container-interop/pull/8#issuecomment-51841079),
this idea was further discussed until all participants in the discussion agreed to remove the interface idea
and replace it with a "standard" feature.
**Pros:**
If we had had an interface, we could have delegated the registration of the delegate/composite container to the
the delegate/composite container itself.
For instance:
```php
$containerA = new ContainerA();
$containerB = new ContainerB();
$compositeContainer = new CompositeContainer([$containerA, $containerB]);
// The call to 'setParentContainer' is delegated to the CompositeContainer
// It is not the responsibility of the user anymore.
class CompositeContainer {
...
public function __construct($containers) {
foreach ($containers as $container) {
if ($container instanceof ParentAwareContainerInterface) {
$container->setParentContainer($this);
}
}
...
}
}
```
**Cons:**
Cons have been extensively discussed [here](https://github.com/container-interop/container-interop/pull/8#issuecomment-51721777).
Basically, forcing a setter into an interface is a bad idea. Setters are similar to constructor arguments,
and it's a bad idea to standardize a constructor: how the delegate container is configured into a container is an implementation detail. This outweights the benefits of the interface.
### 4.4 Alternative: no exception case for delegate lookups
Originally, the proposed wording for delegate lookup calls was:
> Important! The lookup MUST be performed on the delegate container **only**, not on the container itself.
This was later replaced by:
> Important! By default, the lookup SHOULD be performed on the delegate container **only**, not on the container itself.
>
> It is however allowed for containers to provide exception cases for special entries, and a way to lookup
> into the same container (or another container) instead of the delegate container.
Exception cases have been allowed to avoid breaking dependencies with some services that must be provided
by the container (on @njasm proposal). This was proposed here: https://github.com/container-interop/container-interop/pull/20#issuecomment-56597235
### 4.5 Alternative: having one of the containers act as the composite container
In real-life scenarios, we usually have a big framework (Symfony 2, Zend Framework 2, etc...) and we want to
add another DI container to this container. Most of the time, the "big" framework will be responsible for
creating the controller's instances, using it's own DI container. Until *container-interop* is fully adopted,
the "big" framework will not be aware of the existence of a composite container that it should use instead
of its own container.
For this real-life use cases, @mnapoli and @moufmouf proposed to extend the "big" framework's DI container
to make it act as a composite container.
This has been discussed [here](https://github.com/container-interop/container-interop/pull/8#issuecomment-40367194)
and [here](http://mouf-php.com/container-interop-whats-next#solution4).
This was implemented in Symfony 2 using:
- [interop.symfony.di](https://github.com/thecodingmachine/interop.symfony.di/tree/v0.1.0)
- [framework interop](https://github.com/mnapoli/framework-interop/)
This was implemented in Silex using:
- [interop.silex.di](https://github.com/thecodingmachine/interop.silex.di)
Having a container act as the composite container is not part of the delegate lookup standard because it is
simply a temporary design pattern used to make existing frameworks that do not support yet ContainerInterop
play nice with other DI containers.
5. Implementations
------------------
The following projects already implement the delegate lookup feature:
- [Mouf](http://mouf-php.com), through the [`setDelegateLookupContainer` method](https://github.com/thecodingmachine/mouf/blob/2.0/src/Mouf/MoufManager.php#L2120)
- [PHP-DI](http://php-di.org/), through the [`$wrapperContainer` parameter of the constructor](https://github.com/mnapoli/PHP-DI/blob/master/src/DI/Container.php#L72)
- [pimple-interop](https://github.com/moufmouf/pimple-interop), through the [`$container` parameter of the constructor](https://github.com/moufmouf/pimple-interop/blob/master/src/Interop/Container/Pimple/PimpleInterop.php#L62)
6. People
---------
Are listed here all people that contributed in the discussions, by alphabetical order:
- [Alexandru Pătrănescu](https://github.com/drealecs)
- [Ben Peachey](https://github.com/potherca)
- [David Négrier](https://github.com/moufmouf)
- [Jeremy Lindblom](https://github.com/jeremeamia)
- [Marco Pivetta](https://github.com/Ocramius)
- [Matthieu Napoli](https://github.com/mnapoli)
- [Nelson J Morais](https://github.com/njasm)
- [Phil Sturgeon](https://github.com/philsturgeon)
- [Stephan Hochdörfer](https://github.com/shochdoerfer)
7. Relevant Links
-----------------
_**Note:** Order descending chronologically._
- [Pull request on the delegate lookup feature](https://github.com/container-interop/container-interop/pull/20)
- [Pull request on the interface idea](https://github.com/container-interop/container-interop/pull/8)
- [Original article exposing the delegate lookup idea along many others](http://mouf-php.com/container-interop-whats-next)

View File

@ -0,0 +1,60 @@
Delegate lookup feature
=======================
This document describes a standard for dependency injection containers.
The goal set by the *delegate lookup* feature is to allow several containers to share entries.
Containers implementing this feature can perform dependency lookups in other containers.
Containers implementing this feature will offer a greater lever of interoperability
with other containers. Implementation of this feature is therefore RECOMMENDED.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD",
"SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be
interpreted as described in [RFC 2119][].
The word `implementor` in this document is to be interpreted as someone
implementing the delegate lookup feature in a dependency injection-related library or framework.
Users of dependency injections containers (DIC) are refered to as `user`.
[RFC 2119]: http://tools.ietf.org/html/rfc2119
1. Vocabulary
-------------
In a dependency injection container, the container is used to fetch entries.
Entries can have dependencies on other entries. Usually, these other entries are fetched by the container.
The *delegate lookup* feature is the ability for a container to fetch dependencies in
another container. In the rest of the document, the word "container" will reference the container
implemented by the implementor. The word "delegate container" will reference the container we are
fetching the dependencies from.
2. Specification
----------------
A container implementing the *delegate lookup* feature:
- MUST implement the [`ContainerInterface`](ContainerInterface.md)
- MUST provide a way to register a delegate container (using a constructor parameter, or a setter,
or any possible way). The delegate container MUST implement the [`ContainerInterface`](ContainerInterface.md).
When a container is configured to use a delegate container for dependencies:
- Calls to the `get` method should only return an entry if the entry is part of the container.
If the entry is not part of the container, an exception should be thrown
(as requested by the [`ContainerInterface`](ContainerInterface.md)).
- Calls to the `has` method should only return `true` if the entry is part of the container.
If the entry is not part of the container, `false` should be returned.
- If the fetched entry has dependencies, **instead** of performing
the dependency lookup in the container, the lookup is performed on the *delegate container*.
Important: By default, the dependency lookups SHOULD be performed on the delegate container **only**, not on the container itself.
It is however allowed for containers to provide exception cases for special entries, and a way to lookup
into the same container (or another container) instead of the delegate container.
3. Package / Interface
----------------------
This feature is not tied to any code, interface or package.

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -0,0 +1,37 @@
<?php
/**
* @license http://www.opensource.org/licenses/mit-license.php MIT (see the LICENSE file)
*/
namespace Interop\Container;
use Interop\Container\Exception\ContainerException;
use Interop\Container\Exception\NotFoundException;
/**
* Describes the interface of a container that exposes methods to read its entries.
*/
interface ContainerInterface
{
/**
* Finds an entry of the container by its identifier and returns it.
*
* @param string $id Identifier of the entry to look for.
*
* @throws NotFoundException No entry was found for this identifier.
* @throws ContainerException Error while retrieving the entry.
*
* @return mixed Entry.
*/
public function get($id);
/**
* Returns true if the container can return an entry for the given identifier.
* Returns false otherwise.
*
* @param string $id Identifier of the entry to look for.
*
* @return boolean
*/
public function has($id);
}

View File

@ -0,0 +1,13 @@
<?php
/**
* @license http://www.opensource.org/licenses/mit-license.php MIT (see the LICENSE file)
*/
namespace Interop\Container\Exception;
/**
* Base interface representing a generic exception in a container.
*/
interface ContainerException
{
}

View File

@ -0,0 +1,13 @@
<?php
/**
* @license http://www.opensource.org/licenses/mit-license.php MIT (see the LICENSE file)
*/
namespace Interop\Container\Exception;
/**
* No entry was found in the container.
*/
interface NotFoundException extends ContainerException
{
}

16
vendor/erusev/parsedown/.travis.yml vendored Normal file
View File

@ -0,0 +1,16 @@
language: php
php:
- 7.1
- 7.0
- 5.6
- 5.5
- 5.4
- 5.3
- hhvm
- hhvm-nightly
matrix:
fast_finish: true
allow_failures:
- php: hhvm-nightly

20
vendor/erusev/parsedown/LICENSE.txt vendored Normal file
View File

@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2013 Emanuil Rusev, erusev.com
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

1548
vendor/erusev/parsedown/Parsedown.php vendored Normal file

File diff suppressed because it is too large Load Diff

56
vendor/erusev/parsedown/README.md vendored Normal file
View File

@ -0,0 +1,56 @@
> You might also like [Caret](http://caret.io?ref=parsedown) - our Markdown editor for Mac / Windows / Linux.
## Parsedown
[![Build Status](https://img.shields.io/travis/erusev/parsedown/master.svg?style=flat-square)](https://travis-ci.org/erusev/parsedown)
<!--[![Total Downloads](http://img.shields.io/packagist/dt/erusev/parsedown.svg?style=flat-square)](https://packagist.org/packages/erusev/parsedown)-->
Better Markdown Parser in PHP
[Demo](http://parsedown.org/demo) |
[Benchmarks](http://parsedown.org/speed) |
[Tests](http://parsedown.org/tests/) |
[Documentation](https://github.com/erusev/parsedown/wiki/)
### Features
* One File
* Super Fast
* Extensible
* [GitHub flavored](https://help.github.com/articles/github-flavored-markdown)
* Tested in 5.3 to 7.1 and in HHVM
* [Markdown Extra extension](https://github.com/erusev/parsedown-extra)
### Installation
Include `Parsedown.php` or install [the composer package](https://packagist.org/packages/erusev/parsedown).
### Example
``` php
$Parsedown = new Parsedown();
echo $Parsedown->text('Hello _Parsedown_!'); # prints: <p>Hello <em>Parsedown</em>!</p>
```
More examples in [the wiki](https://github.com/erusev/parsedown/wiki/) and in [this video tutorial](http://youtu.be/wYZBY8DEikI).
### Questions
**How does Parsedown work?**
It tries to read Markdown like a human. First, it looks at the lines. Its interested in how the lines start. This helps it recognise blocks. It knows, for example, that if a line starts with a `-` then perhaps it belongs to a list. Once it recognises the blocks, it continues to the content. As it reads, it watches out for special characters. This helps it recognise inline elements (or inlines).
We call this approach "line based". We believe that Parsedown is the first Markdown parser to use it. Since the release of Parsedown, other developers have used the same approach to develop other Markdown parsers in PHP and in other languages.
**Is it compliant with CommonMark?**
It passes most of the CommonMark tests. Most of the tests that don't pass deal with cases that are quite uncommon. Still, as CommonMark matures, compliance should improve.
**Who uses it?**
[phpDocumentor](http://www.phpdoc.org/), [October CMS](http://octobercms.com/), [Bolt CMS](http://bolt.cm/), [Kirby CMS](http://getkirby.com/), [Grav CMS](http://getgrav.org/), [Statamic CMS](http://www.statamic.com/), [Herbie CMS](http://www.getherbie.org/), [RaspberryPi.org](http://www.raspberrypi.org/) and [more](https://packagist.org/packages/erusev/parsedown/dependents).
**How can I help?**
Use it, star it, share it and if you feel generous, [donate](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=528P3NZQMP8N2).

21
vendor/erusev/parsedown/composer.json vendored Normal file
View File

@ -0,0 +1,21 @@
{
"name": "erusev/parsedown",
"description": "Parser for Markdown.",
"keywords": ["markdown", "parser"],
"homepage": "http://parsedown.org",
"type": "library",
"license": "MIT",
"authors": [
{
"name": "Emanuil Rusev",
"email": "hello@erusev.com",
"homepage": "http://erusev.com"
}
],
"require": {
"php": ">=5.3.0"
},
"autoload": {
"psr-0": {"Parsedown": ""}
}
}

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="test/bootstrap.php" colors="true">
<testsuites>
<testsuite>
<file>test/ParsedownTest.php</file>
</testsuite>
</testsuites>
</phpunit>

View File

@ -0,0 +1,74 @@
<?php
/**
* Test Parsedown against the CommonMark spec.
*
* Some code based on the original JavaScript test runner by jgm.
*
* @link http://commonmark.org/ CommonMark
* @link http://git.io/8WtRvQ JavaScript test runner
*/
class CommonMarkTest extends PHPUnit_Framework_TestCase
{
const SPEC_URL = 'https://raw.githubusercontent.com/jgm/stmd/master/spec.txt';
/**
* @dataProvider data
* @param $section
* @param $markdown
* @param $expectedHtml
*/
function test_($section, $markdown, $expectedHtml)
{
$Parsedown = new Parsedown();
$Parsedown->setUrlsLinked(false);
$actualHtml = $Parsedown->text($markdown);
$actualHtml = $this->normalizeMarkup($actualHtml);
$this->assertEquals($expectedHtml, $actualHtml);
}
function data()
{
$spec = file_get_contents(self::SPEC_URL);
$spec = strstr($spec, '<!-- END TESTS -->', true);
$tests = array();
$currentSection = '';
preg_replace_callback(
'/^\.\n([\s\S]*?)^\.\n([\s\S]*?)^\.$|^#{1,6} *(.*)$/m',
function($matches) use ( & $tests, & $currentSection, & $testCount) {
if (isset($matches[3]) and $matches[3]) {
$currentSection = $matches[3];
} else {
$testCount++;
$markdown = $matches[1];
$markdown = preg_replace('/→/', "\t", $markdown);
$expectedHtml = $matches[2];
$expectedHtml = $this->normalizeMarkup($expectedHtml);
$tests []= array(
$currentSection, # section
$markdown, # markdown
$expectedHtml, # html
);
}
},
$spec
);
return $tests;
}
private function normalizeMarkup($markup)
{
$markup = preg_replace("/\n+/", "\n", $markup);
$markup = preg_replace('/^\s+/m', '', $markup);
$markup = preg_replace('/^((?:<[\w]+>)+)\n/m', '$1', $markup);
$markup = preg_replace('/\n((?:<\/[\w]+>)+)$/m', '$1', $markup);
$markup = trim($markup);
return $markup;
}
}

Some files were not shown because too many files have changed in this diff Show More