diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..10926e8
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,675 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ Copyright (C)
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+.
+
diff --git a/check_process b/check_process
new file mode 100644
index 0000000..359db85
--- /dev/null
+++ b/check_process
@@ -0,0 +1,62 @@
+;; Test complet sans multisite
+ auto_remove=1
+ ; Manifest
+ domain="domain.tld" (DOMAIN)
+ path="/path" (PATH)
+ admin="john" (USER)
+ language="fr_FR"
+ multisite="No"
+ is_public="Yes" (PUBLIC|public=Yes|private=No)
+ ; Checks
+ pkg_linter=1
+ setup_sub_dir=1
+ setup_root=1
+ setup_nourl=0
+ setup_private=1
+ setup_public=1
+ upgrade=1
+ backup_restore=1
+ multi_instance=1
+ wrong_user=1
+ wrong_path=1
+ incorrect_path=1
+ corrupt_source=0
+ fail_download_source=0
+ port_already_use=0
+ final_path_already_use=0
+;; Test avec multisite
+ auto_remove=1
+ ; Manifest
+ domain="domain.tld" (DOMAIN)
+ path="/path" (PATH)
+ admin="john" (USER)
+ language="fr_FR"
+ multisite="Yes"
+ is_public="Yes" (PUBLIC|public=Yes|private=No)
+ ; Checks
+ setup_sub_dir=1
+ setup_root=0
+ setup_nourl=0
+ setup_private=1
+ setup_public=1
+ upgrade=1
+ backup_restore=1
+ multi_instance=1
+ wrong_user=0
+ wrong_path=0
+ incorrect_path=0
+ corrupt_source=0
+ fail_download_source=0
+ port_already_use=0
+ final_path_already_use=0
+;;; Levels
+ Level 1=auto
+ Level 2=auto
+ Level 3=auto
+ Level 4=1
+ Level 5=1
+ Level 6=auto
+ Level 7=auto
+ Level 8=0
+ Level 9=0
+ Level 10=0
\ No newline at end of file
diff --git a/conf/php-fpm.ini b/conf/php-fpm.ini
new file mode 100644
index 0000000..55e2ba7
--- /dev/null
+++ b/conf/php-fpm.ini
@@ -0,0 +1,3 @@
+upload_max_filesize=30M
+post_max_size=30M
+; max_execution_time=60
\ No newline at end of file
diff --git a/scripts/.fonctions b/scripts/.fonctions
new file mode 100644
index 0000000..14ec502
--- /dev/null
+++ b/scripts/.fonctions
@@ -0,0 +1,205 @@
+#!/bin/bash
+
+ynh_version="2.4"
+
+YNH_VERSION () { # Renvoi le numéro de version de la moulinette Yunohost
+ ynh_version=$(sudo yunohost -v | grep "moulinette:" | cut -d' ' -f2 | cut -d'.' -f1,2)
+}
+
+CHECK_VAR () { # Vérifie que la variable n'est pas vide.
+# $1 = Variable à vérifier
+# $2 = Texte à afficher en cas d'erreur
+ test -n "$1" || (echo "$2" >&2 && false)
+}
+
+EXIT_PROPERLY () { # Provoque l'arrêt du script en cas d'erreur. Et nettoye les résidus.
+ trap '' ERR
+ echo -e "\e[91m \e[1m" # Shell in light red bold
+ echo -e "!!\n $app install's script has encountered an error. Installation was cancelled.\n!!" >&2
+
+ CLEAN_SETUP # Appel la fonction de nettoyage spécifique du script install.
+
+ # Compense le bug de ssowat qui ne supprime pas l'entrée de l'app en cas d'erreur d'installation.
+ sudo sed -i "\@\"$domain$path/\":@d" /etc/ssowat/conf.json
+
+ if [ "$ynh_version" = "2.2" ]; then
+ /bin/bash $script_dir/remove # Appel le script remove. En 2.2, ce comportement n'est pas automatique.
+ fi
+
+ ynh_die
+}
+
+TRAP_ON () { # Activate signal capture
+ trap EXIT_PROPERLY ERR # Capturing exit signals on error
+}
+
+TRAP_OFF () { # Ignoring signal capture until TRAP_ON
+ # Pour une raison que j'ignore, la fonction TRAP_ON fonctionne très bien.
+ # Mais pas la fonction TRAP_OFF...
+ # Utiliser directement `trap '' ERR` dans le code pour l'utiliser, à la place de la fonction.
+ trap '' ERR # Ignoring exit signals
+}
+
+CHECK_USER () { # Vérifie la validité de l'user admin
+# $1 = Variable de l'user admin.
+ ynh_user_exists "$1" || (echo "Wrong admin" >&2 && false)
+}
+
+CHECK_PATH () { # Vérifie la présence du / en début de path. Et son absence à la fin.
+ if [ "${path:0:1}" != "/" ]; then # Si le premier caractère n'est pas un /
+ path="/$path" # Ajoute un / en début de path
+ fi
+ if [ "${path:${#path}-1}" == "/" ] && [ ${#path} -gt 1 ]; then # Si le dernier caractère est un / et que ce n'est pas le seul caractère.
+ path="${path:0:${#path}-1}" # Supprime le dernier caractère
+ fi
+}
+
+CHECK_DOMAINPATH () { # Vérifie la disponibilité du path et du domaine.
+ sudo yunohost app checkurl $domain$path -a $app
+}
+
+CHECK_FINALPATH () { # Vérifie que le dossier de destination n'est pas déjà utilisé.
+ final_path=/var/www/$app
+ if [ -e "$final_path" ]
+ then
+ echo "This path already contains a folder" >&2
+ false
+ fi
+}
+
+GENERATE_DB () { # Créer une base de données et un utilisateur dédié au nom de l'app.
+# $1 = Nom de la base de donnée
+ # Génère un mot de passe aléatoire.
+ db_user=$1
+ db_pwd=$(head -n20 /dev/urandom | tr -c -d 'A-Za-z0-9' | head -c20)
+ CHECK_VAR "$db_pwd" "db_pwd empty"
+ # Utilise '$app' comme nom d'utilisateur et de base de donnée
+ # Initialise la base de donnée et stocke le mot de passe mysql.
+ ynh_mysql_create_db "$db_user" "$db_user" $db_pwd
+ ynh_app_setting_set $app mysqlpwd $db_pwd
+}
+
+SETUP_SOURCE () { # Télécharge la source, décompresse et copie dans $final_path
+# $1 = Nom de l'archive téléchargée.
+ wget -nv --show-progress -i ../sources/source_url -O $1
+ # Vérifie la somme de contrôle de la source téléchargée.
+ md5sum -c ../sources/source_md5 --status || (echo "Corrupt source" >&2 && false)
+ # Décompresse la source
+ if [ "$(echo ${1##*.})" == "gz" ]; then
+ tar -x -f $1
+ elif [ "$(echo ${1##*.})" == "zip" ]; then
+ unzip -q $1
+ else
+ false # Format d'archive non pris en charge.
+ fi
+ # Copie les fichiers sources
+ sudo cp -a $(cat ../sources/source_dir)/. "$final_path"
+ # Copie les fichiers additionnels ou modifiés.
+ if test -e "../sources/ajouts"; then
+ sudo cp -a ../sources/ajouts/. "$final_path"
+ fi
+}
+
+POOL_FPM () { # Créer le fichier de configuration du pool php-fpm et le configure.
+ sed -i "s@__NAMETOCHANGE__@$app@g" ../conf/php-fpm.conf
+ sed -i "s@__FINALPATH__@$final_path@g" ../conf/php-fpm.conf
+ finalphpconf=/etc/php5/fpm/pool.d/$app.conf
+ sudo cp ../conf/php-fpm.conf $finalphpconf
+ sudo chown root: $finalphpconf
+ finalphpini=/etc/php5/fpm/conf.d/20-$app.ini
+ sudo cp ../conf/php-fpm.ini $finalphpini
+ sudo chown root: $finalphpini
+ sudo service php5-fpm reload
+}
+
+STORE_MD5_CONFIG () { # Enregistre la somme de contrôle du fichier de config
+# $1 = Nom du fichier de conf pour le stockage dans settings.yml
+# $2 = Nom complet et chemin du fichier de conf.
+ ynh_app_setting_set $app $1_file_md5 $(sudo md5sum "$2" | cut -d' ' -f1)
+}
+
+CHECK_MD5_CONFIG () { # Créé un backup du fichier de config si il a été modifié.
+# $1 = Nom du fichier de conf pour le stockage dans settings.yml
+# $2 = Nom complet et chemin du fichier de conf.
+ if [ "$(ynh_app_setting_get $app $1_file_md5)" != $(sudo md5sum "$2" | cut -d' ' -f1) ]; then
+ sudo cp -a "$2" "$2.backup.$(date '+%d.%m.%y_%Hh%M,%Ss')" # Si le fichier de config a été modifié, créer un backup.
+ fi
+}
+
+FIND_PORT () { # Cherche un port libre.
+# $1 = Numéro de port pour débuter la recherche.
+ port=$1
+ while ! sudo yunohost app checkport $port ; do
+ port=$((port+1))
+ done
+ CHECK_VAR "$port" "port empty"
+}
+
+
+### REMOVE SCRIPT
+
+REMOVE_NGINX_CONF () { # Suppression de la configuration nginx
+ if [ -e "/etc/nginx/conf.d/$domain.d/$app.conf" ]; then # Delete nginx config
+ echo "Delete nginx config"
+ sudo rm "/etc/nginx/conf.d/$domain.d/$app.conf"
+ sudo service nginx reload
+ fi
+}
+
+REMOVE_FPM_CONF () { # Suppression de la configuration du pool php-fpm
+ if [ -e "/etc/php5/fpm/pool.d/$app.conf" ]; then # Delete fpm config
+ echo "Delete fpm config"
+ sudo rm "/etc/php5/fpm/pool.d/$app.conf"
+ fi
+ if [ -e "/etc/php5/fpm/conf.d/20-$app.ini" ]; then # Delete php config
+ echo "Delete php config"
+ sudo rm "/etc/php5/fpm/conf.d/20-$app.ini"
+ fi
+ sudo service php5-fpm reload
+}
+
+REMOVE_LOGROTATE_CONF () { # Suppression de la configuration de logrotate
+ if [ -e "/etc/logrotate.d/$app" ]; then
+ echo "Delete logrotate config"
+ sudo rm "/etc/logrotate.d/$app"
+ fi
+}
+
+SECURE_REMOVE () { # Suppression de dossier avec vérification des variables
+ chaine="$1" # L'argument doit être donné entre quotes simple '', pour éviter d'interpréter les variables.
+ no_var=0
+ while (echo "$chaine" | grep -q '\$') # Boucle tant qu'il y a des $ dans la chaine
+ do
+ no_var=1
+ global_var=$(echo "$chaine" | cut -d '$' -f 2) # Isole la première variable trouvée.
+ only_var=\$$(expr "$global_var" : '\([A-Za-z0-9_]*\)') # Isole complètement la variable en ajoutant le $ au début et en gardant uniquement le nom de la variable. Se débarrasse surtout du / et d'un éventuel chemin derrière.
+ real_var=$(eval "echo ${only_var}") # `eval "echo ${var}` permet d'interpréter une variable contenue dans une variable.
+ if test -z "$real_var" || [ "$real_var" = "/" ]; then
+ echo "Variable $only_var is empty, suppression of $chaine cancelled." >&2
+ return 1
+ fi
+ chaine=$(echo "$chaine" | sed "s@$only_var@$real_var@") # remplace la variable par sa valeur dans la chaine.
+ done
+ if [ "$no_var" -eq 1 ]
+ then
+ if [ -e "$chaine" ]; then
+ echo "Delete directory $chaine"
+ sudo rm -r "$chaine"
+ fi
+ return 0
+ else
+ echo "No detected variable." >&2
+ return 1
+ fi
+}
+
+REMOVE_BDD () { # Suppression de la base de donnée et de l'utilisateur associé.
+# $1 = Nom de la base de donnée
+ # Utilise '$app' comme nom d'utilisateur et de base de donnée
+ db_user=$1
+ if mysqlshow -u root -p$(sudo cat $MYSQL_ROOT_PWD_FILE) | grep -q "^| $db_user"; then
+ echo "Delete db"
+ ynh_mysql_drop_db $db_user
+ ynh_mysql_drop_user $db_user
+ fi
+}
\ No newline at end of file
diff --git a/scripts/backup b/scripts/backup
new file mode 100644
index 0000000..10a9c9c
--- /dev/null
+++ b/scripts/backup
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+# Exit on command errors and treat unset variables as an error
+set -eu
+
+# The parameter $1 is the backup directory location dedicated to the app
+backup_dir=$1
+
+# The parameter $2 is theid of the app instance
+app=$2
+
+# Source app helpers
+source /usr/share/yunohost/helpers
+
+domain=$(ynh_app_setting_get $app domain)
+final_path=$(ynh_app_setting_get $app final_path)
+
+# Copy the app files
+sudo mkdir -p ${backup_dir}/var/www
+sudo cp -a $final_path "${backup_dir}/var/www/$app"
+
+# Copy the conf files
+sudo mkdir -p "${backup_dir}/conf"
+sudo cp -a /etc/nginx/conf.d/$domain.d/$app.conf "${backup_dir}/conf/nginx.conf"
+
+# Copy dedicated php-fpm process to backup folder
+sudo cp -a /etc/php5/fpm/pool.d/$app.conf "${backup_dir}/conf/php-fpm.conf"
+sudo cp -a /etc/php5/fpm/conf.d/20-$app.ini "${backup_dir}/conf/php-fpm.ini"
diff --git a/scripts/install b/scripts/install
index 06816b7..b4654de 100644
--- a/scripts/install
+++ b/scripts/install
@@ -1,46 +1,95 @@
#!/bin/bash
-# Retrieve arguments
-domain=$1
-path=$2
-admin_grav=$3
+# Exit on command errors and treat unset variables as an error
+set -eu
-# Check if admin exists
-sudo yunohost user list --json | grep -q "\"username\": \"$admin_grav\""
-if [[ ! $? -eq 0 ]]; then
- echo "Wrong admin"
- exit 1
-fi
-sudo yunohost app setting grav admin -v $admin_grav
+source .fonctions # Charge les fonctions génériques habituellement utilisées dans le script
-# Check domain/path availability
-sudo yunohost app checkurl $domain$path -a grav
-if [[ ! $? -eq 0 ]]; then
- exit 1
-fi
+CLEAN_SETUP () {
+# Nettoyage des résidus d'installation non pris en charge par le script remove.
+ # Clean hosts
+ sudo sed -i '/#GRAV/d' /etc/hosts
+}
+TRAP_ON # Active trap pour arrêter le script si une erreur est détectée.
-# Copy files to the right place
-final_path=/var/www/grav
-sudo mkdir -p $final_path
-sudo cp -aR ../src/* $final_path
+domain=$YNH_APP_ARG_DOMAIN
+path=$YNH_APP_ARG_PATH
+admin_grav=$YNH_APP_ARG_ADMIN
+language=$YNH_APP_ARG_LANGUAGE
+multisite=$YNH_APP_ARG_MULTISITE
+is_public=$YNH_APP_ARG_IS_PUBLIC
-# Set permissions to roundcube directory
+app=$YNH_APP_INSTANCE_NAME
+
+# Source app helpers
+source /usr/share/yunohost/helpers
+
+CHECK_VAR "$app" "app name not set"
+
+CHECK_USER "$admin_grav"
+
+CHECK_PATH
+
+CHECK_DOMAINPATH
+
+CHECK_FINALPATH
+
+ynh_app_setting_set $app domain $domain
+ynh_app_setting_set $app path $path
+ynh_app_setting_set $app admin $admin_grav
+ynh_app_setting_set $app is_public $is_public
+ynh_app_setting_set $app language $language
+ynh_app_setting_set $app multisite $multisite
+
+GENERATE_DB $app # Créer une base de données et un utilisateur dédié au nom de l'app.
+
+# Crée le repertoire de destination et stocke son emplacement.
+sudo mkdir "$final_path"
+ynh_app_setting_set $app final_path $final_path
+
+SETUP_SOURCE "grav-admin-v1.1.17.zip"
+
+# Set permissions to grav directory
sudo chown -R www-data: $final_path
-# Modify Nginx configuration file and copy it to Nginx conf directory
-sed -i "s@PATHTOCHANGE@$path@g" ../conf/nginx.conf
-sed -i "s@ALIASTOCHANGE@$final_path@g" ../conf/nginx.conf
-sudo cp ../conf/nginx.conf /etc/nginx/conf.d/$domain.d/grav.conf
+echo -e "127.0.0.1 $domain #GRAV" | sudo tee -a /etc/hosts
-sed -i "s@NAMETOCHANGE@grav@g" ../conf/php-fpm.conf
-finalphpconf=/etc/php5/fpm/pool.d/grav.conf
-sudo cp ../conf/php-fpm.conf $finalphpconf
-sudo chown root: $finalphpconf
-sudo chmod 644 $finalphpconf
-# sudo $final_path/bin/grav install
+# Et copie le fichier de config nginx
+sudo cp ../conf/nginx.conf /etc/nginx/conf.d/$domain.d/$app.conf
+
+# Modifie les variables dans le fichier de configuration nginx
+sudo sed -i "s@__PATHTOCHANGE__@$path@g" /etc/nginx/conf.d/$domain.d/$app.conf
+sudo sed -i "s@__FINALPATH__@$final_path@g" /etc/nginx/conf.d/$domain.d/$app.conf
+sudo sed -i "s@__NAMETOCHANGE__@$app@g" /etc/nginx/conf.d/$domain.d/$app.conf
+
+if [ "$multisite" = "Yes" ];
+then
+ sudo sed -i "s@#--MULTISITE--@@g" /etc/nginx/conf.d/$domain.d/$app.conf
+fi
+
+if [ "$is_public" = "Yes" ];
+then
+ sudo sed -i "s@#--PRIVATE--@@g" /etc/nginx/conf.d/$domain.d/$app.conf
+fi
+
+POOL_FPM
+
+# Donne un accès public pour curl
+ynh_app_setting_set $app unprotected_uris "/"
+
+# Régénère la configuration de SSOwat
+sudo yunohost app ssowatconf
# Reload Nginx and regenerate SSOwat conf
sudo service php5-fpm restart
sudo service nginx reload
-sudo yunohost app setting grav skipped_uris -v "/"
-sudo yunohost app ssowatconf
\ No newline at end of file
+
+if [ "$is_public" = "No" ];
+then
+ # Retire l'accès public
+ ynh_app_setting_delete $app unprotected_uris
+ sudo yunohost app ssowatconf
+fi
+
+# Nettoyer hosts
+sudo sed -i '/#GRAV/d' /etc/hosts
\ No newline at end of file
diff --git a/scripts/remove b/scripts/remove
index 77cd60d..51e35a6 100644
--- a/scripts/remove
+++ b/scripts/remove
@@ -1,10 +1,26 @@
#!/bin/bash
-domain=$(sudo yunohost app setting grav domain)
+# Exit on command errors and treat unset variables as an error
+set -u
-sudo rm -rf /var/www/grav
-sudo rm -f /etc/nginx/conf.d/$domain.d/grav.conf
-sudo rm -f /etc/php5/fpm/pool.d/grav.conf
+source .fonctions # Charge les fonctions génériques habituellement utilisées dans le script
-sudo service php5-fpm restart
-sudo service nginx reload
\ No newline at end of file
+# Source app helpers
+source /usr/share/yunohost/helpers
+
+# Récupère les infos de l'application.
+app=$YNH_APP_INSTANCE_NAME
+domain=$(ynh_app_setting_get $app domain)
+
+REMOVE_BDD $app # Suppression de la base de donnée et de l'utilisateur associé.
+
+SECURE_REMOVE '/var/www/$app' # Suppression du dossier de l'application
+
+REMOVE_NGINX_CONF # Suppression de la configuration nginx
+
+REMOVE_FPM_CONF # Suppression de la configuration du pool php-fpm
+
+# Régénère la configuration de SSOwat
+sudo yunohost app ssowatconf
+
+echo -e "\e[0m" # Restore normal color
\ No newline at end of file
diff --git a/scripts/restore b/scripts/restore
new file mode 100644
index 0000000..bb3d11b
--- /dev/null
+++ b/scripts/restore
@@ -0,0 +1,53 @@
+#!/bin/bash
+# This restore script is adapted to Yunohost >=2.4
+
+# Exit on command errors and treat unset variables as an error
+set -eu
+
+# The parameter $1 is the backup directory location dedicated to the app
+backup_dir=$1
+
+# The parameter $2 is the id of the app instance ex: ynhexample__2
+app=$2
+
+# Source app helpers
+source /usr/share/yunohost/helpers
+
+# Get old parameter of the app
+domain=$(ynh_app_setting_get $app domain)
+path=$(ynh_app_setting_get $app path)
+is_public=$(ynh_app_setting_get $app is_public)
+final_path=$(ynh_app_setting_get $app final_path)
+
+if [ -d $final_path ]; then
+ ynh_die "There is already a directory: $final_path"
+fi
+
+conf=/etc/nginx/conf.d/$domain.d/$app.conf
+if [ -f $conf ]; then
+ ynh_die "There is already a nginx conf file at this path: $conf"
+fi
+# Restore conf files
+sudo cp -a "${backup_dir}/conf/nginx.conf" $conf
+
+# Reload Nginx
+sudo service nginx reload
+
+sudo cp -a "${backup_dir}/var/www/$app" $final_path
+
+# Set permissions
+# Les fichiers appartiennent à www-data, pour permettre les mises à jour.
+sudo chown -R www-data: $final_path
+
+# Copy dedicated php-fpm process from backup folder to the right location
+sudo cp -a $backup_dir/conf/php-fpm.conf /etc/php5/fpm/pool.d/$app.conf
+sudo cp -a $backup_dir/conf/php-fpm.ini /etc/php5/fpm/conf.d/20-$app.ini
+# And restart service
+sudo service php5-fpm reload
+
+# Set ssowat config
+if [ "$is_public" = "No" ];
+then
+ ynh_app_setting_delete $app skipped_uris
+fi
+sudo yunohost app ssowatconf
diff --git a/scripts/upgrade b/scripts/upgrade
index 12534ed..8f33ef4 100644
--- a/scripts/upgrade
+++ b/scripts/upgrade
@@ -1,20 +1,38 @@
#!/bin/bash
-# Retrieve arguments
-domain=$(sudo yunohost app setting grav domain)
-path=$(sudo yunohost app setting grav path)
-admin_grav=$(sudo yunohost app setting grav admin)
-language=$(sudo yunohost app setting grav language)
-is_public=$(sudo yunohost app setting grav is_public)
+# Exit on command errors and treat unset variables as an error
+set -eu
-final_path=/var/www/grav
+source .fonctions # Charge les fonctions génériques habituellement utilisées dans le script
+
+# See comments in install script
+app=$YNH_APP_INSTANCE_NAME
+
+# Source YunoHost helpers
+source /usr/share/yunohost/helpers
+
+# Retrieve app settings
+domain=$(ynh_app_setting_get "$app" domain)
+path=$(ynh_app_setting_get "$app" path)
+admin=$(ynh_app_setting_get "$app" admin)
+is_public=$(ynh_app_setting_get "$app" is_public)
+language=$(ynh_app_setting_get "$app" language)
+
+CHECK_PATH # Vérifie et corrige la syntaxe du path.
# Check if admin is not null
-if [[ "$admin_grav" = "" || "$is_public" = "" || "$language" = "" ]]; then
+if [[ "$admin" = "" || "$is_public" = "" || "$language" = "" ]]; then
echo "Unable to upgrade, please contact support"
- exit 1
+ ynh_die
fi
+root_pwd=$(sudo cat /etc/yunohost/mysql)
+
+final_path=/var/www/$app
+
+db_name=$app
+
+# CHECK_MD5_CONFIG "connect.php" "$final_path/config/connect.php" # Créé un backup du fichier de config si il a été modifié.
# Modify Nginx configuration file and copy it to Nginx conf directory
sed -i "s@PATHTOCHANGE@$path@g" ../conf/nginx.conf*
@@ -22,9 +40,18 @@ sed -i "s@ALIASTOCHANGE@$final_path/@g" ../conf/nginx.conf*
if [ $is_public = "Yes" ];
then
- sudo cp ../conf/nginx.conf-public /etc/nginx/conf.d/$domain.d/grav.conf
+ sudo cp ../conf/nginx.conf-public /etc/nginx/conf.d/$domain.d/$app.conf
else
- sudo cp ../conf/nginx.conf /etc/nginx/conf.d/$domain.d/grav.conf
+ sudo cp ../conf/nginx.conf /etc/nginx/conf.d/$domain.d/$app.conf
+fi
+
+# If app is public, add url to SSOWat conf as skipped_uris
+if [[ $is_public -eq 1 ]]; then
+ # See install script
+ ynh_app_setting_set "$app" unprotected_uris "/"
+ sudo cp ../conf/nginx.conf-public /etc/nginx/conf.d/$domain.d/$app.conf
+else
+ sudo cp ../conf/nginx.conf /etc/nginx/conf.d/$domain.d/$app.conf
fi
# Reload Nginx
diff --git a/sources/source_dir b/sources/source_dir
new file mode 100644
index 0000000..d4e0cb1
--- /dev/null
+++ b/sources/source_dir
@@ -0,0 +1 @@
+grav
\ No newline at end of file
diff --git a/sources/source_md5. b/sources/source_md5.
new file mode 100644
index 0000000..02defc2
--- /dev/null
+++ b/sources/source_md5.
@@ -0,0 +1 @@
+5593142893cfb1c8bc90a407ede00c09 grav-admin-v1.1.17.zip
\ No newline at end of file
diff --git a/sources/source_url b/sources/source_url
new file mode 100644
index 0000000..78e6805
--- /dev/null
+++ b/sources/source_url
@@ -0,0 +1 @@
+https://getgrav.org/download/core/grav-admin/1.1.17
\ No newline at end of file
diff --git a/src/.config b/src/.config
deleted file mode 100644
index 6a27223..0000000
--- a/src/.config
+++ /dev/null
@@ -1,233 +0,0 @@
-SITE_NAME
- * get::$config->SITE_DOMAIN
- */
- const SITE_NAME = 'YourSite';
- const SITE_DOMAIN = 'YourSite.com';
-
- /**
- * Database name - create new constants for additional connections (commented out example for DB_SLAVE_NAME follows)
- * Defining DB-name constants is a good practice but not required if you hard-code them in dbConnect() below
- */
- const DB_NAME = 'vork';
- //const DB_SLAVE_NAME = 'slave4readonly';
-
- /**
- * Most RDBMS users will only need to adjust the connection string in the first $db object. The syntax of this must
- * always match the syntax of the constructor or connect method of your relational-database PHP extension.
- *
- * For the MySQLi extension all arguments are optional and formatted as:
- * self::$db = new $db($host, $username, $passwd, $dbname, $port, $socket);
- *
- * Note: in most setups $host is either "localhost" or set to an IP address
- * for Amazon RDS it would be something like: myinstance.crwjauxgijdf.us-east-1.rds.amazonaws.com
- *
- * For the syntax of other extensions refer to: http://www.php.net/manual/en/refs.database.vendors.php
- *
- * @param string $modelObject One of the values in self::$modelObjects determining which DB connection to establish
- */
- public function dbConnect($modelObject) {
- $db = (!DEBUG_MODE ? 'db' : 'dbDebug');
- switch ($modelObject) { //a case must exist for each value in self::$modelObjects (additional cases are benign)
- case 'db':
- self::$db = new $db('HOSTNAME', 'USERNAME', 'PASSWORD', self::DB_NAME);
- break;
- case 'mongo':
- if (!class_exists('vorkMongo')) {
- require self::basepath() . 'sql' . self::DS . 'mongodb';
- }
- $m = new vorkMongo();
- self::$mongo = $m->selectDB(self::DB_NAME);
- //Upsert arg is array in newer MongoDB (leave as-is), Boolean in older- remove comments around (Boolean)
- $this->mongoUpsert = /* (Boolean) */ array('upsert' => true);
- break;
- case 'dbro':
- //if an additional connection is needed, adjust credentials below and follow the instructions in the
- //comment for $modelObjects just after this class.
- self::$dbro = new $db('HOSTNAME', 'USERNAME', 'PASSWORD', self::DB_SLAVE_NAME);
- break;
- }
- }
-
- /**
- * Using multiple database connections and/or NoSQL like MongoDB or CouchDB
- *
- * If you are only using one DB connection and it is an RDBMS (any databaes except non-relational like Mongo)
- * then you should skip this step.
- *
- * Each database connection (both RDBMS & NoSQL) needs to be defined in the $modelObjects array and have a static
- * propery existing by the same name. "db" exists by default so to add a second read-only connection you set
- * $modelObjects to array('db', 'dbro') and create a new $dbro static property (commented-out examples follow).
- *
- * Use the same process for adding a MongoDB connection in conjuction with an RDBMS (substituting in the last
- * example "mongo" for "dbro"). To use MongoDB as the sole database just overwrite $modelObjects with
- * array('mongo') - this is instead of keeping the default 'db' connection within the array. You will also want to
- * comment out the last line in this file which is RDBMS-specific: require '.config-rdbms';
- *
- * Important: each connection defined here must establish the connection within the dbConnect() method above, an
- * example for both mongo and dbro exists, for other connections just provide a unique name and access from within
- * your models by name: $this->mydbname->query(...);
- *
- * Caution: do NOT uncomment more than one of the following examples; it will trigger a PHP fatal error if you do!
- */
- //Adds MongoDB support in conjunction with other databases
- //public static $modelObjects = array('db', 'mongo'); public static $mongo;
-
- //Uses MongoDB as the exclusive datasource
- //public static $modelObjects = array('mongo'); public static $mongo;
-
- //Adds an additional database connection called "dbro"
- //public static $modelObjects = array('db', 'dbro'); public static $dbro;
-
- /**
- * If true all self::$modelObjects database connections are made upon loading the first model
- * If false your connections are lazy-loaded when needed but each of your models must extend the model abstract
- * eg.: class wikiModel extends model {...}
- */
- const MODEL_AUTOCONNECT = true;
-
- /**
- * Enables the caching functions by initializing get::$cache with a cache object (Memcache is default, but
- * can be any object-oriented cache mechanism.)
- */
- public function cache() {
- /* // uncomment this section to enable Memcache caching (Memcache must be installed and enabled in PHP)
- if (!class_exists('memcache')) {
- return false;
- }
- get::$cache = new Memcache;
- //get::$cache->addServer('HOSTNAME', 'PORT')
- //Following is the typical setting for a single-server configuration:
- get::$cache->addServer('localhost', 11211);
- */
- }
-
- /**
- * Enables special AJAX handling - eg.: AJAX requests will skip the layout file and just return the view contents
- *
- * Can be set globally here and then overridden form within any controller-action or component
- *
- * Valid values:
- * (Boolean) true or false will enable or disable AJAX in all controllers
- * array('controlerName1' => true,
- * 'controlerName2' => 'actionName',
- * 'controlerName3' => array('action1', 'action2'))
- *
- * @var mixed Boolean or an array with controller-name keys & val either true, an action name or an array of actions
- */
- public $ajaxEnabled = true;
-
- /**
- * Execute a file that is global to the application before the page loads
- * File must be in the root of the mvc directory
- */
- const APP_CONSTRUCT = null;
-
- /**
- * Execute a file that is global to the application after the page loads
- * File must be in the root of the mvc directory
- */
- const APP_DESTRUCT = null;
-
- /**
- * Enter your ShareThis publisher code to enable the shareThis tools helper
- */
- //const SHARE_THIS = 'd123456789-1234-1234-1234-a1e123456f';
-
-
- /**
- * Enter your AddThis publisher code to enable the addThis tools helper
- */
- //const ADD_THIS = 'xa-1234567890123e';
-
- /**
- * Enter your Google AdSense client ID to enable use of the adSense tools helper
- */
- //const GOOGLE_AD_CLIENT = '';
-
- /**
- * Enter your Google Checkout credentials to enable use of the helper
- */
- /*
- public $GOOGLE_CHECKOUT = array('useSandbox' => false,
- 'live' => array('id' => 'YOURID', 'key' => 'YOURKEY'),
- 'sandbox' => array('id' => 'YOURID', 'key' => 'YOURKEY'));
- */
-
- /**
- * Enter your AuthorizeNet credentials to enable use of the chargeAuthNet method of the cc component
- */
- /*
- const AUTHNET_LOGIN = '';
- const AUTHNET_PASSWORD = '';
- */
-
- /**
- * Meetup API key - enables usage of the Meetup tools-helper
- */
- //const MEETUP_API_KEY = '47e794a9c4766374c761a57833a77';
-
- /**
- * Enter your UPS account credentials and XML Access Key (refer to ups.com for signup) to enable use of
- * the UPS functions in the shipping component
- *
- * @var array
- */
- //public $UPS = array('xmlAccessKey' => 'YOURKEY000000000', 'userid' => 'YOURID', 'password' => 'YOURPASS');
-
- /**
- * Enter your Amazon Web Services credentials to enable use of the amazon component
- */
- /*
- public $AMAZON = array('id' => '0000-0000-1234', 'accessKey' => 'AAAABBBBX12345CCDDDD',
- 'secretKey' => 'aA01234560bB01234560cC01234560dD');
- */
-
- /**
- * Enter your PayPal email to enable use of the PayPal component
- */
- //const PAYPAL_EMAIL = 'you@yourdomain.com';
-
- /**
- * Convenience function to determine if a user is a "superuser" (someone who gets complete access to
- * all information) and by default only used in the errorhandler view (to determine verbosity) but typical applications
- * find many uses for this
- *
- * Note, if your application uses this method to grant access to private resources then you are highly-recommended
- * to use a stronger authentication method than just checking the IP address (IPs can easily be spoofed.)
- *
- * @return boolean
- */
- public function isSuperuser() {
- return (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] == '127.0.0.1'); // <--change this before use
- }
-
- /**
- * Set any application-specific constants or properties after this comment.
- * examples:
- * const MY_CONSTANT = 'Hello, Shalom and Bonjour';
- * public $myProperty = array(1, 2, 3);
- *
- * Access them from any MVC element via:
- * get::$config->MY_CONSTANT
- * get::$config->myProperty
- */
- //const EXAMPLE_CONSTANT = 'your data...';
-}
-
-/**
- * If you are using a relational-database other than MySQL or Amazon RDS (eg. SQLite, Oracle, etc.) then you need to
- * set your RDBMS-type in the .config-rdbms file. If you are NOT using a relational-database then comment out the
- * next line. Note: MongoDB and other NoSQL databases are NOT relational and do not require the .config-rdbms file
- */
-require '.config-rdbms';
\ No newline at end of file
diff --git a/src/.debug b/src/.debug
deleted file mode 100644
index 52fa0a0..0000000
--- a/src/.debug
+++ /dev/null
@@ -1,221 +0,0 @@
- 1) {
- $return = (end(self::$timer[$id]) - reset(self::$timer[$id]));
- }
- return number_format($return, 5);
- }
-
- /**
- * Reports the total time table for a timer via the debug output mode
- *
- * @param mixed $id Optional, any vector type is valid
- * @return string Nicely formatted float
- */
- public static function timerReport($id = 'default') {
- if (!isset(self::$timer[$id])) {
- return null;
- }
- $last = reset(self::$timer[$id]);
- if (self::$_modeStatic == 'FirePHP') {
- $FirePHP = FirePHP::getInstance(true);
- foreach (self::$timer[$id] as $breakpointId => $val) {
- $FirePHP->info((string) $breakpointId, number_format(($val - $last), 5));
- $last = $val;
- }
- } else {
- foreach (self::$timer[$id] as $breakpointId => $val) {
- $return[] = number_format(($val - $last), 5) . ' - ' . $breakpointId;
- $last = $val;
- }
- if (self::$_modeStatic == 'html' || self::$_modeStatic == 'text') {
- $recordDelimiter = PHP_EOL . PHP_EOL;
- if (self::$_modeStatic == 'html') {
- $recordDelimiter .= '';
- }
- echo $recordDelimiter . implode($recordDelimiter, $return) . $recordDelimiter;
- }
- return $return;
- }
- }
-
- /**
- * Logs a SQL query
- *
- * @param string $query
- * @param float $executionTime Optional
- * @param string $error Optional
- */
- public static function logQuery($query, $executionTime = null, $error = null) {
- self::$_queries[] = array('query' => $query, 'executionTime' => $executionTime, 'error' => $error);
- }
-
- /**
- * Logs a message
- *
- * @param str $data
- * @param str $type Valid options are log, info, warn and error
- */
- public static function log($data, $type = 'log') {
- self::$_log[] = array('data' => $data, 'method' => $type, 'time' => self::microtime());
- }
-
- /**
- * Initializes the debug system
- *
- * @param string $mode Optional. Mode of output by default is html, but the framework automatically overrides
- * this with your DEBUG_OUTPUT_METHOD setting
- */
- public function __construct($mode = 'html') {
- if ($mode == 'auto') {
- $mode = (strpos($_SERVER['HTTP_USER_AGENT'], 'FirePHP') !== false ? 'FirePHP' : 'html');
- }
- if ($mode == 'FirePHP' && !class_exists('FirePHP')) {
- $configInit = new configInit;
- $firephpDir = $configInit->packagesPath() . 'FirePHPCore' . $configInit->DS;
- if (is_dir($firephpDir)) {
- require_once $firephpDir . 'FirePHP.class.php';
- }
- if (!class_exists('FirePHP')) {
- $mode = 'html';
- }
- }
- if ($mode == 'FirePHP' && ini_get('output_buffering') != 'On') {
- ob_start();
- }
- self::$_modeStatic = $this->_mode = $mode;
- $this->_timeStart = self::microtime();
- }
-
- /**
- * Tallies up the debug info and outputs it
- */
- public function __destruct() {
- $execTime = 'Page execution time: ' . number_format(self::microtime() - $this->_timeStart, 5);
- $sqlExecString = 'Execution time of previous SQL: ';
- if ($this->_mode == 'FirePHP') {
- $FirePHP = FirePHP::getInstance(true);
- $FirePHP->info($execTime);
- if (!empty(self::$_log)) {
- $timeLast = $this->_timeStart;
- foreach (self::$_log as $logArray) {
- $data = '(' . number_format($logArray['time'] - $timeLast, 5) . ') ' . $logArray['data'];
- $FirePHP->{$logArray['method']}($data);
- $timeLast = $logArray['time'];
- }
- }
- if (!empty(self::$_queries)) {
- foreach (self::$_queries as $queryArray) {
- $FirePHP->group('SQL');
- $FirePHP->log($queryArray['query']);
- if ($queryArray['executionTime'] !== null) {
- $FirePHP->info($sqlExecString . $queryArray['executionTime']);
- }
- if ($queryArray['error'] !== null) {
- $FirePHP->error($queryArray['error']);
- }
- $FirePHP->groupEnd();
- }
- }
- } else {
- $recordDelimiter = PHP_EOL . PHP_EOL;
- $lineDelimiter = PHP_EOL;
- if ($this->_mode == 'html') {
- echo ' ';
- $recordDelimiter .= '';
- $lineDelimiter .= ' ';
- }
- echo $recordDelimiter . $execTime;
- if (!empty(self::$_log)) {
- foreach (self::$_log as $logArray) {
- echo $lineDelimiter . $logArray['method'] . ': ' . get::htmlentities($logArray['data']);
- }
- }
- if (!empty(self::$_queries)) {
- foreach (self::$_queries as $queryArray) {
- echo $recordDelimiter . ($this->_mode == 'html' ? get::htmlentities($queryArray['query'])
- : $queryArray['query']);
- if ($queryArray['executionTime'] !== null) {
- echo $lineDelimiter . $sqlExecString . $queryArray['executionTime'];
- }
- if ($queryArray['error'] !== null) {
- echo $lineDelimiter . $queryArray['error'];
- }
- }
- }
- }
- }
-}
-$debugObject = new debug(DEBUG_OUTPUT_METHOD);
\ No newline at end of file
diff --git a/src/.dependencies b/src/.dependencies
deleted file mode 100644
index 3e82e06..0000000
--- a/src/.dependencies
+++ /dev/null
@@ -1,26 +0,0 @@
-git:
- problems:
- url: https://github.com/getgrav/grav-plugin-problems
- path: user/plugins/problems
- branch: master
- error:
- url: https://github.com/getgrav/grav-plugin-error
- path: user/plugins/error
- branch: master
- antimatter:
- url: https://github.com/getgrav/grav-theme-antimatter
- path: user/themes/antimatter
- branch: master
-links:
- problems:
- src: grav-plugin-problems
- path: user/plugins/problems
- scm: github
- error:
- src: grav-plugin-error
- path: user/plugins/error
- scm: github
- antimatter:
- src: grav-theme-antimatter
- path: user/themes/antimatter
- scm: github
diff --git a/src/.hg_archival.txt b/src/.hg_archival.txt
deleted file mode 100644
index 268fb1e..0000000
--- a/src/.hg_archival.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-repo: 4bb20edbf41fe2cf5294bfad1428e943f7d3fe65
-node: 01251bf0ea8aeaec434f4226bee735eaf1bc14ba
-branch: default
-latesttag: null
-latesttagdistance: 25
diff --git a/src/.hgignore b/src/.hgignore
deleted file mode 100644
index e43b0f9..0000000
--- a/src/.hgignore
+++ /dev/null
@@ -1 +0,0 @@
-.DS_Store
diff --git a/src/.htaccess b/src/.htaccess
deleted file mode 100644
index db50159..0000000
--- a/src/.htaccess
+++ /dev/null
@@ -1,63 +0,0 @@
-
-
-RewriteEngine On
-
-## Begin RewriteBase
-# If you are getting 404 errors on subpages, you may have to uncomment the RewriteBase entry
-# You should change the '/' to your appropriate subfolder. For example if you have
-# your Grav install at the root of your site '/' should work, else it might be something
-# along the lines of: RewriteBase /
-##
-
-# RewriteBase /
-
-## End - RewriteBase
-
-## Begin - Exploits
-# If you experience problems on your site block out the operations listed below
-# This attempts to block the most common type of exploit `attempts` to Grav
-#
-# Block out any script trying to base64_encode data within the URL.
-RewriteCond %{QUERY_STRING} base64_encode[^(]*\([^)]*\) [OR]
-# Block out any script that includes a ' . "\n";
- }
- foreach ($this->js_no_pipeline as $file) {
- if ($group && $file['group'] == $group) {
- $output .= '' . "\n";
- }
- }
- } else {
- foreach ($this->js as $file) {
- if ($group && $file['group'] == $group) {
- $output .= '' . "\n";
- }
- }
- }
-
- // Render Inline JS
- foreach ($this->inline_js as $inline) {
- if ($group && $inline['group'] == $group) {
- $inline_js .= $inline['asset'] . "\n";
- }
- }
-
- if ($inline_js) {
- $output .= "\n\n";
- }
-
- return $output;
- }
-
- /**
- * Minify and concatenate CSS.
- *
- * @return string
- */
- protected function pipelineCss($group = 'head')
- {
- /** @var Cache $cache */
- $cache = self::getGrav()['cache'];
- $key = '?' . $cache->getKey();
-
- // temporary list of assets to pipeline
- $temp_css = [];
-
- // clear no-pipeline assets lists
- $this->css_no_pipeline = [];
-
- $file = md5(json_encode($this->css) . $this->css_minify . $this->css_rewrite . $group) . '.css';
-
- $relative_path = "{$this->base_url}{$this->assets_url}/{$file}";
- $absolute_path = $this->assets_dir . $file;
-
- // If pipeline exist return it
- if (file_exists($absolute_path)) {
- return $relative_path . $key;
- }
-
- // Remove any non-pipeline files
- foreach ($this->css as $id => $asset) {
- if ($asset['group'] == $group) {
- if (!$asset['pipeline']) {
- $this->css_no_pipeline[$id] = $asset;
- } else {
- $temp_css[$id] = $asset;
- }
- }
- }
-
- //if nothing found get out of here!
- if (count($temp_css) == 0) {
- return false;
- }
-
- $css_minify = $this->css_minify;
-
- // If this is a Windows server, and minify_windows is false (default value) skip the
- // minification process because it will cause Apache to die/crash due to insufficient
- // ThreadStackSize in httpd.conf - See: https://bugs.php.net/bug.php?id=47689
- if (strtoupper(substr(php_uname('s'), 0, 3)) === 'WIN' && !$this->css_minify_windows) {
- $css_minify = false;
- }
-
- // Concatenate files
- $buffer = $this->gatherLinks($temp_css, CSS_ASSET);
- if ($css_minify) {
- $min = new \CSSmin();
- $buffer = $min->run($buffer);
- }
-
- // Write file
- if (strlen(trim($buffer)) > 0) {
- file_put_contents($absolute_path, $buffer);
- return $relative_path . $key;
- } else {
- return false;
- }
- }
-
- /**
- * Minify and concatenate JS files.
- *
- * @return string
- */
- protected function pipelineJs($group = 'head')
- {
- /** @var Cache $cache */
- $cache = self::getGrav()['cache'];
- $key = '?' . $cache->getKey();
-
- // temporary list of assets to pipeline
- $temp_js = [];
-
- // clear no-pipeline assets lists
- $this->js_no_pipeline = [];
-
- $file = md5(json_encode($this->js) . $this->js_minify . $group) . '.js';
-
- $relative_path = "{$this->base_url}{$this->assets_url}/{$file}";
- $absolute_path = $this->assets_dir . $file;
-
- // If pipeline exist return it
- if (file_exists($absolute_path)) {
- return $relative_path . $key;
- }
-
- // Remove any non-pipeline files
- foreach ($this->js as $id => $asset) {
- if ($asset['group'] == $group) {
- if (!$asset['pipeline']) {
- $this->js_no_pipeline[] = $asset;
- } else {
- $temp_js[$id] = $asset;
- }
- }
- }
-
- //if nothing found get out of here!
- if (count($temp_js) == 0) {
- return false;
- }
-
- // Concatenate files
- $buffer = $this->gatherLinks($temp_js, JS_ASSET);
- if ($this->js_minify) {
- $buffer = \JSMin::minify($buffer);
- }
-
- // Write file
- if (strlen(trim($buffer)) > 0) {
- file_put_contents($absolute_path, $buffer);
- return $relative_path . $key;
- } else {
- return false;
- }
- }
-
- /**
- * Return the array of all the registered CSS assets
- *
- * @return array
- */
- public function getCss()
- {
- return $this->css;
- }
-
- /**
- * Return the array of all the registered JS assets
- *
- * @return array
- */
- public function getJs()
- {
- return $this->js;
- }
-
- /**
- * Return the array of all the registered collections
- *
- * @return array
- */
- public function getCollections()
- {
- return $this->collections;
- }
-
- /**
- * Determines if an asset exists as a collection, CSS or JS reference
- *
- * @param $asset
- *
- * @return bool
- */
- public function exists($asset)
- {
- if (isset($this->collections[$asset]) ||
- isset($this->css[$asset]) ||
- isset($this->js[$asset])) {
- return true;
- } else {
- return false;
- }
- }
-
- /**
- * Add/replace collection.
- *
- * @param string $collectionName
- * @param array $assets
- * @param bool $overwrite
- *
- * @return $this
- */
- public function registerCollection($collectionName, Array $assets, $overwrite = false)
- {
- if ($overwrite || !isset($this->collections[$collectionName])) {
- $this->collections[$collectionName] = $assets;
- }
-
- return $this;
- }
-
- /**
- * Reset all assets.
- *
- * @return $this
- */
- public function reset()
- {
- return $this->resetCss()->resetJs();
- }
-
- /**
- * Reset JavaScript assets.
- *
- * @return $this
- */
- public function resetJs()
- {
- $this->js = array();
-
- return $this;
- }
-
- /**
- * Reset CSS assets.
- *
- * @return $this
- */
- public function resetCss()
- {
- $this->css = array();
-
- return $this;
- }
-
- /**
- * Add all CSS assets within $directory (relative to public dir).
- *
- * @param string $directory Relative to $this->public_dir
- *
- * @return $this
- */
- public function addDirCss($directory)
- {
- return $this->addDir($directory, self::CSS_REGEX);
- }
-
- /**
- * Add all assets matching $pattern within $directory.
- *
- * @param string $directory Relative to $this->public_dir
- * @param string $pattern (regex)
- *
- * @return $this
- * @throws Exception
- */
- public function addDir($directory, $pattern = self::DEFAULT_REGEX)
- {
- // Check if public_dir exists
- if (!is_dir($this->assets_dir)) {
- throw new Exception('Assets: Public dir not found');
- }
-
- // Get files
- $files = $this->rglob($this->assets_dir . DIRECTORY_SEPARATOR . $directory, $pattern, $this->assets_dir);
-
- // No luck? Nothing to do
- if (!$files) {
- return $this;
- }
-
- // Add CSS files
- if ($pattern === self::CSS_REGEX) {
- $this->css = array_unique(array_merge($this->css, $files));
- return $this;
- }
-
- // Add JavaScript files
- if ($pattern === self::JS_REGEX) {
- $this->js = array_unique(array_merge($this->js, $files));
- return $this;
- }
-
- // Unknown pattern. We must poll to know the extension :(
- foreach ($files as $asset) {
- $info = pathinfo($asset);
- if (isset($info['extension'])) {
- $ext = strtolower($info['extension']);
- if ($ext === 'css' && !in_array($asset, $this->css)) {
- $this->css[] = $asset;
- } elseif ($ext === 'js' && !in_array($asset, $this->js)) {
- $this->js[] = $asset;
- }
- }
- }
-
- return $this;
- }
-
- /**
- * Determine whether a link is local or remote.
- *
- * Understands both "http://" and "https://" as well as protocol agnostic links "//"
- *
- * @param string $link
- *
- * @return bool
- */
- protected function isRemoteLink($link)
- {
- return ('http://' === substr($link, 0, 7) || 'https://' === substr($link, 0, 8)
- || '//' === substr($link, 0, 2));
- }
-
- /**
- * Build local links including grav asset shortcodes
- *
- * @param string $asset the asset string reference
- *
- * @return string the final link url to the asset
- */
- protected function buildLocalLink($asset)
- {
- try {
- $asset = self::getGrav()['locator']->findResource($asset, false);
- } catch (\Exception $e) {
- }
-
- return $asset ? $this->base_url . ltrim($asset, '/') : false;
- }
-
- /**
- * Build an HTML attribute string from an array.
- *
- * @param array $attributes
- *
- * @return string
- */
- protected function attributes(array $attributes)
- {
- $html = '';
-
- foreach ($attributes as $key => $value) {
- // For numeric keys we will assume that the key and the value are the same
- // as this will convert HTML attributes such as "required" to a correct
- // form like required="required" instead of using incorrect numerics.
- if (is_numeric($key)) {
- $key = $value;
- }
- if (is_array($value)) {
- $value = implode(' ', $value);
- }
-
- $element = $key . '="' . htmlentities($value, ENT_QUOTES, 'UTF-8', false) . '"';
- $html .= ' ' . $element;
- }
-
- return $html;
- }
-
- /**
- * Download and concatenate the content of several links.
- *
- * @param array $links
- * @param bool $css
- *
- * @return string
- */
- protected function gatherLinks(array $links, $css = true)
- {
-
-
- $buffer = '';
- $local = true;
-
- foreach ($links as $asset) {
- $link = $asset['asset'];
- $relative_path = $link;
-
- if ($this->isRemoteLink($link)) {
- $local = false;
- if ('//' === substr($link, 0, 2)) {
- $link = 'http:' . $link;
- }
- } else {
- // Fix to remove relative dir if grav is in one
- if (($this->base_url != '/') && (strpos($this->base_url, $link) == 0)) {
- $base_url = '#' . preg_quote($this->base_url, '#') . '#';
- $relative_path = ltrim(preg_replace($base_url, '/', $link, 1), '/');
- }
-
- $relative_dir = dirname($relative_path);
- $link = ROOT_DIR . $relative_path;
- }
-
- $file = ($this->fetch_command instanceof Closure) ? @$this->fetch_command->__invoke($link) : @file_get_contents($link);
-
- // No file found, skip it...
- if ($file === false) {
- continue;
- }
-
- // Double check last character being
- if (!$css) {
- $file = rtrim($file, ' ;') . ';';
- }
-
- // If this is CSS + the file is local + rewrite enabled
- if ($css && $local && $this->css_rewrite) {
- $file = $this->cssRewrite($file, $relative_dir);
- }
-
- $buffer .= $file;
- }
-
- // Pull out @imports and move to top
- if ($css) {
- $buffer = $this->moveImports($buffer);
- }
-
- return $buffer;
- }
-
- /**
- * Finds relative CSS urls() and rewrites the URL with an absolute one
- *
- * @param $file the css source file
- * @param $relative_path relative path to the css file
- *
- * @return mixed
- */
- protected function cssRewrite($file, $relative_path)
- {
- // Strip any sourcemap comments
- $file = preg_replace(self::CSS_SOURCEMAP_REGEX, '', $file);
-
- // Find any css url() elements, grab the URLs and calculate an absolute path
- // Then replace the old url with the new one
- $file = preg_replace_callback(
- self::CSS_URL_REGEX,
- function ($matches) use ($relative_path) {
-
- $old_url = $matches[1];
-
- // ensure this is not a data url
- if (strpos($old_url, 'data:') === 0) {
- return $matches[0];
- }
-
- $new_url = $this->base_url . ltrim(Utils::normalizePath($relative_path . '/' . $old_url), '/');
-
- return str_replace($old_url, $new_url, $matches[0]);
- },
- $file
- );
-
- return $file;
- }
-
- /**
- * Moves @import statements to the top of the file per the CSS specification
- *
- * @param string $file the file containing the combined CSS files
- *
- * @return string the modified file with any @imports at the top of the file
- */
- protected function moveImports($file)
- {
- $this->imports = array();
-
- $file = preg_replace_callback(
- self::CSS_IMPORT_REGEX,
- function ($matches) {
- $this->imports[] = $matches[0];
- return '';
- },
- $file
- );
-
- return implode("\n", $this->imports) . "\n\n" . $file;
- }
-
- /**
- * Recursively get files matching $pattern within $directory.
- *
- * @param string $directory
- * @param string $pattern (regex)
- * @param string $ltrim Will be trimmed from the left of the file path
- *
- * @return array
- */
- protected function rglob($directory, $pattern, $ltrim = null)
- {
- $iterator = new RegexIterator(
- new RecursiveIteratorIterator(
- new RecursiveDirectoryIterator(
- $directory,
- FilesystemIterator::SKIP_DOTS
- )
- ),
- $pattern
- );
- $offset = strlen($ltrim);
- $files = array();
-
- foreach ($iterator as $file) {
- $files[] = substr($file->getPathname(), $offset);
- }
-
- return $files;
- }
-
- /**
- * Add all JavaScript assets within $directory.
- *
- * @param string $directory Relative to $this->public_dir
- *
- * @return $this
- */
- public function addDirJs($directory)
- {
- return $this->addDir($directory, self::JS_REGEX);
- }
-
- public function __toString()
- {
- return '';
- }
-
- /**
- * @param $a
- * @param $b
- *
- * @return mixed
- */
- protected function priorityCompare($a, $b)
- {
- return $a ['priority'] - $b ['priority'];
- }
-
-}
diff --git a/src/system/src/Grav/Common/Backup/ZipBackup.php b/src/system/src/Grav/Common/Backup/ZipBackup.php
deleted file mode 100644
index c73358e..0000000
--- a/src/system/src/Grav/Common/Backup/ZipBackup.php
+++ /dev/null
@@ -1,130 +0,0 @@
-findResource('backup://', true);
-
- if (!$destination)
- throw new \RuntimeException('The backup folder is missing.');
-
- Folder::mkdir($destination);
- }
-
- $name = self::getGrav()['config']->get('site.title', basename(GRAV_ROOT));
-
- $inflector = new Inflector();
-
- if (is_dir($destination)) {
- $date = date('YmdHis', time());
- $filename = trim($inflector->hyphenize($name), '-') . '-' . $date . '.zip';
- $destination = rtrim($destination, DS) . DS . $filename;
- }
-
- $messager && $messager([
- 'type' => 'message',
- 'level' => 'info',
- 'message' => 'Creating new Backup "' . $destination . '"'
- ]);
- $messager && $messager([
- 'type' => 'message',
- 'level' => 'info',
- 'message' => ''
- ]);
-
- $zip = new \ZipArchive();
- $zip->open($destination, \ZipArchive::CREATE);
-
- static::folderToZip(GRAV_ROOT, $zip, strlen(rtrim(GRAV_ROOT, DS) . DS), $messager);
-
- $messager && $messager([
- 'type' => 'progress',
- 'percentage' => false,
- 'complete' => true
- ]);
-
- $messager && $messager([
- 'type' => 'message',
- 'level' => 'info',
- 'message' => ''
- ]);
- $messager && $messager([
- 'type' => 'message',
- 'level' => 'info',
- 'message' => 'Saving and compressing archive...'
- ]);
-
- $zip->close();
-
- return $destination;
- }
-
- /**
- * @param $folder
- * @param $zipFile
- * @param $exclusiveLength
- * @param $messager
- */
- private static function folderToZip($folder, \ZipArchive &$zipFile, $exclusiveLength, callable $messager = null)
- {
- $handle = opendir($folder);
- while (false !== $f = readdir($handle)) {
- if ($f != '.' && $f != '..') {
- $filePath = "$folder/$f";
- // Remove prefix from file path before add to zip.
- $localPath = substr($filePath, $exclusiveLength);
-
- if (in_array($f, static::$ignoreFolders)) {
- continue;
- } elseif (in_array($localPath, static::$ignorePaths)) {
- $zipFile->addEmptyDir($f);
- continue;
- }
-
- if (is_file($filePath)) {
- $zipFile->addFile($filePath, $localPath);
-
- $messager && $messager([
- 'type' => 'progress',
- 'percentage' => false,
- 'complete' => false
- ]);
- } elseif (is_dir($filePath)) {
- // Add sub-directory.
- $zipFile->addEmptyDir($localPath);
- static::folderToZip($filePath, $zipFile, $exclusiveLength, $messager);
- }
- }
- }
- closedir($handle);
- }
-}
diff --git a/src/system/src/Grav/Common/Browser.php b/src/system/src/Grav/Common/Browser.php
deleted file mode 100644
index 4feea46..0000000
--- a/src/system/src/Grav/Common/Browser.php
+++ /dev/null
@@ -1,58 +0,0 @@
-useragent = parse_user_agent();
- } catch (\InvalidArgumentException $e) {
- $this->useragent = parse_user_agent("Mozilla/5.0 (compatible; Unknown;)");
- }
- }
-
- public function getBrowser()
- {
- return strtolower($this->useragent['browser']);
- }
-
- public function getPlatform()
- {
- return strtolower($this->useragent['platform']);
- }
-
- public function getLongVersion()
- {
- return $this->useragent['version'];
- }
-
- public function getVersion()
- {
- $version = explode('.', $this->getLongVersion());
- return intval($version[0]);
- }
-
- /**
- * Determine if the request comes from a human, or from a bot/crawler
- */
- public function isHuman()
- {
- $browser = $this->getBrowser();
- if (empty($browser)) {
- return false;
- }
-
- if (preg_match('~(bot|crawl)~i', $browser)) {
- return false;
- }
-
- return true;
- }
-}
diff --git a/src/system/src/Grav/Common/Cache.php b/src/system/src/Grav/Common/Cache.php
deleted file mode 100644
index 0445c50..0000000
--- a/src/system/src/Grav/Common/Cache.php
+++ /dev/null
@@ -1,314 +0,0 @@
-init($grav);
- }
-
- /**
- * Initialization that sets a base key and the driver based on configuration settings
- *
- * @param Grav $grav
- * @return void
- */
- public function init(Grav $grav)
- {
- /** @var Config $config */
- $this->config = $grav['config'];
- $this->now = time();
-
- $this->cache_dir = $grav['locator']->findResource('cache://doctrine', true, true);
-
- /** @var Uri $uri */
- $uri = $grav['uri'];
-
- $prefix = $this->config->get('system.cache.prefix');
-
- $this->enabled = (bool) $this->config->get('system.cache.enabled');
-
- // Cache key allows us to invalidate all cache on configuration changes.
- $this->key = ($prefix ? $prefix : 'g') . '-' . substr(md5($uri->rootUrl(true) . $this->config->key() . GRAV_VERSION), 2, 8);
-
- $this->driver = $this->getCacheDriver();
-
- // Set the cache namespace to our unique key
- $this->driver->setNamespace($this->key);
- }
-
- /**
- * Automatically picks the cache mechanism to use. If you pick one manually it will use that
- * If there is no config option for $driver in the config, or it's set to 'auto', it will
- * pick the best option based on which cache extensions are installed.
- *
- * @return DoctrineCacheDriver The cache driver to use
- */
- public function getCacheDriver()
- {
- $setting = $this->config->get('system.cache.driver');
- $driver_name = 'file';
-
- if (!$setting || $setting == 'auto') {
- if (extension_loaded('apc')) {
- $driver_name = 'apc';
- } elseif (extension_loaded('wincache')) {
- $driver_name = 'wincache';
- } elseif (extension_loaded('xcache')) {
- $driver_name = 'xcache';
- }
- } else {
- $driver_name = $setting;
- }
-
- switch ($driver_name) {
- case 'apc':
- $driver = new \Doctrine\Common\Cache\ApcCache();
- break;
-
- case 'wincache':
- $driver = new \Doctrine\Common\Cache\WinCacheCache();
- break;
-
- case 'xcache':
- $driver = new \Doctrine\Common\Cache\XcacheCache();
- break;
-
- case 'memcache':
- $memcache = new \Memcache();
- $memcache->connect($this->config->get('system.cache.memcache.server','localhost'),
- $this->config->get('system.cache.memcache.port', 11211));
- $driver = new \Doctrine\Common\Cache\MemcacheCache();
- $driver->setMemcache($memcache);
- break;
-
- case 'redis':
- $redis = new \Redis();
- $redis->connect($this->config->get('system.cache.redis.server','localhost'),
- $this->config->get('system.cache.redis.port', 6379));
-
- $driver = new \Doctrine\Common\Cache\RedisCache();
- $driver->setRedis($redis);
- break;
-
- default:
- $driver = new \Doctrine\Common\Cache\FilesystemCache($this->cache_dir);
- break;
- }
-
- return $driver;
- }
-
- /**
- * Gets a cached entry if it exists based on an id. If it does not exist, it returns false
- *
- * @param string $id the id of the cached entry
- * @return object returns the cached entry, can be any type, or false if doesn't exist
- */
- public function fetch($id)
- {
- if ($this->enabled) {
- return $this->driver->fetch($id);
- } else {
- return false;
- }
- }
-
- /**
- * Stores a new cached entry.
- *
- * @param string $id the id of the cached entry
- * @param array|object $data the data for the cached entry to store
- * @param int $lifetime the lifetime to store the entry in seconds
- */
- public function save($id, $data, $lifetime = null)
- {
- if ($this->enabled) {
- if ($lifetime === null) {
- $lifetime = $this->getLifetime();
- }
- $this->driver->save($id, $data, $lifetime);
- }
- }
-
- /**
- * Getter method to get the cache key
- */
- public function getKey()
- {
- return $this->key;
- }
-
- /**
- * Helper method to clear all Grav caches
- *
- * @param string $remove standard|all|assets-only|images-only|cache-only
- *
- * @return array
- */
- public static function clearCache($remove = 'standard')
- {
-
- $output = [];
- $user_config = USER_DIR . 'config/system.yaml';
-
- switch($remove) {
- case 'all':
- $remove_paths = self::$all_remove;
- break;
- case 'assets-only':
- $remove_paths = self::$assets_remove;
- break;
- case 'images-only':
- $remove_paths = self::$images_remove;
- break;
- case 'cache-only':
- $remove_paths = self::$cache_remove;
- break;
- default:
- $remove_paths = self::$standard_remove;
- }
-
-
- foreach ($remove_paths as $path) {
-
- $anything = false;
- $files = glob(ROOT_DIR . $path . '*');
-
- if (is_array($files)) {
- foreach ($files as $file) {
- if (is_file($file)) {
- if (@unlink($file)) {
- $anything = true;
- }
- } elseif (is_dir($file)) {
- if (@Folder::delete($file)) {
- $anything = true;
- }
- }
- }
- }
-
- if ($anything) {
- $output[] = 'Cleared: ' . $path . '*';
- }
- }
-
- $output[] = '';
-
- if (($remove == 'all' || $remove == 'standard') && file_exists($user_config)) {
- touch($user_config);
-
- $output[] = 'Touched: ' . $user_config;
- $output[] = '';
- }
-
- return $output;
- }
-
-
- /**
- * Set the cache lifetime programmatically
- *
- * @param int $future timestamp
- */
- public function setLifetime($future)
- {
- if (!$future) {
- return;
- }
-
- $interval = $future - $this->now;
- if ($interval > 0 && $interval < $this->getLifetime()) {
- $this->lifetime = $interval;
- }
- }
-
-
- /**
- * Retrieve the cache lifetime (in seconds)
- *
- * @return mixed
- */
- public function getLifetime()
- {
- if ($this->lifetime === null) {
- $this->lifetime = $this->config->get('system.cache.lifetime') ?: 604800; // 1 week default
- }
-
- return $this->lifetime;
- }
-}
diff --git a/src/system/src/Grav/Common/Composer.php b/src/system/src/Grav/Common/Composer.php
deleted file mode 100644
index 5efde89..0000000
--- a/src/system/src/Grav/Common/Composer.php
+++ /dev/null
@@ -1,55 +0,0 @@
-grav = $grav ?: Grav::instance();
- }
-
- public function init()
- {
- /** @var UniformResourceLocator $locator */
- $locator = $this->grav['locator'];
-
- $blueprints = $locator->findResources('blueprints://config');
- $plugins = $locator->findResources('plugins://');
-
- $blueprintFiles = $this->getBlueprintFiles($blueprints, $plugins);
-
- $this->loadCompiledBlueprints($plugins + $blueprints, $blueprintFiles);
- }
-
- protected function loadCompiledBlueprints($blueprints, $blueprintFiles)
- {
- $checksum = md5(serialize($blueprints));
- $filename = CACHE_DIR . 'compiled/blueprints/' . $checksum .'.php';
- $checksum .= ':'.md5(serialize($blueprintFiles));
- $class = get_class($this);
- $file = PhpFile::instance($filename);
-
- if ($file->exists()) {
- $cache = $file->exists() ? $file->content() : null;
- } else {
- $cache = null;
- }
-
-
- // Load real file if cache isn't up to date (or is invalid).
- if (
- !is_array($cache)
- || empty($cache['checksum'])
- || empty($cache['$class'])
- || $cache['checksum'] != $checksum
- || $cache['@class'] != $class
- ) {
- // Attempt to lock the file for writing.
- $file->lock(false);
-
- // Load blueprints.
- $this->blueprints = new Blueprints();
- foreach ($blueprintFiles as $key => $files) {
- $this->loadBlueprints($key);
- }
-
- $cache = [
- '@class' => $class,
- 'checksum' => $checksum,
- 'files' => $blueprintFiles,
- 'data' => $this->blueprints->toArray()
- ];
-
- // If compiled file wasn't already locked by another process, save it.
- if ($file->locked() !== false) {
- $file->save($cache);
- $file->unlock();
- }
- } else {
- $this->blueprints = new Blueprints($cache['data']);
- }
- }
-
- /**
- * Load global blueprints.
- *
- * @param string $key
- * @param array $files
- */
- public function loadBlueprints($key, array $files = null)
- {
- if (is_null($files)) {
- $files = $this->files[$key];
- }
- foreach ($files as $name => $item) {
- $file = CompiledYamlFile::instance($item['file']);
- $this->blueprints->embed($name, $file->content(), '/');
- }
- }
-
- /**
- * Get all blueprint files (including plugins).
- *
- * @param array $blueprints
- * @param array $plugins
- * @return array
- */
- protected function getBlueprintFiles(array $blueprints, array $plugins)
- {
- $list = [];
- foreach (array_reverse($plugins) as $folder) {
- $list += $this->detectPlugins($folder, true);
- }
- foreach (array_reverse($blueprints) as $folder) {
- $list += $this->detectConfig($folder, true);
- }
- return $list;
- }
-
- /**
- * Detects all plugins with a configuration file and returns last modification time.
- *
- * @param string $lookup Location to look up from.
- * @param bool $blueprints
- * @return array
- * @internal
- */
- protected function detectPlugins($lookup = SYSTEM_DIR, $blueprints = false)
- {
- $find = $blueprints ? 'blueprints.yaml' : '.yaml';
- $location = $blueprints ? 'blueprintFiles' : 'configFiles';
- $path = trim(Folder::getRelativePath($lookup), '/');
- if (isset($this->{$location}[$path])) {
- return [$path => $this->{$location}[$path]];
- }
-
- $list = [];
-
- if (is_dir($lookup)) {
- $iterator = new \DirectoryIterator($lookup);
-
- /** @var \DirectoryIterator $directory */
- foreach ($iterator as $directory) {
- if (!$directory->isDir() || $directory->isDot()) {
- continue;
- }
-
- $name = $directory->getBasename();
- $filename = "{$path}/{$name}/" . ($find && $find[0] != '.' ? $find : $name . $find);
-
- if (is_file($filename)) {
- $list["plugins/{$name}"] = ['file' => $filename, 'modified' => filemtime($filename)];
- }
- }
- }
-
- $this->{$location}[$path] = $list;
-
- return [$path => $list];
- }
-
- /**
- * Detects all plugins with a configuration file and returns last modification time.
- *
- * @param string $lookup Location to look up from.
- * @param bool $blueprints
- * @return array
- * @internal
- */
- protected function detectConfig($lookup = SYSTEM_DIR, $blueprints = false)
- {
- $location = $blueprints ? 'blueprintFiles' : 'configFiles';
- $path = trim(Folder::getRelativePath($lookup), '/');
- if (isset($this->{$location}[$path])) {
- return [$path => $this->{$location}[$path]];
- }
-
- if (is_dir($lookup)) {
- // Find all system and user configuration files.
- $options = [
- 'compare' => 'Filename',
- 'pattern' => '|\.yaml$|',
- 'filters' => [
- 'key' => '|\.yaml$|',
- 'value' => function (\RecursiveDirectoryIterator $file) use ($path) {
- return ['file' => "{$path}/{$file->getSubPathname()}", 'modified' => $file->getMTime()];
- }],
- 'key' => 'SubPathname'
- ];
-
- $list = Folder::all($lookup, $options);
- } else {
- $list = [];
- }
-
- $this->{$location}[$path] = $list;
-
- return [$path => $list];
- }
-}
diff --git a/src/system/src/Grav/Common/Config/Config.php b/src/system/src/Grav/Common/Config/Config.php
deleted file mode 100644
index cc8acc0..0000000
--- a/src/system/src/Grav/Common/Config/Config.php
+++ /dev/null
@@ -1,479 +0,0 @@
- [
- 'type' => 'ReadOnlyStream',
- 'prefixes' => [
- '' => ['system'],
- ]
- ],
- 'user' => [
- 'type' => 'ReadOnlyStream',
- 'prefixes' => [
- '' => ['user'],
- ]
- ],
- 'blueprints' => [
- 'type' => 'ReadOnlyStream',
- 'prefixes' => [
- '' => ['user://blueprints', 'system/blueprints'],
- ]
- ],
- 'config' => [
- 'type' => 'ReadOnlyStream',
- 'prefixes' => [
- '' => ['user://config', 'system/config'],
- ]
- ],
- 'plugins' => [
- 'type' => 'ReadOnlyStream',
- 'prefixes' => [
- '' => ['user://plugins'],
- ]
- ],
- 'plugin' => [
- 'type' => 'ReadOnlyStream',
- 'prefixes' => [
- '' => ['user://plugins'],
- ]
- ],
- 'themes' => [
- 'type' => 'ReadOnlyStream',
- 'prefixes' => [
- '' => ['user://themes'],
- ]
- ],
- 'languages' => [
- 'type' => 'ReadOnlyStream',
- 'prefixes' => [
- '' => ['user://languages', 'system/languages'],
- ]
- ],
- 'cache' => [
- 'type' => 'Stream',
- 'prefixes' => [
- '' => ['cache'],
- 'images' => ['images']
- ]
- ],
- 'log' => [
- 'type' => 'Stream',
- 'prefixes' => [
- '' => ['logs']
- ]
- ],
- 'backup' => [
- 'type' => 'Stream',
- 'prefixes' => [
- '' => ['backup']
- ]
- ]
- ];
-
- protected $setup = [];
-
- protected $blueprintFiles = [];
- protected $configFiles = [];
- protected $languageFiles = [];
- protected $checksum;
- protected $timestamp;
-
- protected $configLookup;
- protected $blueprintLookup;
- protected $pluginLookup;
- protected $languagesLookup;
-
- protected $finder;
- protected $environment;
- protected $messages = [];
-
- protected $languages;
-
- public function __construct(array $setup = array(), Grav $grav = null, $environment = null)
- {
- $this->grav = $grav ?: Grav::instance();
- $this->finder = new ConfigFinder;
- $this->environment = $environment ?: 'localhost';
- $this->messages[] = 'Environment Name: ' . $this->environment;
-
- // Make sure that
- if (!isset($setup['streams']['schemes'])) {
- $setup['streams']['schemes'] = [];
- }
- $setup['streams']['schemes'] += $this->streams;
-
- $setup = $this->autoDetectEnvironmentConfig($setup);
-
- $this->setup = $setup;
- parent::__construct($setup);
-
- $this->check();
- }
-
- public function key()
- {
- return $this->checksum();
- }
-
- public function reload()
- {
- $this->items = $this->setup;
- $this->check();
- $this->init();
- $this->debug();
-
- return $this;
- }
-
- protected function check()
- {
- $streams = isset($this->items['streams']['schemes']) ? $this->items['streams']['schemes'] : null;
- if (!is_array($streams)) {
- throw new \InvalidArgumentException('Configuration is missing streams.schemes!');
- }
- $diff = array_keys(array_diff_key($this->streams, $streams));
- if ($diff) {
- throw new \InvalidArgumentException(
- sprintf('Configuration is missing keys %s from streams.schemes!', implode(', ', $diff))
- );
- }
- }
-
- public function debug()
- {
- foreach ($this->messages as $message) {
- $this->grav['debugger']->addMessage($message);
- }
- $this->messages = [];
- }
-
- public function init()
- {
- /** @var UniformResourceLocator $locator */
- $locator = $this->grav['locator'];
-
- $this->configLookup = $locator->findResources('config://');
- $this->blueprintLookup = $locator->findResources('blueprints://config');
- $this->pluginLookup = $locator->findResources('plugins://');
-
-
- $this->loadCompiledBlueprints($this->blueprintLookup, $this->pluginLookup, 'master');
- $this->loadCompiledConfig($this->configLookup, $this->pluginLookup, 'master');
-
- // process languages if supported
- if ($this->get('system.languages.translations', true)) {
- $this->languagesLookup = $locator->findResources('languages://');
- $this->loadCompiledLanguages($this->languagesLookup, $this->pluginLookup, 'master');
- }
-
- $this->initializeLocator($locator);
- }
-
- public function checksum()
- {
- if (empty($this->checksum)) {
- $checkBlueprints = $this->get('system.cache.check.blueprints', false);
- $checkLanguages = $this->get('system.cache.check.languages', false);
- $checkConfig = $this->get('system.cache.check.config', true);
- $checkSystem = $this->get('system.cache.check.system', true);
-
- if (!$checkBlueprints && !$checkLanguages && !$checkConfig && !$checkSystem) {
- $this->messages[] = 'Skip configuration timestamp check.';
- return false;
- }
-
- // Generate checksum according to the configuration settings.
- if (!$checkConfig) {
- // Just check changes in system.yaml files and ignore all the other files.
- $cc = $checkSystem ? $this->finder->locateConfigFile($this->configLookup, 'system') : [];
- } else {
- // Check changes in all configuration files.
- $cc = $this->finder->locateConfigFiles($this->configLookup, $this->pluginLookup);
- }
-
- if ($checkBlueprints) {
- $cb = $this->finder->locateBlueprintFiles($this->blueprintLookup, $this->pluginLookup);
- } else {
- $cb = [];
- }
-
- if ($checkLanguages) {
- $cl = $this->finder->locateLanguageFiles($this->languagesLookup, $this->pluginLookup);
- } else {
- $cl = [];
- }
-
- $this->checksum = md5(json_encode([$cc, $cb, $cl]));
- }
-
- return $this->checksum;
- }
-
- protected function autoDetectEnvironmentConfig($items)
- {
- $environment = $this->environment;
- $env_stream = 'user://'.$environment.'/config';
-
- if (file_exists(USER_DIR.$environment.'/config')) {
- array_unshift($items['streams']['schemes']['config']['prefixes'][''], $env_stream);
- }
-
- return $items;
- }
-
- protected function loadCompiledBlueprints($blueprints, $plugins, $filename = null)
- {
- $checksum = md5(json_encode($blueprints));
- $filename = $filename
- ? CACHE_DIR . 'compiled/blueprints/' . $filename . '-' . $this->environment . '.php'
- : CACHE_DIR . 'compiled/blueprints/' . $checksum . '-' . $this->environment . '.php';
- $file = PhpFile::instance($filename);
- $cache = $file->exists() ? $file->content() : null;
- $blueprintFiles = $this->finder->locateBlueprintFiles($blueprints, $plugins);
- $checksum .= ':'.md5(json_encode($blueprintFiles));
- $class = get_class($this);
-
- // Load real file if cache isn't up to date (or is invalid).
- if (
- !is_array($cache)
- || !isset($cache['checksum'])
- || !isset($cache['@class'])
- || $cache['checksum'] != $checksum
- || $cache['@class'] != $class
- ) {
- // Attempt to lock the file for writing.
- $file->lock(false);
-
- // Load blueprints.
- $this->blueprints = new Blueprints;
- foreach ($blueprintFiles as $files) {
- $this->loadBlueprintFiles($files);
- }
-
- $cache = [
- '@class' => $class,
- 'checksum' => $checksum,
- 'files' => $blueprintFiles,
- 'data' => $this->blueprints->toArray()
- ];
- // If compiled file wasn't already locked by another process, save it.
- if ($file->locked() !== false) {
- $this->messages[] = 'Saving compiled blueprints.';
- $file->save($cache);
- $file->unlock();
- }
- } else {
- $this->blueprints = new Blueprints($cache['data']);
- }
- }
-
- protected function loadCompiledConfig($configs, $plugins, $filename = null)
- {
- $filename = $filename
- ? CACHE_DIR . 'compiled/config/' . $filename . '-' . $this->environment . '.php'
- : CACHE_DIR . 'compiled/config/' . $checksum . '-' . $this->environment . '.php';
- $file = PhpFile::instance($filename);
- $cache = $file->exists() ? $file->content() : null;
- $class = get_class($this);
- $checksum = $this->checksum();
-
- if (
- !is_array($cache)
- || !isset($cache['checksum'])
- || !isset($cache['@class'])
- || $cache['@class'] != $class
- ) {
- $this->messages[] = 'No cached configuration, compiling new configuration..';
- } else if ($cache['checksum'] !== $checksum) {
- $this->messages[] = 'Configuration checksum mismatch, reloading configuration..';
- } else {
- $this->messages[] = 'Configuration checksum matches, using cached version.';
-
- $this->items = $cache['data'];
- return;
- }
-
- $configFiles = $this->finder->locateConfigFiles($configs, $plugins);
-
- // Attempt to lock the file for writing.
- $file->lock(false);
-
- // Load configuration.
- foreach ($configFiles as $files) {
- $this->loadConfigFiles($files);
- }
- $cache = [
- '@class' => $class,
- 'timestamp' => time(),
- 'checksum' => $checksum,
- 'data' => $this->toArray()
- ];
-
- // If compiled file wasn't already locked by another process, save it.
- if ($file->locked() !== false) {
- $this->messages[] = 'Saving compiled configuration.';
- $file->save($cache);
- $file->unlock();
- }
-
- $this->items = $cache['data'];
- }
-
- /**
- * @param $languages
- * @param $plugins
- * @param null $filename
- */
- protected function loadCompiledLanguages($languages, $plugins, $filename = null)
- {
- $checksum = md5(json_encode($languages));
- $filename = $filename
- ? CACHE_DIR . 'compiled/languages/' . $filename . '-' . $this->environment . '.php'
- : CACHE_DIR . 'compiled/languages/' . $checksum . '-' . $this->environment . '.php';
- $file = PhpFile::instance($filename);
- $cache = $file->exists() ? $file->content() : null;
- $languageFiles = $this->finder->locateLanguageFiles($languages, $plugins);
- $checksum .= ':' . md5(json_encode($languageFiles));
- $class = get_class($this);
-
- // Load real file if cache isn't up to date (or is invalid).
- if (
- !is_array($cache)
- || !isset($cache['checksum'])
- || !isset($cache['@class'])
- || $cache['checksum'] != $checksum
- || $cache['@class'] != $class
- ) {
- // Attempt to lock the file for writing.
- $file->lock(false);
-
- // Load languages.
- $this->languages = new Languages;
- $pluginPaths = str_ireplace(GRAV_ROOT . '/', '', array_reverse($plugins));
- foreach ($pluginPaths as $path) {
- if (isset($languageFiles[$path])) {
- foreach ((array) $languageFiles[$path] as $plugin => $item) {
- $lang_file = CompiledYamlFile::instance($item['file']);
- $content = $lang_file->content();
- $this->languages->mergeRecursive($content);
- }
- unset($languageFiles[$path]);
- }
- }
-
- foreach ($languageFiles as $location) {
- foreach ($location as $lang => $item) {
- $lang_file = CompiledYamlFile::instance($item['file']);
- $content = $lang_file->content();
- $this->languages->join($lang, $content, '/');
- }
- }
-
- $cache = [
- '@class' => $class,
- 'checksum' => $checksum,
- 'files' => $languageFiles,
- 'data' => $this->languages->toArray()
- ];
- // If compiled file wasn't already locked by another process, save it.
- if ($file->locked() !== false) {
- $this->messages[] = 'Saving compiled languages.';
- $file->save($cache);
- $file->unlock();
- }
- } else {
- $this->languages = new Languages($cache['data']);
- }
- }
-
- /**
- * Load blueprints.
- *
- * @param array $files
- */
- public function loadBlueprintFiles(array $files)
- {
- foreach ($files as $name => $item) {
- $file = CompiledYamlFile::instance($item['file']);
- $this->blueprints->embed($name, $file->content(), '/');
- }
- }
-
- /**
- * Load configuration.
- *
- * @param array $files
- */
- public function loadConfigFiles(array $files)
- {
- foreach ($files as $name => $item) {
- $file = CompiledYamlFile::instance($item['file']);
- $this->join($name, $file->content(), '/');
- }
- }
-
- /**
- * Initialize resource locator by using the configuration.
- *
- * @param UniformResourceLocator $locator
- */
- public function initializeLocator(UniformResourceLocator $locator)
- {
- $locator->reset();
-
- $schemes = (array) $this->get('streams.schemes', []);
-
- foreach ($schemes as $scheme => $config) {
- if (isset($config['paths'])) {
- $locator->addPath($scheme, '', $config['paths']);
- }
- if (isset($config['prefixes'])) {
- foreach ($config['prefixes'] as $prefix => $paths) {
- $locator->addPath($scheme, $prefix, $paths);
- }
- }
- }
- }
-
- /**
- * Get available streams and their types from the configuration.
- *
- * @return array
- */
- public function getStreams()
- {
- $schemes = [];
- foreach ((array) $this->get('streams.schemes') as $scheme => $config) {
- $type = !empty($config['type']) ? $config['type'] : 'ReadOnlyStream';
- if ($type[0] != '\\') {
- $type = '\\RocketTheme\\Toolbox\\StreamWrapper\\' . $type;
- }
-
- $schemes[$scheme] = $type;
- }
-
- return $schemes;
- }
-
- public function getLanguages()
- {
- return $this->languages;
- }
-}
diff --git a/src/system/src/Grav/Common/Config/ConfigFinder.php b/src/system/src/Grav/Common/Config/ConfigFinder.php
deleted file mode 100644
index 4606941..0000000
--- a/src/system/src/Grav/Common/Config/ConfigFinder.php
+++ /dev/null
@@ -1,186 +0,0 @@
-detectInFolder($folder, 'blueprints');
- }
- foreach (array_reverse($blueprints) as $folder) {
- $list += $this->detectRecursive($folder);
- }
- return $list;
- }
-
- /**
- * Get all locations for configuration files (including plugins).
- *
- * @param array $configs
- * @param array $plugins
- * @return array
- */
- public function locateConfigFiles(array $configs, array $plugins)
- {
- $list = [];
- foreach (array_reverse($plugins) as $folder) {
- $list += $this->detectInFolder($folder);
- }
- foreach (array_reverse($configs) as $folder) {
- $list += $this->detectRecursive($folder);
- }
- return $list;
- }
-
- public function locateLanguageFiles(array $languages, array $plugins)
- {
- $list = [];
- foreach (array_reverse($plugins) as $folder) {
- $list += $this->detectLanguagesInFolder($folder, 'languages');
- }
- foreach (array_reverse($languages) as $folder) {
- $list += $this->detectRecursive($folder);
- }
- return $list;
- }
-
- /**
- * Get all locations for a single configuration file.
- *
- * @param array $folders Locations to look up from.
- * @param string $name Filename to be located.
- * @return array
- */
- public function locateConfigFile(array $folders, $name)
- {
- $filename = "{$name}.yaml";
-
- $list = [];
- foreach ($folders as $folder) {
- $path = trim(Folder::getRelativePath($folder), '/');
-
- if (is_file("{$folder}/{$filename}")) {
- $modified = filemtime("{$folder}/{$filename}");
- } else {
- $modified = 0;
- }
- $list[$path] = [$name => ['file' => "{$path}/{$filename}", 'modified' => $modified]];
- }
-
- return $list;
- }
-
- /**
- * Detects all plugins with a configuration file and returns them with last modification time.
- *
- * @param string $folder Location to look up from.
- * @param string $lookup Filename to be located.
- * @return array
- * @internal
- */
- protected function detectInFolder($folder, $lookup = null)
- {
- $path = trim(Folder::getRelativePath($folder), '/');
-
- $list = [];
-
- if (is_dir($folder)) {
- $iterator = new \FilesystemIterator($folder);
-
- /** @var \DirectoryIterator $directory */
- foreach ($iterator as $directory) {
- if (!$directory->isDir()) {
- continue;
- }
-
- $name = $directory->getBasename();
- $find = ($lookup ?: $name) . '.yaml';
- $filename = "{$path}/{$name}/$find";
-
- if (file_exists($filename)) {
- $list["plugins/{$name}"] = ['file' => $filename, 'modified' => filemtime($filename)];
- }
- }
- }
-
- return [$path => $list];
- }
-
- protected function detectLanguagesInFolder($folder, $lookup = null)
- {
- $path = trim(Folder::getRelativePath($folder), '/');
-
- $list = [];
-
- if (is_dir($folder)) {
- $iterator = new \FilesystemIterator($folder);
-
- /** @var \DirectoryIterator $directory */
- foreach ($iterator as $directory) {
- if (!$directory->isDir()) {
- continue;
- }
-
- $name = $directory->getBasename();
- $find = ($lookup ?: $name) . '.yaml';
- $filename = "{$path}/{$name}/$find";
-
- if (file_exists($filename)) {
- $list[$name] = ['file' => $filename, 'modified' => filemtime($filename)];
- }
- }
- }
-
- return [$path => $list];
- }
-
- /**
- * Detects all plugins with a configuration file and returns them with last modification time.
- *
- * @param string $folder Location to look up from.
- * @return array
- * @internal
- */
- protected function detectRecursive($folder)
- {
- $path = trim(Folder::getRelativePath($folder), '/');
-
- if (is_dir($folder)) {
- // Find all system and user configuration files.
- $options = [
- 'compare' => 'Filename',
- 'pattern' => '|\.yaml$|',
- 'filters' => [
- 'key' => '|\.yaml$|',
- 'value' => function (\RecursiveDirectoryIterator $file) use ($path) {
- return ['file' => "{$path}/{$file->getSubPathname()}", 'modified' => $file->getMTime()];
- }
- ],
- 'key' => 'SubPathname'
- ];
-
- $list = Folder::all($folder, $options);
- } else {
- $list = [];
- }
-
- return [$path => $list];
- }
-}
diff --git a/src/system/src/Grav/Common/Config/Languages.php b/src/system/src/Grav/Common/Config/Languages.php
deleted file mode 100644
index c014129..0000000
--- a/src/system/src/Grav/Common/Config/Languages.php
+++ /dev/null
@@ -1,27 +0,0 @@
-items['plugins'])) {
- $this->items = array_merge_recursive($this->items, $this->items['plugins']);
- unset($this->items['plugins']);
- }
- }
-
- public function mergeRecursive(array $data)
- {
- $this->items = array_merge_recursive($this->items, $data);
- }
-}
diff --git a/src/system/src/Grav/Common/Data/Blueprint.php b/src/system/src/Grav/Common/Data/Blueprint.php
deleted file mode 100644
index 15cdce6..0000000
--- a/src/system/src/Grav/Common/Data/Blueprint.php
+++ /dev/null
@@ -1,456 +0,0 @@
- 1];
-
- /**
- * @param string $name
- * @param array $data
- * @param Blueprints $context
- */
- public function __construct($name, array $data = array(), Blueprints $context = null)
- {
- $this->name = $name;
- $this->items = $data;
- $this->context = $context;
- }
-
- /**
- * Set filter for inherited properties.
- *
- * @param array $filter List of field names to be inherited.
- */
- public function setFilter(array $filter)
- {
- $this->filter = array_flip($filter);
- }
-
- /**
- * Return all form fields.
- *
- * @return array
- */
- public function fields()
- {
- if (!isset($this->fields)) {
- $this->fields = [];
- $this->embed('', $this->items);
- }
-
- return $this->fields;
- }
-
- /**
- * Validate data against blueprints.
- *
- * @param array $data
- * @throws \RuntimeException
- */
- public function validate(array $data)
- {
- // Initialize data
- $this->fields();
-
- try {
- $this->validateArray($data, $this->nested);
- } catch (\RuntimeException $e) {
- throw new \RuntimeException(sprintf('Validation failed: %s', $e->getMessage()));
- }
- }
-
- /**
- * Merge two arrays by using blueprints.
- *
- * @param array $data1
- * @param array $data2
- * @return array
- */
- public function mergeData(array $data1, array $data2)
- {
- // Initialize data
- $this->fields();
- return $this->mergeArrays($data1, $data2, $this->nested);
- }
-
- /**
- * Filter data by using blueprints.
- *
- * @param array $data
- * @return array
- */
- public function filter(array $data)
- {
- // Initialize data
- $this->fields();
- return $this->filterArray($data, $this->nested);
- }
-
- /**
- * Return data fields that do not exist in blueprints.
- *
- * @param array $data
- * @param string $prefix
- * @return array
- */
- public function extra(array $data, $prefix = '')
- {
- // Initialize data
- $this->fields();
- $rules = $this->nested;
-
- // Drill down to prefix level
- if (!empty($prefix)) {
- $parts = explode('.', trim($prefix, '.'));
- foreach ($parts as $part) {
- $rules = isset($rules[$part]) ? $rules[$part] : [];
- }
- }
-
- return $this->extraArray($data, $rules, $prefix);
- }
-
- /**
- * Extend blueprint with another blueprint.
- *
- * @param Blueprint $extends
- * @param bool $append
- */
- public function extend(Blueprint $extends, $append = false)
- {
- $blueprints = $append ? $this->items : $extends->toArray();
- $appended = $append ? $extends->toArray() : $this->items;
-
- $bref_stack = array(&$blueprints);
- $head_stack = array($appended);
-
- do {
- end($bref_stack);
-
- $bref = &$bref_stack[key($bref_stack)];
- $head = array_pop($head_stack);
-
- unset($bref_stack[key($bref_stack)]);
-
- foreach (array_keys($head) as $key) {
- if (isset($key, $bref[$key]) && is_array($bref[$key]) && is_array($head[$key])) {
- $bref_stack[] = &$bref[$key];
- $head_stack[] = $head[$key];
- } else {
- $bref = array_merge($bref, array($key => $head[$key]));
- }
- }
- } while (count($head_stack));
-
- $this->items = $blueprints;
- }
-
- /**
- * Convert object into an array.
- *
- * @return array
- */
- public function getState()
- {
- return ['name' => $this->name, 'items' => $this->items, 'rules' => $this->rules, 'nested' => $this->nested];
- }
-
- /**
- * Embed an array to the blueprint.
- *
- * @param $name
- * @param array $value
- * @param string $separator
- */
- public function embed($name, array $value, $separator = '.')
- {
-
- if (!isset($value['form']['fields']) || !is_array($value['form']['fields'])) {
- return;
- }
- // Initialize data
- $this->fields();
- $prefix = $name ? strtr($name, $separator, '.') . '.' : '';
- $params = array_intersect_key($this->filter, $value);
- $this->parseFormFields($value['form']['fields'], $params, $prefix, $this->fields);
- }
-
- /**
- * @param array $data
- * @param array $rules
- * @throws \RuntimeException
- * @internal
- */
- protected function validateArray(array $data, array $rules)
- {
- $this->checkRequired($data, $rules);
-
- foreach ($data as $key => $field) {
- $val = isset($rules[$key]) ? $rules[$key] : null;
- $rule = is_string($val) ? $this->rules[$val] : null;
-
- if ($rule) {
- // Item has been defined in blueprints.
- Validation::validate($field, $rule);
- } elseif (is_array($field) && is_array($val)) {
- // Array has been defined in blueprints.
- $this->validateArray($field, $val);
- } elseif (isset($this->items['form']['validation']) && $this->items['form']['validation'] == 'strict') {
- // Undefined/extra item.
- throw new \RuntimeException(sprintf('%s is not defined in blueprints', $key));
- }
- }
- }
-
- /**
- * @param array $data
- * @param array $rules
- * @return array
- * @internal
- */
- protected function filterArray(array $data, array $rules)
- {
- $results = array();
- foreach ($data as $key => $field) {
- $val = isset($rules[$key]) ? $rules[$key] : null;
- $rule = is_string($val) ? $this->rules[$val] : null;
-
- if ($rule) {
- // Item has been defined in blueprints.
- if (is_array($field) && count($field) == 1 && reset($field) == '') {
- continue;
- }
- $field = Validation::filter($field, $rule);
- } elseif (is_array($field) && is_array($val)) {
- // Array has been defined in blueprints.
- $field = $this->filterArray($field, $val);
- } elseif (isset($this->items['form']['validation']) && $this->items['form']['validation'] == 'strict') {
- $field = null;
- }
-
- if (isset($field) && (!is_array($field) || !empty($field))) {
- $results[$key] = $field;
- }
- }
-
- return $results;
- }
-
- /**
- * @param array $data1
- * @param array $data2
- * @param array $rules
- * @return array
- * @internal
- */
- protected function mergeArrays(array $data1, array $data2, array $rules)
- {
- foreach ($data2 as $key => $field) {
- $val = isset($rules[$key]) ? $rules[$key] : null;
- $rule = is_string($val) ? $this->rules[$val] : null;
-
- if (!$rule && array_key_exists($key, $data1) && is_array($field) && is_array($val)) {
- // Array has been defined in blueprints.
- $data1[$key] = $this->mergeArrays($data1[$key], $field, $val);
- } else {
- // Otherwise just take value from the data2.
- $data1[$key] = $field;
- }
- }
-
- return $data1;
- }
-
- /**
- * @param array $data
- * @param array $rules
- * @param string $prefix
- * @return array
- * @internal
- */
- protected function extraArray(array $data, array $rules, $prefix)
- {
- $array = array();
- foreach ($data as $key => $field) {
- $val = isset($rules[$key]) ? $rules[$key] : null;
- $rule = is_string($val) ? $this->rules[$val] : null;
-
- if ($rule) {
- // Item has been defined in blueprints.
- } elseif (is_array($field) && is_array($val)) {
- // Array has been defined in blueprints.
- $array += $this->ExtraArray($field, $val, $prefix . $key . '.');
- } else {
- // Undefined/extra item.
- $array[$prefix.$key] = $field;
- }
- }
- return $array;
- }
-
- /**
- * Gets all field definitions from the blueprints.
- *
- * @param array $fields
- * @param array $params
- * @param string $prefix
- * @param array $current
- * @internal
- */
- protected function parseFormFields(array &$fields, $params, $prefix, array &$current)
- {
- // Go though all the fields in current level.
- foreach ($fields as $key => &$field) {
- $current[$key] = &$field;
- // Set name from the array key.
- $field['name'] = $prefix . $key;
- $field += $params;
-
- if (isset($field['fields']) && (!isset($field['type']) || $field['type'] !== 'list')) {
- // Recursively get all the nested fields.
- $newParams = array_intersect_key($this->filter, $field);
- $this->parseFormFields($field['fields'], $newParams, $prefix, $current[$key]['fields']);
- } else if ($field['type'] !== 'ignore') {
- // Add rule.
- $this->rules[$prefix . $key] = &$field;
- $this->addProperty($prefix . $key);
-
- foreach ($field as $name => $value) {
- // Support nested blueprints.
- if ($this->context && $name == '@import') {
- $values = (array) $value;
- if (!isset($field['fields'])) {
- $field['fields'] = array();
- }
- foreach ($values as $bname) {
- $b = $this->context->get($bname);
- $field['fields'] = array_merge($field['fields'], $b->fields());
- }
- }
-
- // Support for callable data values.
- elseif (substr($name, 0, 6) == '@data-') {
- $property = substr($name, 6);
- if (is_array($value)) {
- $func = array_shift($value);
- } else {
- $func = $value;
- $value = array();
- }
- list($o, $f) = preg_split('/::/', $func);
- if (!$f && function_exists($o)) {
- $data = call_user_func_array($o, $value);
- } elseif ($f && method_exists($o, $f)) {
- $data = call_user_func_array(array($o, $f), $value);
- }
-
- // If function returns a value,
- if (isset($data)) {
- if (isset($field[$property]) && is_array($field[$property]) && is_array($data)) {
- // Combine field and @data-field together.
- $field[$property] += $data;
- } else {
- // Or create/replace field with @data-field.
- $field[$property] = $data;
- }
- }
- }
-
- elseif (substr($name, 0, 8) == '@config-') {
- $property = substr($name, 8);
- $default = isset($field[$property]) ? $field[$property] : null;
- $config = self::getGrav()['config']->get($value, $default);
-
- if (!is_null($config)) {
- $field[$property] = $config;
- }
- }
- }
-
- // Initialize predefined validation rule.
- if (isset($field['validate']['rule']) && $field['type'] !== 'ignore') {
- $field['validate'] += $this->getRule($field['validate']['rule']);
- }
- }
- }
- }
-
- /**
- * Add property to the definition.
- *
- * @param string $path Comma separated path to the property.
- * @internal
- */
- protected function addProperty($path)
- {
- $parts = explode('.', $path);
- $item = array_pop($parts);
-
- $nested = &$this->nested;
- foreach ($parts as $part) {
- if (!isset($nested[$part])) {
- $nested[$part] = array();
- }
- $nested = &$nested[$part];
- }
-
- if (!isset($nested[$item])) {
- $nested[$item] = $path;
- }
- }
-
- /**
- * @param $rule
- * @return array
- * @internal
- */
- protected function getRule($rule)
- {
- if (isset($this->items['rules'][$rule]) && is_array($this->items['rules'][$rule])) {
- return $this->items['rules'][$rule];
- }
- return array();
- }
-
- /**
- * @param array $data
- * @param array $fields
- * @throws \RuntimeException
- * @internal
- */
- protected function checkRequired(array $data, array $fields)
- {
- foreach ($fields as $name => $field) {
- if (!is_string($field)) {
- continue;
- }
- $field = $this->rules[$field];
- if (isset($field['validate']['required'])
- && $field['validate']['required'] === true
- && empty($data[$name])) {
- throw new \RuntimeException("Missing required field: {$field['name']}");
- }
- }
- }
-}
diff --git a/src/system/src/Grav/Common/Data/Blueprints.php b/src/system/src/Grav/Common/Data/Blueprints.php
deleted file mode 100644
index 4c144a3..0000000
--- a/src/system/src/Grav/Common/Data/Blueprints.php
+++ /dev/null
@@ -1,145 +0,0 @@
-search = $search;
- }
-
- /**
- * Get blueprint.
- *
- * @param string $type Blueprint type.
- * @return Blueprint
- * @throws \RuntimeException
- */
- public function get($type)
- {
- if (!isset($this->instances[$type])) {
- $parents = [];
- if (is_string($this->search)) {
- $filename = $this->search . $type . YAML_EXT;
-
- // Check if search is a stream and resolve the path.
- if (strpos($filename, '://')) {
- $grav = static::getGrav();
- /** @var UniformResourceLocator $locator */
- $locator = $grav['locator'];
- $parents = $locator->findResources($filename);
- $filename = array_shift($parents);
- }
- } else {
- $filename = isset($this->search[$type]) ? $this->search[$type] : '';
- }
-
- if ($filename && is_file($filename)) {
- $file = CompiledYamlFile::instance($filename);
- $blueprints = $file->content();
- } else {
- $blueprints = [];
- }
-
- $blueprint = new Blueprint($type, $blueprints, $this);
-
- if (isset($blueprints['@extends'])) {
- // Extend blueprint by other blueprints.
- $extends = (array) $blueprints['@extends'];
-
- if (is_string(key($extends))) {
- $extends = [ $extends ];
- }
-
- foreach ($extends as $extendConfig) {
- $extendType = !is_string($extendConfig) ? empty($extendConfig['type']) ? false : $extendConfig['type'] : $extendConfig;
-
- if (!$extendType) {
- continue;
- } elseif ($extendType === '@parent') {
- $parentFile = array_shift($parents);
- if (!$parentFile || !is_file($parentFile)) {
- continue;
- }
- $blueprints = CompiledYamlFile::instance($parentFile)->content();
- $parent = new Blueprint($type.'-parent', $blueprints, $this);
- $blueprint->extend($parent);
- continue;
- }
-
- if (is_string($extendConfig) || empty($extendConfig['context'])) {
- $context = $this;
- } else {
- // Load blueprints from external context.
- $array = explode('://', $extendConfig['context'], 2);
- $scheme = array_shift($array);
- $path = array_shift($array);
- if ($path) {
- $scheme .= '://';
- $extendType = $path ? "{$path}/{$extendType}" : $extendType;
- }
- $context = new self($scheme);
- }
- $blueprint->extend($context->get($extendType));
- }
- }
-
- $this->instances[$type] = $blueprint;
- }
-
- return $this->instances[$type];
- }
-
- /**
- * Get all available blueprint types.
- *
- * @return array List of type=>name
- */
- public function types()
- {
- if ($this->types === null) {
- $this->types = array();
-
- // Check if search is a stream.
- if (strpos($this->search, '://')) {
- // Stream: use UniformResourceIterator.
- $grav = static::getGrav();
- /** @var UniformResourceLocator $locator */
- $locator = $grav['locator'];
- $iterator = $locator->getIterator($this->search, null);
- } else {
- // Not a stream: use DirectoryIterator.
- $iterator = new \DirectoryIterator($this->search);
- }
-
- /** @var \DirectoryIterator $file */
- foreach ($iterator as $file) {
- if (!$file->isFile() || '.' . $file->getExtension() != YAML_EXT) {
- continue;
- }
- $name = $file->getBasename(YAML_EXT);
- $this->types[$name] = ucfirst(strtr($name, '_', ' '));
- }
- }
- return $this->types;
- }
-}
diff --git a/src/system/src/Grav/Common/Data/Data.php b/src/system/src/Grav/Common/Data/Data.php
deleted file mode 100644
index 6a35fbc..0000000
--- a/src/system/src/Grav/Common/Data/Data.php
+++ /dev/null
@@ -1,240 +0,0 @@
-items = $items;
-
- $this->blueprints = $blueprints;
- }
-
- /**
- * Get value by using dot notation for nested arrays/objects.
- *
- * @example $value = $data->value('this.is.my.nested.variable');
- *
- * @param string $name Dot separated path to the requested value.
- * @param mixed $default Default value (or null).
- * @param string $separator Separator, defaults to '.'
- * @return mixed Value.
- */
- public function value($name, $default = null, $separator = '.')
- {
- return $this->get($name, $default, $separator);
- }
-
- /**
- * Set default value by using dot notation for nested arrays/objects.
- *
- * @example $data->def('this.is.my.nested.variable', 'default');
- *
- * @param string $name Dot separated path to the requested value.
- * @param mixed $default Default value (or null).
- * @param string $separator Separator, defaults to '.'
- */
- public function def($name, $default = null, $separator = '.')
- {
- $this->set($name, $this->get($name, $default, $separator), $separator);
- }
-
- /**
- * Join two values together by using blueprints if available.
- *
- * @param string $name Dot separated path to the requested value.
- * @param mixed $value Value to be joined.
- * @param string $separator Separator, defaults to '.'
- */
- public function join($name, $value, $separator = '.')
- {
- $old = $this->get($name, null, $separator);
- if ($old === null) {
- // Variable does not exist yet: just use the incoming value.
- } elseif ($this->blueprints) {
- // Blueprints: join values by using blueprints.
- $value = $this->blueprints->mergeData($old, $value, $name, $separator);
- } else {
- // No blueprints: replace existing top level variables with the new ones.
- $value = array_merge($old, $value);
- }
-
- $this->set($name, $value, $separator);
- }
-
- /**
- * Join two values together by using blueprints if available.
- *
- * @param string $name Dot separated path to the requested value.
- * @param mixed $value Value to be joined.
- * @param string $separator Separator, defaults to '.'
- */
- public function joinDefaults($name, $value, $separator = '.')
- {
- $old = $this->get($name, null, $separator);
- if ($old === null) {
- // Variable does not exist yet: just use the incoming value.
- } elseif ($this->blueprints) {
- // Blueprints: join values by using blueprints.
- $value = $this->blueprints->mergeData($value, $old, $name, $separator);
- } else {
- // No blueprints: replace existing top level variables with the new ones.
- $value = array_merge($value, $old);
- }
-
- $this->set($name, $value, $separator);
- }
-
-
- /**
- * Merge two sets of data together.
- *
- * @param array $data
- * @return void
- */
- public function merge(array $data)
- {
- if ($this->blueprints) {
- $this->items = $this->blueprints->mergeData($this->items, $data);
- } else {
- $this->items = array_merge($this->items, $data);
- }
- }
-
- /**
- * Add default data to the set.
- *
- * @param array $data
- * @return void
- */
- public function setDefaults(array $data)
- {
- if ($this->blueprints) {
- $this->items = $this->blueprints->mergeData($data, $this->items);
- } else {
- $this->items = array_merge($data, $this->items);
- }
- }
-
- /**
- * Return blueprints.
- *
- * @return Blueprint
- */
- public function blueprints()
- {
- return $this->blueprints;
- }
-
- /**
- * Validate by blueprints.
- *
- * @throws \Exception
- */
- public function validate()
- {
- if ($this->blueprints) {
- $this->blueprints->validate($this->items);
- }
- }
-
- /**
- * Filter all items by using blueprints.
- */
- public function filter()
- {
- if ($this->blueprints) {
- $this->items = $this->blueprints->filter($this->items);
- }
- }
-
- /**
- * Get extra items which haven't been defined in blueprints.
- *
- * @return array
- */
- public function extra()
- {
- return $this->blueprints ? $this->blueprints->extra($this->items) : array();
- }
-
- /**
- * Save data if storage has been defined.
- */
- public function save()
- {
- $file = $this->file();
- if ($file) {
- $file->save($this->items);
- }
- }
-
- /**
- * Returns whether the data already exists in the storage.
- *
- * NOTE: This method does not check if the data is current.
- *
- * @return bool
- */
- public function exists()
- {
- return $this->file()->exists();
- }
-
- /**
- * Return unmodified data as raw string.
- *
- * NOTE: This function only returns data which has been saved to the storage.
- *
- * @return string
- */
- public function raw()
- {
- return $this->file()->raw();
- }
-
- /**
- * Set or get the data storage.
- *
- * @param FileInterface $storage Optionally enter a new storage.
- * @return FileInterface
- */
- public function file(FileInterface $storage = null)
- {
- if ($storage) {
- $this->storage = $storage;
- }
- return $this->storage;
- }
-}
diff --git a/src/system/src/Grav/Common/Data/DataInterface.php b/src/system/src/Grav/Common/Data/DataInterface.php
deleted file mode 100644
index 85d2fb6..0000000
--- a/src/system/src/Grav/Common/Data/DataInterface.php
+++ /dev/null
@@ -1,68 +0,0 @@
-value('this.is.my.nested.variable');
- *
- * @param string $name Dot separated path to the requested value.
- * @param mixed $default Default value (or null).
- * @param string $separator Separator, defaults to '.'
- * @return mixed Value.
- */
- public function value($name, $default = null, $separator = '.');
-
- /**
- * Merge external data.
- *
- * @param array $data
- * @return mixed
- */
- public function merge(array $data);
-
- /**
- * Return blueprints.
- */
- public function blueprints();
-
- /**
- * Validate by blueprints.
- *
- * @throws \Exception
- */
- public function validate();
-
- /**
- * Filter all items by using blueprints.
- */
- public function filter();
-
- /**
- * Get extra items which haven't been defined in blueprints.
- */
- public function extra();
-
- /**
- * Save data into the file.
- */
- public function save();
-
- /**
- * Set or get the data storage.
- *
- * @param FileInterface $storage Optionally enter a new storage.
- * @return FileInterface
- */
- public function file(FileInterface $storage = null);
-}
diff --git a/src/system/src/Grav/Common/Data/DataMutatorTrait.php b/src/system/src/Grav/Common/Data/DataMutatorTrait.php
deleted file mode 100644
index 707b507..0000000
--- a/src/system/src/Grav/Common/Data/DataMutatorTrait.php
+++ /dev/null
@@ -1,68 +0,0 @@
-get('this.is.my.nested.variable');
- *
- * @param string $name Dot separated path to the requested value.
- * @param mixed $default Default value (or null).
- * @param string $separator Separator, defaults to '.'
- * @return mixed Value.
- */
- public function get($name, $default = null, $separator = '.')
- {
- $path = explode($separator, $name);
- $current = $this->items;
- foreach ($path as $field) {
- if (is_object($current) && isset($current->{$field})) {
- $current = $current->{$field};
- } elseif (is_array($current) && isset($current[$field])) {
- $current = $current[$field];
- } else {
- return $default;
- }
- }
-
- return $current;
- }
-
- /**
- * Set value by using dot notation for nested arrays/objects.
- *
- * @example $value = $data->set('this.is.my.nested.variable', true);
- *
- * @param string $name Dot separated path to the requested value.
- * @param mixed $value New value.
- * @param string $separator Separator, defaults to '.'
- */
- public function set($name, $value, $separator = '.')
- {
- $path = explode($separator, $name);
- $current = &$this->items;
- foreach ($path as $field) {
- if (is_object($current)) {
- // Handle objects.
- if (!isset($current->{$field})) {
- $current->{$field} = array();
- }
- $current = &$current->{$field};
- } else {
- // Handle arrays and scalars.
- if (!is_array($current)) {
- $current = array($field => array());
- } elseif (!isset($current[$field])) {
- $current[$field] = array();
- }
- $current = &$current[$field];
- }
- }
-
- $current = $value;
- }
-
-}
diff --git a/src/system/src/Grav/Common/Data/Validation.php b/src/system/src/Grav/Common/Data/Validation.php
deleted file mode 100644
index 3382a72..0000000
--- a/src/system/src/Grav/Common/Data/Validation.php
+++ /dev/null
@@ -1,672 +0,0 @@
-translate($name) . '""';
-
- if (method_exists(__CLASS__, $method)) {
- $success = self::$method($value, $validate, $field);
- } else {
- $success = self::typeText($value, $validate, $field);
- }
- if (!$success) {
- throw new \RuntimeException($message);
- }
-
- // Check individual rules
- foreach ($validate as $rule => $params) {
- $method = 'validate'.strtr($rule, '-', '_');
- if (method_exists(__CLASS__, $method)) {
- $success = self::$method($value, $params);
-
- if (!$success) {
- throw new \RuntimeException($message);
- }
- }
- }
- }
-
- /**
- * Filter value against a blueprint field definition.
- *
- * @param mixed $value
- * @param array $field
- * @return mixed Filtered value.
- */
- public static function filter($value, array $field)
- {
- $validate = isset($field['validate']) ? (array) $field['validate'] : array();
-
- // If value isn't required, we will return null if empty value is given.
- if (empty($validate['required']) && ($value === null || $value === '')) {
- return null;
- }
-
- // if this is a YAML field, simply parse it and return the value
- if (isset($field['yaml']) && $field['yaml'] === true) {
- try {
- $yaml = new Parser();
- return $yaml->parse($value);
- } catch (ParseException $e) {
- throw new \RuntimeException($e->getMessage());
- }
- }
-
- // Validate type with fallback type text.
- $type = (string) isset($field['validate']['type']) ? $field['validate']['type'] : $field['type'];
- $method = 'filter'.strtr($type, '-', '_');
- if (method_exists(__CLASS__, $method)) {
- $value = self::$method($value, $validate, $field);
- } else {
- $value = self::filterText($value, $validate, $field);
- }
-
- return $value;
- }
-
- /**
- * HTML5 input: text
- *
- * @param mixed $value Value to be validated.
- * @param array $params Validation parameters.
- * @param array $field Blueprint for the field.
- * @return bool True if validation succeeded.
- */
- public static function typeText($value, array $params, array $field)
- {
- if (!is_string($value)) {
- return false;
- }
-
- if (isset($params['min']) && strlen($value) < $params['min']) {
- return false;
- }
-
- if (isset($params['max']) && strlen($value) > $params['max']) {
- return false;
- }
-
- $min = isset($params['min']) ? $params['min'] : 0;
- if (isset($params['step']) && (strlen($value) - $min) % $params['step'] == 0) {
- return false;
- }
-
- if ((!isset($params['multiline']) || !$params['multiline']) && preg_match('/\R/um', $value)) {
- return false;
- }
-
- return true;
- }
-
- protected static function filterText($value, array $params, array $field)
- {
- return (string) $value;
- }
-
- protected static function filterCommaList($value, array $params, array $field)
- {
- return is_array($value) ? $value : preg_split('/\s*,\s*/', $value, -1, PREG_SPLIT_NO_EMPTY);
- }
-
- protected static function typeCommaList($value, array $params, array $field)
- {
- return is_array($value) ? true : self::typeText($value, $params, $field);
- }
-
- /**
- * HTML5 input: textarea
- *
- * @param mixed $value Value to be validated.
- * @param array $params Validation parameters.
- * @param array $field Blueprint for the field.
- * @return bool True if validation succeeded.
- */
- public static function typeTextarea($value, array $params, array $field)
- {
- if (!isset($params['multiline'])) {
- $params['multiline'] = true;
- }
-
- return self::typeText($value, $params, $field);
- }
-
- /**
- * HTML5 input: password
- *
- * @param mixed $value Value to be validated.
- * @param array $params Validation parameters.
- * @param array $field Blueprint for the field.
- * @return bool True if validation succeeded.
- */
- public static function typePassword($value, array $params, array $field)
- {
- return self::typeText($value, $params, $field);
- }
-
- /**
- * HTML5 input: hidden
- *
- * @param mixed $value Value to be validated.
- * @param array $params Validation parameters.
- * @param array $field Blueprint for the field.
- * @return bool True if validation succeeded.
- */
- public static function typeHidden($value, array $params, array $field)
- {
- return self::typeText($value, $params, $field);
- }
-
- /**
- * Custom input: checkbox list
- *
- * @param mixed $value Value to be validated.
- * @param array $params Validation parameters.
- * @param array $field Blueprint for the field.
- * @return bool True if validation succeeded.
- */
- public static function typeCheckboxes($value, array $params, array $field)
- {
- return self::typeArray((array) $value, $params, $field);
- }
-
- protected static function filterCheckboxes($value, array $params, array $field)
- {
- return self::filterArray($value, $params, $field);
- }
-
- /**
- * HTML5 input: checkbox
- *
- * @param mixed $value Value to be validated.
- * @param array $params Validation parameters.
- * @param array $field Blueprint for the field.
- * @return bool True if validation succeeded.
- */
- public static function typeCheckbox($value, array $params, array $field)
- {
- $value = (string) $value;
-
- if (!isset($field['value'])) {
- $field['value'] = 1;
- }
- if ($value && $value != $field['value']) {
- return false;
- }
-
- return true;
- }
-
- /**
- * HTML5 input: radio
- *
- * @param mixed $value Value to be validated.
- * @param array $params Validation parameters.
- * @param array $field Blueprint for the field.
- * @return bool True if validation succeeded.
- */
- public static function typeRadio($value, array $params, array $field)
- {
- return self::typeArray((array) $value, $params, $field);
- }
-
- /**
- * Custom input: toggle
- *
- * @param mixed $value Value to be validated.
- * @param array $params Validation parameters.
- * @param array $field Blueprint for the field.
- * @return bool True if validation succeeded.
- */
- public static function typeToggle($value, array $params, array $field)
- {
- return self::typeArray((array) $value, $params, $field);
- }
-
- /**
- * HTML5 input: select
- *
- * @param mixed $value Value to be validated.
- * @param array $params Validation parameters.
- * @param array $field Blueprint for the field.
- * @return bool True if validation succeeded.
- */
- public static function typeSelect($value, array $params, array $field)
- {
- return self::typeArray((array) $value, $params, $field);
- }
-
- /**
- * HTML5 input: number
- *
- * @param mixed $value Value to be validated.
- * @param array $params Validation parameters.
- * @param array $field Blueprint for the field.
- * @return bool True if validation succeeded.
- */
-
- public static function typeNumber($value, array $params, array $field)
- {
- if (!is_numeric($value)) {
- return false;
- }
-
- if (isset($params['min']) && $value < $params['min']) {
- return false;
- }
-
- if (isset($params['max']) && $value > $params['max']) {
- return false;
- }
-
- $min = isset($params['min']) ? $params['min'] : 0;
- if (isset($params['step']) && fmod($value - $min, $params['step']) == 0) {
- return false;
- }
-
- return true;
- }
-
- protected static function filterNumber($value, array $params, array $field)
- {
- return (int) $value;
- }
-
- protected static function filterDateTime($value, array $params, array $field)
- {
- $format = self::getGrav()['config']->get('system.pages.dateformat.default');
- if ($format) {
- $converted = new \DateTime($value);
- return $converted->format($format);
- }
- return $value;
- }
-
-
- /**
- * HTML5 input: range
- *
- * @param mixed $value Value to be validated.
- * @param array $params Validation parameters.
- * @param array $field Blueprint for the field.
- * @return bool True if validation succeeded.
- */
- public static function typeRange($value, array $params, array $field)
- {
- return self::typeNumber($value, $params, $field);
- }
-
- protected static function filterRange($value, array $params, array $field)
- {
- return self::filterNumber($value, $params, $field);
- }
-
- /**
- * HTML5 input: color
- *
- * @param mixed $value Value to be validated.
- * @param array $params Validation parameters.
- * @param array $field Blueprint for the field.
- * @return bool True if validation succeeded.
- */
- public static function typeColor($value, array $params, array $field)
- {
- return preg_match('/^\#[0-9a-fA-F]{3}[0-9a-fA-F]{3}?$/u', $value);
- }
-
- /**
- * HTML5 input: email
- *
- * @param mixed $value Value to be validated.
- * @param array $params Validation parameters.
- * @param array $field Blueprint for the field.
- * @return bool True if validation succeeded.
- */
- public static function typeEmail($value, array $params, array $field)
- {
- return self::typeText($value, $params, $field) && filter_var($value, FILTER_VALIDATE_EMAIL);
- }
-
- /**
- * HTML5 input: url
- *
- * @param mixed $value Value to be validated.
- * @param array $params Validation parameters.
- * @param array $field Blueprint for the field.
- * @return bool True if validation succeeded.
- */
-
- public static function typeUrl($value, array $params, array $field)
- {
- return self::typeText($value, $params, $field) && filter_var($value, FILTER_VALIDATE_URL);
- }
-
- /**
- * HTML5 input: datetime
- *
- * @param mixed $value Value to be validated.
- * @param array $params Validation parameters.
- * @param array $field Blueprint for the field.
- * @return bool True if validation succeeded.
- */
- public static function typeDatetime($value, array $params, array $field)
- {
- if ($value instanceof \DateTime) {
- return true;
- } elseif (!is_string($value)) {
- return false;
- } elseif (!isset($params['format'])) {
- return false !== strtotime($value);
- }
-
- $dateFromFormat = \DateTime::createFromFormat($params['format'], $value);
-
- return $dateFromFormat && $value === date($params['format'], $dateFromFormat->getTimestamp());
- }
-
- /**
- * HTML5 input: datetime-local
- *
- * @param mixed $value Value to be validated.
- * @param array $params Validation parameters.
- * @param array $field Blueprint for the field.
- * @return bool True if validation succeeded.
- */
- public static function typeDatetimeLocal($value, array $params, array $field)
- {
- return self::typeDatetime($value, $params, $field);
- }
-
- /**
- * HTML5 input: date
- *
- * @param mixed $value Value to be validated.
- * @param array $params Validation parameters.
- * @param array $field Blueprint for the field.
- * @return bool True if validation succeeded.
- */
- public static function typeDate($value, array $params, array $field)
- {
- $params = array($params);
- if (!isset($params['format'])) {
- $params['format'] = 'Y-m-d';
- }
- return self::typeDatetime($value, $params, $field);
- }
-
- /**
- * HTML5 input: time
- *
- * @param mixed $value Value to be validated.
- * @param array $params Validation parameters.
- * @param array $field Blueprint for the field.
- * @return bool True if validation succeeded.
- */
- public static function typeTime($value, array $params, array $field)
- {
- $params = array($params);
- if (!isset($params['format'])) {
- $params['format'] = 'H:i';
- }
- return self::typeDatetime($value, $params, $field);
- }
-
- /**
- * HTML5 input: month
- *
- * @param mixed $value Value to be validated.
- * @param array $params Validation parameters.
- * @param array $field Blueprint for the field.
- * @return bool True if validation succeeded.
- */
- public static function typeMonth($value, array $params, array $field)
- {
- $params = array($params);
- if (!isset($params['format'])) {
- $params['format'] = 'Y-m';
- }
- return self::typeDatetime($value, $params, $field);
- }
-
- /**
- * HTML5 input: week
- *
- * @param mixed $value Value to be validated.
- * @param array $params Validation parameters.
- * @param array $field Blueprint for the field.
- * @return bool True if validation succeeded.
- */
- public static function typeWeek($value, array $params, array $field)
- {
- if (!isset($params['format']) && !preg_match('/^\d{4}-W\d{2}$/u', $value)) {
- return false;
- }
- return self::typeDatetime($value, $params, $field);
- }
-
- /**
- * Custom input: array
- *
- * @param mixed $value Value to be validated.
- * @param array $params Validation parameters.
- * @param array $field Blueprint for the field.
- * @return bool True if validation succeeded.
- */
- public static function typeArray($value, array $params, array $field)
- {
- if (!is_array($value)) {
- return false;
- }
-
- if (isset($field['multiple'])) {
- if (isset($params['min']) && count($value) < $params['min']) {
- return false;
- }
-
- if (isset($params['max']) && count($value) > $params['max']) {
- return false;
- }
-
- $min = isset($params['min']) ? $params['min'] : 0;
- if (isset($params['step']) && (count($value) - $min) % $params['step'] == 0) {
- return false;
- }
- }
-
- $options = isset($field['options']) ? array_keys($field['options']) : array();
- $values = isset($field['use']) && $field['use'] == 'keys' ? array_keys($value) : $value;
- if ($options && array_diff($values, $options)) {
- return false;
- }
-
- return true;
- }
-
- protected static function filterArray($value, $params, $field)
- {
- $values = (array) $value;
- $options = isset($field['options']) ? array_keys($field['options']) : array();
- $multi = isset($field['multiple']) ? $field['multiple'] : false;
-
- if ($options) {
- $useKey = isset($field['use']) && $field['use'] == 'keys';
- foreach ($values as $key => $value) {
- $values[$key] = $useKey ? (bool) $value : $value;
- }
- }
-
- if ($multi) {
- foreach ($values as $key => $value) {
- if (is_array($value)) {
- $value = implode(',', $value);
- }
-
- $values[$key] = array_map('trim', explode(',', $value));
- }
- }
-
- return $values;
- }
-
- public static function typeList($value, array $params, array $field)
- {
- if (!is_array($value)) {
- return false;
- }
-
- if (isset($field['fields'])) {
- foreach ($value as $key => $item) {
- foreach ($field['fields'] as $subKey => $subField) {
- $subKey = trim($subKey, '.');
- $subValue = isset($item[$subKey]) ? $item[$subKey] : null;
- self::validate($subValue, $subField);
- }
- }
- }
-
- return true;
- }
-
- protected static function filterList($value, array $params, array $field)
- {
- return (array) $value;
- }
-
- /**
- * Custom input: ignore (will not validate)
- *
- * @param mixed $value Value to be validated.
- * @param array $params Validation parameters.
- * @param array $field Blueprint for the field.
- * @return bool True if validation succeeded.
- */
- public static function typeIgnore($value, array $params, array $field)
- {
- return true;
- }
-
- public static function filterIgnore($value, array $params, array $field)
- {
- return $value;
- }
-
- // HTML5 attributes (min, max and range are handled inside the types)
-
- public static function validateRequired($value, $params)
- {
- if (is_string($value)) {
- $value = trim($value);
- }
-
- return (bool) $params !== true || !empty($value);
- }
-
- public static function validatePattern($value, $params)
- {
- return (bool) preg_match("`^{$params}$`u", $value);
- }
-
-
- // Internal types
-
- public static function validateAlpha($value, $params)
- {
- return ctype_alpha($value);
- }
-
- public static function validateAlnum($value, $params)
- {
- return ctype_alnum($value);
- }
-
- public static function typeBool($value, $params)
- {
- return is_bool($value) || $value == 1 || $value == 0;
- }
-
- public static function validateBool($value, $params)
- {
- return is_bool($value) || $value == 1 || $value == 0;
- }
-
- protected static function filterBool($value, $params)
- {
- return (bool) $value;
- }
-
- public static function validateDigit($value, $params)
- {
- return ctype_digit($value);
- }
-
- public static function validateFloat($value, $params)
- {
- return is_float(filter_var($value, FILTER_VALIDATE_FLOAT));
- }
-
- protected static function filterFloat($value, $params)
- {
- return (float) $value;
- }
-
- public static function validateHex($value, $params)
- {
- return ctype_xdigit($value);
- }
-
- public static function validateInt($value, $params)
- {
- return is_numeric($value) && (int) $value == $value;
- }
-
- protected static function filterInt($value, $params)
- {
- return (int) $value;
- }
-
- public static function validateArray($value, $params)
- {
- return is_array($value) || ($value instanceof \ArrayAccess
- && $value instanceof \Traversable
- && $value instanceof \Countable);
- }
-
- public static function validateJson($value, $params)
- {
- return (bool) (json_decode($value));
- }
-}
diff --git a/src/system/src/Grav/Common/Debugger.php b/src/system/src/Grav/Common/Debugger.php
deleted file mode 100644
index a996a7d..0000000
--- a/src/system/src/Grav/Common/Debugger.php
+++ /dev/null
@@ -1,121 +0,0 @@
-debugbar = new StandardDebugBar();
- $this->debugbar['time']->addMeasure('Loading', $this->debugbar['time']->getRequestStartTime(), microtime(true));
- }
-
- public function init()
- {
- $this->grav = Grav::instance();
-
- if ($this->enabled()) {
- $this->debugbar->addCollector(new \DebugBar\DataCollector\ConfigCollector((array)$this->grav['config']->get('system')));
- }
- return $this;
- }
-
- public function enabled($state = null)
- {
- if (isset($state)) {
- $this->enabled = $state;
- } else {
- if (!isset($this->enabled)) {
- $this->enabled = $this->grav['config']->get('system.debugger.enabled');
- }
- }
- return $this->enabled;
- }
-
- public function addAssets()
- {
- if ($this->enabled()) {
- $assets = $this->grav['assets'];
-
- // Add jquery library
- $assets->add('jquery', 101);
-
- $this->renderer = $this->debugbar->getJavascriptRenderer();
- $this->renderer->setIncludeVendors(false);
-
- // Get the required CSS files
- list($css_files, $js_files) = $this->renderer->getAssets(null, JavascriptRenderer::RELATIVE_URL);
- foreach ($css_files as $css) {
- $assets->addCss($css);
- }
-
- $assets->addCss('/system/assets/debugger.css');
-
- foreach ($js_files as $js) {
- $assets->addJs($js);
- }
- }
- return $this;
- }
-
- public function addCollector($collector)
- {
- $this->debugbar->addCollector($collector);
- return $this;
- }
-
- public function getCollector($collector)
- {
- return $this->debugbar->getCollector($collector);
- }
-
- public function render()
- {
- if ($this->enabled()) {
- echo $this->renderer->render();
- }
- return $this;
- }
-
- public function sendDataInHeaders()
- {
- $this->debugbar->sendDataInHeaders();
- return $this;
- }
-
- public function startTimer($name, $description = null)
- {
- if ($name[0] == '_' || $this->grav['config']->get('system.debugger.enabled')) {
- $this->debugbar['time']->startMeasure($name, $description);
- }
- return $this;
- }
-
- public function stopTimer($name)
- {
- if ($name[0] == '_' || $this->grav['config']->get('system.debugger.enabled')) {
- $this->debugbar['time']->stopMeasure($name);
- }
- return $this;
- }
-
-
- public function addMessage($message, $label = 'info', $isString = true)
- {
- if ($this->enabled()) {
- $this->debugbar['messages']->addMessage($message, $label, $isString);
- }
- return $this;
- }
-}
diff --git a/src/system/src/Grav/Common/Errors/Errors.php b/src/system/src/Grav/Common/Errors/Errors.php
deleted file mode 100644
index e135e6f..0000000
--- a/src/system/src/Grav/Common/Errors/Errors.php
+++ /dev/null
@@ -1,52 +0,0 @@
-handlerStack[$key] = $handler;
- } else {
- $this->handlerStack[] = $handler;
- }
-
- return $this;
- }
-
- public function resetHandlers()
- {
- $grav = Grav::instance();
- $config = $grav['config']->get('system.errors');
- if (isset($config['display']) && !$config['display']) {
- unset($this->handlerStack['pretty']);
- $this->handlerStack = array('simple' => new SimplePageHandler()) + $this->handlerStack;
- }
- if (isset($config['log']) && !$config['log']) {
- unset($this->handlerStack['log']);
- }
- }
-
-}
diff --git a/src/system/src/Grav/Common/Errors/Resources/error.css b/src/system/src/Grav/Common/Errors/Resources/error.css
deleted file mode 100644
index 11ce3fd..0000000
--- a/src/system/src/Grav/Common/Errors/Resources/error.css
+++ /dev/null
@@ -1,52 +0,0 @@
-html, body {
- height: 100%
-}
-body {
- margin:0 3rem;
- padding:0;
- font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
- font-size: 1.5rem;
- line-height: 1.4;
- display: -webkit-box; /* OLD - iOS 6-, Safari 3.1-6 */
- display: -moz-box; /* OLD - Firefox 19- (buggy but mostly works) */
- display: -ms-flexbox; /* TWEENER - IE 10 */
- display: -webkit-flex; /* NEW - Chrome */
- display: flex;
- -webkit-align-items: center;
- align-items: center;
- -webkit-justify-content: center;
- justify-content: center;
-}
-.container {
- margin: 0rem;
- max-width: 600px;
- padding-bottom:5rem;
-}
-
-header {
- color: #000;
- font-size: 4rem;
- letter-spacing: 2px;
- line-height: 1.1;
- margin-bottom: 2rem;
-}
-p {
- font-family: Optima, Segoe, "Segoe UI", Candara, Calibri, Arial, sans-serif;
- color: #666;
-}
-
-h5 {
- font-weight: normal;
- color: #999;
- font-size: 1rem;
-}
-
-h6 {
- font-weight: normal;
- color: #999;
-}
-
-code {
- font-weight: bold;
- font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
-}
diff --git a/src/system/src/Grav/Common/Errors/Resources/layout.html.php b/src/system/src/Grav/Common/Errors/Resources/layout.html.php
deleted file mode 100644
index 6699959..0000000
--- a/src/system/src/Grav/Common/Errors/Resources/layout.html.php
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
-
- Whoops there was an error!
-
-
-
-
-
-
- Server Error
-
-
-
-
-
Sorry, something went terribly wrong!
-
-
-
-
-
For further details please review your logs/ folder, or enable displaying of errors in your system configuration.
-
-
-
-
diff --git a/src/system/src/Grav/Common/Errors/SimplePageHandler.php b/src/system/src/Grav/Common/Errors/SimplePageHandler.php
deleted file mode 100644
index 16d0a88..0000000
--- a/src/system/src/Grav/Common/Errors/SimplePageHandler.php
+++ /dev/null
@@ -1,96 +0,0 @@
-searchPaths[] = __DIR__ . "/Resources";
- }
-
- /**
- * @return int|null
- */
- public function handle()
- {
- $inspector = $this->getInspector();
-
- $helper = new TemplateHelper();
- $templateFile = $this->getResource("layout.html.php");
- $cssFile = $this->getResource("error.css");
-
- $code = $inspector->getException()->getCode();
- $message = $inspector->getException()->getMessage();
-
- if ($inspector->getException() instanceof \ErrorException) {
- $code = Misc::translateErrorCode($code);
- }
-
- $vars = array(
- "stylesheet" => file_get_contents($cssFile),
- "code" => $code,
- "message" => $message,
- );
-
- $helper->setVariables($vars);
- $helper->render($templateFile);
-
- return Handler::QUIT;
- }
-
- /**
- * @param $resource
- *
- * @return string
- */
- protected function getResource($resource)
- {
- // If the resource was found before, we can speed things up
- // by caching its absolute, resolved path:
- if (isset($this->resourceCache[$resource])) {
- return $this->resourceCache[$resource];
- }
-
- // Search through available search paths, until we find the
- // resource we're after:
- foreach ($this->searchPaths as $path) {
- $fullPath = $path . "/$resource";
-
- if (is_file($fullPath)) {
- // Cache the result:
- $this->resourceCache[$resource] = $fullPath;
- return $fullPath;
- }
- }
-
- // If we got this far, nothing was found.
- throw new \RuntimeException(
- "Could not find resource '$resource' in any resource paths."
- . "(searched: " . join(", ", $this->searchPaths). ")"
- );
- }
-
- public function addResourcePath($path)
- {
- if (!is_dir($path)) {
- throw new \InvalidArgumentException(
- "'$path' is not a valid directory"
- );
- }
-
- array_unshift($this->searchPaths, $path);
- }
-
- public function getResourcePaths()
- {
- return $this->searchPaths;
- }
-}
diff --git a/src/system/src/Grav/Common/File/CompiledFile.php b/src/system/src/Grav/Common/File/CompiledFile.php
deleted file mode 100644
index 7120c9c..0000000
--- a/src/system/src/Grav/Common/File/CompiledFile.php
+++ /dev/null
@@ -1,73 +0,0 @@
-settings(['native' => true, 'compat' => true]);
-
- // If nothing has been loaded, attempt to get pre-compiled version of the file first.
- if ($var === null && $this->raw === null && $this->content === null) {
- $key = md5($this->filename);
- $file = PhpFile::instance(CACHE_DIR . "compiled/files/{$key}{$this->extension}.php");
- $modified = $this->modified();
-
- if (!$modified) {
- return $this->decode($this->raw());
- }
-
- $class = get_class($this);
-
- $cache = $file->exists() ? $file->content() : null;
-
- // Load real file if cache isn't up to date (or is invalid).
- if (
- !isset($cache['@class'])
- || $cache['@class'] != $class
- || $cache['modified'] != $modified
- || $cache['filename'] != $this->filename
- ) {
- // Attempt to lock the file for writing.
- $file->lock(false);
-
- // Decode RAW file into compiled array.
- $data = (array) $this->decode($this->raw());
- $cache = [
- '@class' => $class,
- 'filename' => $this->filename,
- 'modified' => $modified,
- 'data' => $data
- ];
-
- // If compiled file wasn't already locked by another process, save it.
- if ($file->locked() !== false) {
- $file->save($cache);
- $file->unlock();
- }
- }
-
- $this->content = $cache['data'];
- }
-
- return parent::content($var);
- }
-}
diff --git a/src/system/src/Grav/Common/File/CompiledMarkdownFile.php b/src/system/src/Grav/Common/File/CompiledMarkdownFile.php
deleted file mode 100644
index 669a4eb..0000000
--- a/src/system/src/Grav/Common/File/CompiledMarkdownFile.php
+++ /dev/null
@@ -1,9 +0,0 @@
-getMTime();
- if ($dir_modified > $last_modified) {
- $last_modified = $dir_modified;
- }
- }
-
- return $last_modified;
- }
-
- /**
- * Recursively find the last modified time under given path by file.
- *
- * @param string $path
- * @param string $extensions which files to search for specifically
- *
- * @return int
- */
- public static function lastModifiedFile($path, $extensions = 'md|yaml')
- {
- $last_modified = 0;
-
- $dirItr = new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS);
- $itrItr = new \RecursiveIteratorIterator($dirItr, \RecursiveIteratorIterator::SELF_FIRST);
- $itr = new \RegexIterator($itrItr, '/^.+\.'.$extensions.'$/i');
-
- /** @var \RecursiveDirectoryIterator $file */
- foreach ($itr as $filepath => $file) {
- $file_modified = $file->getMTime();
- if ($file_modified > $last_modified) {
- $last_modified = $file_modified;
- }
- }
-
- return $last_modified;
- }
-
- /**
- * Get relative path between target and base path. If path isn't relative, return full path.
- *
- * @param string $path
- * @param string $base
- * @return string
- */
- public static function getRelativePath($path, $base = GRAV_ROOT)
- {
- if ($base) {
- $base = preg_replace('![\\\/]+!', '/', $base);
- $path = preg_replace('![\\\/]+!', '/', $path);
- if (strpos($path, $base) === 0) {
- $path = ltrim(substr($path, strlen($base)), '/');
- }
- }
-
- return $path;
- }
-
- /**
- * Shift first directory out of the path.
- *
- * @param string $path
- * @return string
- */
- public static function shift(&$path)
- {
- $parts = explode('/', trim($path, '/'), 2);
- $result = array_shift($parts);
- $path = array_shift($parts);
-
- return $result ?: null;
- }
-
-
-
- /**
- * Return recursive list of all files and directories under given path.
- *
- * @param string $path
- * @param array $params
- * @return array
- * @throws \RuntimeException
- */
- public static function all($path, array $params = array())
- {
- if ($path === false) {
- throw new \RuntimeException("Path to {$path} doesn't exist.");
- }
-
- $compare = isset($params['compare']) ? 'get' . $params['compare'] : null;
- $pattern = isset($params['pattern']) ? $params['pattern'] : null;
- $filters = isset($params['filters']) ? $params['filters'] : null;
- $recursive = isset($params['recursive']) ? $params['recursive'] : true;
- $key = isset($params['key']) ? 'get' . $params['key'] : null;
- $value = isset($params['value']) ? 'get' . $params['value'] : ($recursive ? 'getSubPathname' : 'getFilename');
-
- if ($recursive) {
- $directory = new \RecursiveDirectoryIterator($path,
- \RecursiveDirectoryIterator::SKIP_DOTS + \FilesystemIterator::UNIX_PATHS + \FilesystemIterator::CURRENT_AS_SELF);
- $iterator = new \RecursiveIteratorIterator($directory, \RecursiveIteratorIterator::SELF_FIRST);
- } else {
- $iterator = new \FilesystemIterator($path);
- }
-
- $results = array();
-
- /** @var \RecursiveDirectoryIterator $file */
- foreach ($iterator as $file) {
- if ($compare && $pattern && !preg_match($pattern, $file->{$compare}())) {
- continue;
- }
- $fileKey = $key ? $file->{$key}() : null;
- $filePath = $file->{$value}();
- if ($filters) {
- if (isset($filters['key'])) {
- $fileKey = preg_replace($filters['key'], '', $fileKey);
- }
- if (isset($filters['value'])) {
- $filter = $filters['value'];
- if (is_callable($filter)) {
- $filePath = call_user_func($filter, $file);
- } else {
- $filePath = preg_replace($filter, '', $filePath);
- }
- }
- }
-
- if ($fileKey !== null) {
- $results[$fileKey] = $filePath;
- } else {
- $results[] = $filePath;
- }
- }
-
- return $results;
- }
-
- /**
- * Recursively copy directory in filesystem.
- *
- * @param string $source
- * @param string $target
- * @throws \RuntimeException
- */
- public static function copy($source, $target)
- {
- $source = rtrim($source, '\\/');
- $target = rtrim($target, '\\/');
-
- if (!is_dir($source)) {
- throw new \RuntimeException('Cannot copy non-existing folder.');
- }
-
- // Make sure that path to the target exists before copying.
- self::mkdir($target);
-
- $success = true;
-
- // Go through all sub-directories and copy everything.
- $files = self::all($source);
- foreach ($files as $file) {
- $src = $source .'/'. $file;
- $dst = $target .'/'. $file;
-
- if (is_dir($src)) {
- // Create current directory.
- $success &= @mkdir($dst);
- } else {
- // Or copy current file.
- $success &= @copy($src, $dst);
- }
- }
-
- if (!$success) {
- $error = error_get_last();
- throw new \RuntimeException($error['message']);
- }
-
- // Make sure that the change will be detected when caching.
- @touch(dirname($target));
- }
-
- /**
- * Move directory in filesystem.
- *
- * @param string $source
- * @param string $target
- * @throws \RuntimeException
- */
- public static function move($source, $target)
- {
- if (!is_dir($source)) {
- throw new \RuntimeException('Cannot move non-existing folder.');
- }
-
- // Make sure that path to the target exists before moving.
- self::mkdir(dirname($target));
-
- // Just rename the directory.
- $success = @rename($source, $target);
-
- if (!$success) {
- $error = error_get_last();
- throw new \RuntimeException($error['message']);
- }
-
- // Make sure that the change will be detected when caching.
- @touch(dirname($source));
- @touch(dirname($target));
- }
-
- /**
- * Recursively delete directory from filesystem.
- *
- * @param string $target
- * @throws \RuntimeException
- * @return bool
- */
- public static function delete($target)
- {
- if (!is_dir($target)) {
- return;
- }
-
- $success = self::doDelete($target);
-
- if (!$success) {
- $error = error_get_last();
- throw new \RuntimeException($error['message']);
- }
-
- // Make sure that the change will be detected when caching.
- @touch(dirname($target));
- return $success;
- }
-
- /**
- * @param string $folder
- * @throws \RuntimeException
- * @internal
- */
- public static function mkdir($folder)
- {
- if (is_dir($folder)) {
- return;
- }
-
- $success = @mkdir($folder, 0777, true);
-
- if (!$success) {
- $error = error_get_last();
- throw new \RuntimeException($error['message']);
- }
- }
-
- /**
- * Recursive copy of one directory to another
- *
- * @param $src
- * @param $dest
- *
- * @return bool
- */
- public static function rcopy($src, $dest)
- {
-
- // If the src is not a directory do a simple file copy
- if (!is_dir($src)) {
- copy($src, $dest);
- return true;
- }
-
- // If the destination directory does not exist create it
- if (!is_dir($dest)) {
- if (!mkdir($dest)) {
- // If the destination directory could not be created stop processing
- return false;
- }
- }
-
- // Open the source directory to read in files
- $i = new \DirectoryIterator($src);
- /** @var \DirectoryIterator $f */
- foreach ($i as $f) {
- if ($f->isFile()) {
- copy($f->getRealPath(), "$dest/" . $f->getFilename());
- } else {
- if (!$f->isDot() && $f->isDir()) {
- static::rcopy($f->getRealPath(), "$dest/$f");
- }
- }
- }
- return true;
- }
-
- /**
- * @param string $folder
- * @return bool
- * @internal
- */
- protected static function doDelete($folder)
- {
- // Special case for symbolic links.
- if (is_link($folder)) {
- return @unlink($folder);
- }
-
- $files = new \RecursiveIteratorIterator(
- new \RecursiveDirectoryIterator($folder, \RecursiveDirectoryIterator::SKIP_DOTS),
- \RecursiveIteratorIterator::CHILD_FIRST
- );
-
- /** @var \DirectoryIterator $fileinfo */
- foreach ($files as $fileinfo) {
- if ($fileinfo->isDir()) {
- if (false === rmdir($fileinfo->getRealPath())) {
- return false;
- }
- } else {
- if (false === unlink($fileinfo->getRealPath())) {
- return false;
- }
- }
- }
-
- return rmdir($folder);
- }
-}
diff --git a/src/system/src/Grav/Common/Filesystem/RecursiveFolderFilterIterator.php b/src/system/src/Grav/Common/Filesystem/RecursiveFolderFilterIterator.php
deleted file mode 100644
index aa9fd4a..0000000
--- a/src/system/src/Grav/Common/Filesystem/RecursiveFolderFilterIterator.php
+++ /dev/null
@@ -1,31 +0,0 @@
-get('system.pages.ignore_folders');
- }
- }
-
- public function accept()
- {
-
- /** @var $current \SplFileInfo */
- $current = $this->current();
-
- if ($current->isDir() && !in_array($current->getFilename(), $this::$folder_ignores)) {
- return true;
- }
- return false;
- }
-}
diff --git a/src/system/src/Grav/Common/GPM/AbstractCollection.php b/src/system/src/Grav/Common/GPM/AbstractCollection.php
deleted file mode 100644
index 7c1974d..0000000
--- a/src/system/src/Grav/Common/GPM/AbstractCollection.php
+++ /dev/null
@@ -1,32 +0,0 @@
-items as $name => $package) {
- $items[$name] = $package->toArray();
- }
-
- return json_encode($items);
- }
-
- public function toArray()
- {
- $items = [];
-
- foreach ($this->items as $name => $package) {
- $items[$name] = $package->toArray();
- }
-
- return $items;
- }
-}
diff --git a/src/system/src/Grav/Common/GPM/Common/AbstractPackageCollection.php b/src/system/src/Grav/Common/GPM/Common/AbstractPackageCollection.php
deleted file mode 100644
index 46c9e89..0000000
--- a/src/system/src/Grav/Common/GPM/Common/AbstractPackageCollection.php
+++ /dev/null
@@ -1,34 +0,0 @@
-items as $name => $package) {
- $items[$name] = $package->toArray();
- }
-
- return json_encode($items);
- }
-
- public function toArray()
- {
- $items = [];
-
- foreach ($this->items as $name => $package) {
- $items[$name] = $package->toArray();
- }
-
- return $items;
- }
-}
diff --git a/src/system/src/Grav/Common/GPM/Common/CachedCollection.php b/src/system/src/Grav/Common/GPM/Common/CachedCollection.php
deleted file mode 100644
index fd6ae94..0000000
--- a/src/system/src/Grav/Common/GPM/Common/CachedCollection.php
+++ /dev/null
@@ -1,21 +0,0 @@
- $item) {
- $this->append([$name => $item]);
- }
- }
-}
diff --git a/src/system/src/Grav/Common/GPM/Common/Package.php b/src/system/src/Grav/Common/GPM/Common/Package.php
deleted file mode 100644
index ff9a087..0000000
--- a/src/system/src/Grav/Common/GPM/Common/Package.php
+++ /dev/null
@@ -1,42 +0,0 @@
-data = $package;
-
- if ($type) {
- $this->data->set('package_type', $type);
- }
- }
-
- public function getData() {
- return $this->data;
- }
-
- public function __get($key) {
- return $this->data->get($key);
- }
-
- public function __isset($key) {
- return isset($this->data->$key);
- }
-
- public function __toString() {
- return $this->toJson();
- }
-
- public function toJson() {
- return $this->data->toJson();
- }
-
- public function toArray() {
- return $this->data->toArray();
- }
-
-}
diff --git a/src/system/src/Grav/Common/GPM/GPM.php b/src/system/src/Grav/Common/GPM/GPM.php
deleted file mode 100644
index fa1c808..0000000
--- a/src/system/src/Grav/Common/GPM/GPM.php
+++ /dev/null
@@ -1,398 +0,0 @@
- 'user/plugins/%name%', 'themes' => 'user/themes/%name%', 'skeletons' => 'user/'];
-
- /**
- * Creates a new GPM instance with Local and Remote packages available
- * @param boolean $refresh Applies to Remote Packages only and forces a refetch of data
- * @param callable $callback Either a function or callback in array notation
- */
- public function __construct($refresh = false, $callback = null)
- {
- $this->installed = new Local\Packages();
- try {
- $this->repository = new Remote\Packages($refresh, $callback);
- $this->grav = new Remote\Grav($refresh, $callback);
- } catch (\Exception $e) {
- }
- }
-
- /**
- * Returns the Locally installed packages
- * @return Iterator The installed packages
- */
- public function getInstalled()
- {
- return $this->installed;
- }
-
- /**
- * Returns the amount of locally installed packages
- * @return integer Amount of installed packages
- */
- public function countInstalled()
- {
- $installed = $this->getInstalled();
-
- return count($installed['plugins']) + count($installed['themes']);
- }
-
- /**
- * Return the instance of a specific Plugin
- * @param string $slug The slug of the Plugin
- * @return Local\Package The instance of the Plugin
- */
- public function getInstalledPlugin($slug)
- {
- return $this->installed['plugins'][$slug];
- }
-
- /**
- * Returns the Locally installed plugins
- * @return Iterator The installed plugins
- */
- public function getInstalledPlugins()
- {
- return $this->installed['plugins'];
- }
-
- /**
- * Checks if a Plugin is installed
- * @param string $slug The slug of the Plugin
- * @return boolean True if the Plugin has been installed. False otherwise
- */
- public function isPluginInstalled($slug)
- {
- return isset($this->installed['plugins'][$slug]);
- }
-
- /**
- * Return the instance of a specific Theme
- * @param string $slug The slug of the Theme
- * @return Local\Package The instance of the Theme
- */
- public function getInstalledTheme($slug)
- {
- return $this->installed['themes'][$slug];
- }
-
- /**
- * Returns the Locally installed themes
- * @return Iterator The installed themes
- */
- public function getInstalledThemes()
- {
- return $this->installed['themes'];
- }
-
- /**
- * Checks if a Theme is installed
- * @param string $slug The slug of the Theme
- * @return boolean True if the Theme has been installed. False otherwise
- */
- public function isThemeInstalled($slug)
- {
- return isset($this->installed['themes'][$slug]);
- }
-
- /**
- * Returns the amount of updates available
- * @return integer Amount of available updates
- */
- public function countUpdates()
- {
- $count = 0;
-
- $count += count($this->getUpdatablePlugins());
- $count += count($this->getUpdatableThemes());
-
- return $count;
- }
-
- /**
- * Returns an array of Plugins and Themes that can be updated.
- * Plugins and Themes are extended with the `available` property that relies to the remote version
- * @return array Array of updatable Plugins and Themes.
- * Format: ['total' => int, 'plugins' => array, 'themes' => array]
- */
- public function getUpdatable()
- {
- $plugins = $this->getUpdatablePlugins();
- $themes = $this->getUpdatableThemes();
-
- $items = [
- 'total' => count($plugins)+count($themes),
- 'plugins' => $plugins,
- 'themes' => $themes
- ];
-
- return $items;
- }
-
- /**
- * Returns an array of Plugins that can be updated.
- * The Plugins are extended with the `available` property that relies to the remote version
- * @return Iterator Array of updatable Plugins
- */
- public function getUpdatablePlugins()
- {
- $items = [];
- $repository = $this->repository['plugins'];
-
- // local cache to speed things up
- if (isset($this->cache[__METHOD__])) {
- return $this->cache[__METHOD__];
- }
-
- foreach ($this->installed['plugins'] as $slug => $plugin) {
- if (!isset($repository[$slug]) || $plugin->symlink) {
- continue;
- }
-
- $local_version = $plugin->version ? $plugin->version : 'Unknown';
- $remote_version = $repository[$slug]->version;
-
- if (version_compare($local_version, $remote_version) < 0) {
- $repository[$slug]->available = $remote_version;
- $repository[$slug]->version = $local_version;
- $items[$slug] = $repository[$slug];
- }
- }
-
- $this->cache[__METHOD__] = $items;
-
- return $items;
- }
-
- /**
- * Check if a Plugin or Theme is updatable
- * @param string $slug The slug of the package
- * @return boolean True if updatable. False otherwise or if not found
- */
- public function isUpdatable($slug)
- {
- return $this->isPluginUpdatable($slug) || $this->isThemeUpdatable($slug);
- }
-
- /**
- * Checks if a Plugin is updatable
- * @param string $plugin The slug of the Plugin
- * @return boolean True if the Plugin is updatable. False otherwise
- */
- public function isPluginUpdatable($plugin)
- {
- return array_key_exists($plugin, (array) $this->getUpdatablePlugins());
- }
-
- /**
- * Returns an array of Themes that can be updated.
- * The Themes are extended with the `available` property that relies to the remote version
- * @return Iterator Array of updatable Themes
- */
- public function getUpdatableThemes()
- {
- $items = [];
- $repository = $this->repository['themes'];
-
- // local cache to speed things up
- if (isset($this->cache[__METHOD__])) {
- return $this->cache[__METHOD__];
- }
-
- foreach ($this->installed['themes'] as $slug => $plugin) {
- if (!isset($repository[$slug]) || $plugin->symlink) {
- continue;
- }
-
- $local_version = $plugin->version ? $plugin->version : 'Unknown';
- $remote_version = $repository[$slug]->version;
-
- if (version_compare($local_version, $remote_version) < 0) {
- $repository[$slug]->available = $remote_version;
- $repository[$slug]->version = $local_version;
- $items[$slug] = $repository[$slug];
- }
- }
-
- $this->cache[__METHOD__] = $items;
-
- return $items;
- }
-
- /**
- * Checks if a Theme is Updatable
- * @param string $theme The slug of the Theme
- * @return boolean True if the Theme is updatable. False otherwise
- */
- public function isThemeUpdatable($theme)
- {
- return array_key_exists($theme, (array) $this->getUpdatableThemes());
- }
-
- /**
- * Returns a Plugin from the repository
- * @param string $slug The slug of the Plugin
- * @return mixed Package if found, NULL if not
- */
- public function getRepositoryPlugin($slug)
- {
- return @$this->repository['plugins'][$slug];
- }
-
- /**
- * Returns the list of Plugins available in the repository
- * @return Iterator The Plugins remotely available
- */
- public function getRepositoryPlugins()
- {
- return $this->repository['plugins'];
- }
-
- /**
- * Returns a Theme from the repository
- * @param string $slug The slug of the Theme
- * @return mixed Package if found, NULL if not
- */
- public function getRepositoryTheme($slug)
- {
- return @$this->repository['themes'][$slug];
- }
-
- /**
- * Returns the list of Themes available in the repository
- * @return Iterator The Themes remotely available
- */
- public function getRepositoryThemes()
- {
- return $this->repository['themes'];
- }
-
- /**
- * Returns the list of Plugins and Themes available in the repository
- * @return array Array of available Plugins and Themes
- * Format: ['plugins' => array, 'themes' => array]
- */
- public function getRepository()
- {
- return $this->repository;
- }
-
- /**
- * Searches for a Package in the repository
- * @param string $search Can be either the slug or the name
- * @return Remote\Package Package if found, FALSE if not
- */
- public function findPackage($search)
- {
- $search = strtolower($search);
- if ($found = $this->getRepositoryTheme($search)) {
- return $found;
- }
-
- if ($found = $this->getRepositoryPlugin($search)) {
- return $found;
- }
-
- foreach ($this->getRepositoryThemes() as $slug => $theme) {
- if ($search == $slug || $search == $theme->name) {
- return $theme;
- }
- }
-
- foreach ($this->getRepositoryPlugins() as $slug => $plugin) {
- if ($search == $slug || $search == $plugin->name) {
- return $plugin;
- }
- }
-
- return false;
- }
-
- /**
- * Returns the list of Plugins and Themes available in the repository
- * @return array Array of available Plugins and Themes
- * Format: ['plugins' => array, 'themes' => array]
- */
- /**
- * Searches for a list of Packages in the repository
- * @param array $searches An array of either slugs or names
- * @return array Array of found Packages
- * Format: ['total' => int, 'not_found' => array, ]
- */
- public function findPackages($searches = [])
- {
- $packages = ['total' => 0, 'not_found' => []];
- $inflector = new Inflector();
-
- foreach ($searches as $search) {
- $repository = '';
- // if this is an object, get the search data from the key
- if (is_object($search)) {
- $search = (array) $search;
- $key = key($search);
- $repository = $search[$key];
- $search = $key;
- }
-
- if ($found = $this->findPackage($search)) {
- // set override repository if provided
- if ($repository) {
- $found->override_repository = $repository;
- }
- if (!isset($packages[$found->package_type])) {
- $packages[$found->package_type] = [];
- }
-
- $packages[$found->package_type][$found->slug] = $found;
- $packages['total']++;
- } else {
- // make a best guess at the type based on the repo URL
- if (Utils::contains($repository, '-theme')) {
- $type = 'themes';
- } else {
- $type = 'plugins';
- }
-
- $not_found = new \stdClass();
- $not_found->name = $inflector->camelize($search);
- $not_found->slug = $search;
- $not_found->package_type = $type;
- $not_found->install_path = str_replace('%name%', $search, $this->install_paths[$type]);
- $not_found->override_repository = $repository;
- $packages['not_found'][$search] = $not_found;
- }
- }
-
- return $packages;
- }
-}
diff --git a/src/system/src/Grav/Common/GPM/Installer.php b/src/system/src/Grav/Common/GPM/Installer.php
deleted file mode 100644
index ee9db48..0000000
--- a/src/system/src/Grav/Common/GPM/Installer.php
+++ /dev/null
@@ -1,343 +0,0 @@
- true,
- 'ignore_symlinks' => true,
- 'sophisticated' => false,
- 'theme' => false,
- 'install_path' => '',
- 'exclude_checks' => [self::EXISTS, self::NOT_FOUND, self::IS_LINK]
- ];
-
- /**
- * Installs a given package to a given destination.
- *
- * @param string $package The local path to the ZIP package
- * @param string $destination The local path to the Grav Instance
- * @param array $options Options to use for installing. ie, ['install_path' => 'user/themes/antimatter']
- *
- * @return boolean True if everything went fine, False otherwise.
- */
- public static function install($package, $destination, $options = [])
- {
- $destination = rtrim($destination, DS);
- $options = array_merge(self::$options, $options);
- $install_path = rtrim($destination . DS . ltrim($options['install_path'], DS), DS);
-
- if (!self::isGravInstance($destination) || !self::isValidDestination($install_path, $options['exclude_checks'])) {
- return false;
- }
-
- if (self::lastErrorCode() == self::IS_LINK && $options['ignore_symlinks'] ||
- self::lastErrorCode() == self::EXISTS && !$options['overwrite']) {
- return false;
- }
-
- // Pre install checks
- static::flightProcessing('pre_install', $install_path);
-
- $zip = new \ZipArchive();
- $archive = $zip->open($package);
- $tmp = CACHE_DIR . 'tmp/Grav-' . uniqid();
-
- if ($archive !== true) {
- self::$error = self::ZIP_OPEN_ERROR;
-
- return false;
- }
-
- Folder::mkdir($tmp);
-
- $unzip = $zip->extractTo($tmp);
-
- if (!$unzip) {
- self::$error = self::ZIP_EXTRACT_ERROR;
-
- $zip->close();
- Folder::delete($tmp);
-
- return false;
- }
-
-
- if (!$options['sophisticated']) {
- if ($options['theme']) {
- self::copyInstall($zip, $install_path, $tmp);
- } else {
- self::moveInstall($zip, $install_path, $tmp);
- }
- } else {
- self::sophisticatedInstall($zip, $install_path, $tmp);
- }
-
- Folder::delete($tmp);
- $zip->close();
-
- // Post install checks
- static::flightProcessing('post_install', $install_path);
-
- self::$error = self::OK;
-
- return true;
-
- }
-
- protected static function flightProcessing($state, $install_path)
- {
- $blueprints_path = $install_path . DS . 'blueprints.yaml';
-
- if (file_exists($blueprints_path)) {
- $package_yaml = Yaml::parse(file_get_contents($blueprints_path));
- if (isset($package_yaml['install'][$state]['create'])) {
- foreach ((array) $package_yaml['install']['pre_install']['create'] as $file) {
- Folder::mkdir($install_path . '/' . ltrim($file, '/'));
- }
- }
- if (isset($package_yaml['install'][$state]['remove'])) {
- foreach ((array) $package_yaml['install']['pre_install']['remove'] as $file) {
- Folder::delete($install_path . '/' . ltrim($file, '/'));
- }
- }
- }
- }
-
- public static function moveInstall(\ZipArchive $zip, $install_path, $tmp)
- {
- $container = $zip->getNameIndex(0);
- if (file_exists($install_path)) {
- Folder::delete($install_path);
- }
-
- Folder::move($tmp . DS . $container, $install_path);
-
- return true;
- }
-
- public static function copyInstall(\ZipArchive $zip, $install_path, $tmp)
- {
- $firstDir = $zip->getNameIndex(0);
- if (empty($firstDir)) {
- throw new \RuntimeException("Directory $firstDir is missing");
- } else {
- $tmp = realpath($tmp . DS . $firstDir);
- Folder::rcopy($tmp, $install_path);
- }
-
- return true;
- }
-
- public static function sophisticatedInstall(\ZipArchive $zip, $install_path, $tmp)
- {
- for ($i = 0, $l = $zip->numFiles; $i < $l; $i++) {
- $filename = $zip->getNameIndex($i);
- $fileinfo = pathinfo($filename);
- $depth = count(explode(DS, rtrim($filename, '/')));
-
- if ($depth > 2) {
- continue;
- }
-
- $path = $install_path . DS . $fileinfo['basename'];
-
- if (is_link($path)) {
- continue;
- } else {
- if (is_dir($path)) {
- Folder::delete($path);
- Folder::move($tmp . DS . $filename, $path);
-
- if ($fileinfo['basename'] == 'bin') {
- foreach (glob($path . DS . '*') as $file) {
- @chmod($file, 0755);
- }
- }
- } else {
- @unlink($path);
- @copy($tmp . DS . $filename, $path);
- }
- }
- }
-
- return true;
- }
-
- /**
- * Uninstalls one or more given package
- *
- * @param string $path The slug of the package(s)
- * @param array $options Options to use for uninstalling
- *
- * @return boolean True if everything went fine, False otherwise.
- */
- public static function uninstall($path, $options = [])
- {
- $options = array_merge(self::$options, $options);
- if (!self::isValidDestination($path, $options['exclude_checks'])
- ) {
- return false;
- }
-
- return Folder::delete($path);
- }
-
- /**
- * Runs a set of checks on the destination and sets the Error if any
- *
- * @param string $destination The directory to run validations at
- * @param array $exclude An array of constants to exclude from the validation
- *
- * @return boolean True if validation passed. False otherwise
- */
- public static function isValidDestination($destination, $exclude = [])
- {
- self::$error = 0;
- self::$target = $destination;
-
- if (is_link($destination)) {
- self::$error = self::IS_LINK;
- } elseif (file_exists($destination)) {
- self::$error = self::EXISTS;
- } elseif (!file_exists($destination)) {
- self::$error = self::NOT_FOUND;
- } elseif (!is_dir($destination)) {
- self::$error = self::NOT_DIRECTORY;
- }
-
- if (count($exclude) && in_array(self::$error, $exclude)) {
- return true;
- }
-
- return !(self::$error);
- }
-
- /**
- * Validates if the given path is a Grav Instance
- *
- * @param string $target The local path to the Grav Instance
- *
- * @return boolean True if is a Grav Instance. False otherwise
- */
- public static function isGravInstance($target)
- {
- self::$error = 0;
- self::$target = $target;
-
- if (
- !file_exists($target . DS . 'index.php') ||
- !file_exists($target . DS . 'bin') ||
- !file_exists($target . DS . 'user') ||
- !file_exists($target . DS . 'system' . DS . 'config' . DS . 'system.yaml')
- ) {
- self::$error = self::NOT_GRAV_ROOT;
- }
-
- return !self::$error;
- }
-
- /**
- * Returns the last error occurred in a string message format
- * @return string The message of the last error
- */
- public static function lastErrorMsg()
- {
- $msg = 'Unknown Error';
-
- switch (self::$error) {
- case 0:
- $msg = 'No Error';
- break;
-
- case self::EXISTS:
- $msg = 'The target path "' . self::$target . '" already exists';
- break;
-
- case self::IS_LINK:
- $msg = 'The target path "' . self::$target . '" is a symbolic link';
- break;
-
- case self::NOT_FOUND:
- $msg = 'The target path "' . self::$target . '" does not appear to exist';
- break;
-
- case self::NOT_DIRECTORY:
- $msg = 'The target path "' . self::$target . '" does not appear to be a folder';
- break;
-
- case self::NOT_GRAV_ROOT:
- $msg = 'The target path "' . self::$target . '" does not appear to be a Grav instance';
- break;
-
- case self::ZIP_OPEN_ERROR:
- $msg = 'Unable to open the package file';
- break;
-
- case self::ZIP_EXTRACT_ERROR:
- $msg = 'An error occurred while extracting the package';
- break;
-
- default:
- return 'Unknown error';
- break;
- }
-
- return $msg;
- }
-
- /**
- * Returns the last error code of the occurred error
- * @return integer The code of the last error
- */
- public static function lastErrorCode()
- {
- return self::$error;
- }
-
- /**
- * Allows to manually set an error
- * @param $error the Error code
- */
-
- public static function setError($error)
- {
- self::$error = $error;
- }
-}
diff --git a/src/system/src/Grav/Common/GPM/Local/AbstractPackageCollection.php b/src/system/src/Grav/Common/GPM/Local/AbstractPackageCollection.php
deleted file mode 100644
index b61f92c..0000000
--- a/src/system/src/Grav/Common/GPM/Local/AbstractPackageCollection.php
+++ /dev/null
@@ -1,17 +0,0 @@
- $data) {
- $data->set('slug', $name);
- $this->items[$name] = new Package($data, $this->type);
- }
- }
-}
diff --git a/src/system/src/Grav/Common/GPM/Local/Package.php b/src/system/src/Grav/Common/GPM/Local/Package.php
deleted file mode 100644
index 6505a59..0000000
--- a/src/system/src/Grav/Common/GPM/Local/Package.php
+++ /dev/null
@@ -1,32 +0,0 @@
-blueprints()->toArray());
- parent::__construct($data, $package_type);
-
- $this->settings = $package->toArray();
-
- $html_description = \Parsedown::instance()->line($this->description);
- $this->data->set('slug', $package->slug);
- $this->data->set('description_html', $html_description);
- $this->data->set('description_plain', strip_tags($html_description));
- $this->data->set('symlink', is_link(USER_DIR . $package_type . DS . $this->name));
- }
-
- /**
- * @return mixed
- */
- public function isEnabled()
- {
- return $this->settings['enabled'];
- }
-}
diff --git a/src/system/src/Grav/Common/GPM/Local/Packages.php b/src/system/src/Grav/Common/GPM/Local/Packages.php
deleted file mode 100644
index a8ed6a4..0000000
--- a/src/system/src/Grav/Common/GPM/Local/Packages.php
+++ /dev/null
@@ -1,17 +0,0 @@
- new Plugins(),
- 'themes' => new Themes()
- ];
-
- parent::__construct($items);
- }
-}
diff --git a/src/system/src/Grav/Common/GPM/Local/Plugins.php b/src/system/src/Grav/Common/GPM/Local/Plugins.php
deleted file mode 100644
index b1c3c64..0000000
--- a/src/system/src/Grav/Common/GPM/Local/Plugins.php
+++ /dev/null
@@ -1,22 +0,0 @@
-all());
- }
-}
diff --git a/src/system/src/Grav/Common/GPM/Local/Themes.php b/src/system/src/Grav/Common/GPM/Local/Themes.php
deleted file mode 100644
index 64d23b9..0000000
--- a/src/system/src/Grav/Common/GPM/Local/Themes.php
+++ /dev/null
@@ -1,22 +0,0 @@
-all());
- }
-}
diff --git a/src/system/src/Grav/Common/GPM/PackageInterface.php b/src/system/src/Grav/Common/GPM/PackageInterface.php
deleted file mode 100644
index ad856c0..0000000
--- a/src/system/src/Grav/Common/GPM/PackageInterface.php
+++ /dev/null
@@ -1,58 +0,0 @@
-findResource('cache://gpm', true, true);
- $this->cache = new FilesystemCache($cache_dir);
-
- $this->repository = $repository;
- $this->raw = $this->cache->fetch(md5($this->repository));
-
- $this->fetch($refresh, $callback);
- foreach (json_decode($this->raw, true) as $slug => $data) {
- $this->items[$slug] = new Package($data, $this->type);
- }
- }
-
- public function fetch($refresh = false, $callback = null)
- {
- if (!$this->raw || $refresh) {
- $response = Response::get($this->repository, [], $callback);
- $this->raw = $response;
- $this->cache->save(md5($this->repository), $this->raw, $this->lifetime);
- }
-
- return $this->raw;
- }
-}
diff --git a/src/system/src/Grav/Common/GPM/Remote/Grav.php b/src/system/src/Grav/Common/GPM/Remote/Grav.php
deleted file mode 100644
index f8148a5..0000000
--- a/src/system/src/Grav/Common/GPM/Remote/Grav.php
+++ /dev/null
@@ -1,95 +0,0 @@
-findResource('cache://gpm', true, true);
- $this->cache = new FilesystemCache($cache_dir);
- $this->raw = $this->cache->fetch(md5($this->repository));
-
- $this->fetch($refresh, $callback);
-
- $this->data = json_decode($this->raw, true);
- $this->version = isset($this->data['version']) ? $this->data['version'] : '-';
- $this->date = isset($this->data['date']) ? $this->data['date'] : '-';
-
- if (isset($this->data['assets'])) foreach ($this->data['assets'] as $slug => $data) {
- $this->items[$slug] = new Package($data);
- }
- }
-
- /**
- * Returns the list of assets associated to the latest version of Grav
- * @return array list of assets
- */
- public function getAssets()
- {
- return $this->data['assets'];
- }
-
- /**
- * Returns the changelog list for each version of Grav
- * @param string $diff the version number to start the diff from
- *
- * @return array changelog list for each version
- */
- public function getChangelog($diff = null)
- {
- if (!$diff) {
- return $this->data['changelog'];
- }
-
- $diffLog = [];
- foreach ($this->data['changelog'] as $version => $changelog) {
- preg_match("/[\d\.]+/", $version, $cleanVersion);
-
- if (!$cleanVersion || version_compare($diff, $cleanVersion[0], ">=")) { continue; }
-
- $diffLog[$version] = $changelog;
- }
-
- return $diffLog;
- }
-
- /**
- * Returns the latest version of Grav available remotely
- * @return string
- */
- public function getVersion()
- {
- return $this->version;
- }
-
- /**
- * Return the release date of the latest Grav
- * @return string
- */
- public function getDate()
- {
- return $this->date;
- }
-
- public function isUpdatable()
- {
- return version_compare(GRAV_VERSION, $this->getVersion(), '<');
- }
-
- public function isSymlink()
- {
- return is_link(GRAV_ROOT . DS . 'index.php');
- }
-}
diff --git a/src/system/src/Grav/Common/GPM/Remote/Package.php b/src/system/src/Grav/Common/GPM/Remote/Package.php
deleted file mode 100644
index 9b0367f..0000000
--- a/src/system/src/Grav/Common/GPM/Remote/Package.php
+++ /dev/null
@@ -1,12 +0,0 @@
- new Plugins($refresh, $callback),
- 'themes' => new Themes($refresh, $callback)
- ];
-
- parent::__construct($items);
- }
-}
diff --git a/src/system/src/Grav/Common/GPM/Remote/Plugins.php b/src/system/src/Grav/Common/GPM/Remote/Plugins.php
deleted file mode 100644
index ec6d645..0000000
--- a/src/system/src/Grav/Common/GPM/Remote/Plugins.php
+++ /dev/null
@@ -1,24 +0,0 @@
-repository, $refresh, $callback);
- }
-}
diff --git a/src/system/src/Grav/Common/GPM/Remote/Themes.php b/src/system/src/Grav/Common/GPM/Remote/Themes.php
deleted file mode 100644
index 759b7e1..0000000
--- a/src/system/src/Grav/Common/GPM/Remote/Themes.php
+++ /dev/null
@@ -1,24 +0,0 @@
-repository, $refresh, $callback);
- }
-}
diff --git a/src/system/src/Grav/Common/GPM/Response.php b/src/system/src/Grav/Common/GPM/Response.php
deleted file mode 100644
index 4f61e2b..0000000
--- a/src/system/src/Grav/Common/GPM/Response.php
+++ /dev/null
@@ -1,221 +0,0 @@
- [
- CURLOPT_REFERER => 'Grav GPM',
- CURLOPT_USERAGENT => 'Grav GPM',
- CURLOPT_RETURNTRANSFER => true,
- CURLOPT_FOLLOWLOCATION => true,
- CURLOPT_TIMEOUT => 15,
- CURLOPT_HEADER => false,
- /**
- * Example of callback parameters from within your own class
- */
- //CURLOPT_NOPROGRESS => false,
- //CURLOPT_PROGRESSFUNCTION => [$this, 'progress']
- ],
- 'fopen' => [
- 'method' => 'GET',
- 'user_agent' => 'Grav GPM',
- 'max_redirects' => 5,
- 'follow_location' => 1,
- 'timeout' => 15,
- /**
- * Example of callback parameters from within your own class
- */
- //'notification' => [$this, 'progress']
- ]
- ];
-
- /**
- * Sets the preferred method to use for making HTTP calls.
- * @param string $method Default is `auto`
- */
- public static function setMethod($method = 'auto')
- {
- if (!in_array($method, ['auto', 'curl', 'fopen'])) {
- $method = 'auto';
- }
-
- self::$method = $method;
-
- return new self();
- }
-
- /**
- * Makes a request to the URL by using the preferred method
- * @param string $uri URL to call
- * @param array $options An array of parameters for both `curl` and `fopen`
- * @return string The response of the request
- */
- public static function get($uri = '', $options = [], $callback = null)
- {
- if (!self::isCurlAvailable() && !self::isFopenAvailable()) {
- throw new \RuntimeException('Could not start an HTTP request. `allow_url_open` is disabled and `cURL` is not available');
- }
-
- $options = array_replace_recursive(self::$defaults, $options);
- $method = 'get' . ucfirst(strtolower(self::$method));
-
- self::$callback = $callback;
- return static::$method($uri, $options, $callback);
- }
-
- /**
- * Progress normalized for cURL and Fopen
- * @param args Variable length of arguments passed in by stream method
- * @return array Normalized array with useful data.
- * Format: ['code' => int|false, 'filesize' => bytes, 'transferred' => bytes, 'percent' => int]
- */
- public static function progress()
- {
- static $filesize = null;
-
- $args = func_get_args();
- $isCurlResource = is_resource($args[0]) && get_resource_type($args[0]) == 'curl';
-
- $notification_code = !$isCurlResource ? $args[0] : false;
- $bytes_transferred = $isCurlResource ? $args[2] : $args[4];
-
- if ($isCurlResource) {
- $filesize = $args[1];
- } elseif ($notification_code == STREAM_NOTIFY_FILE_SIZE_IS) {
- $filesize = $args[5];
- }
-
- if ($bytes_transferred > 0) {
- if ($notification_code == STREAM_NOTIFY_PROGRESS|STREAM_NOTIFY_COMPLETED || $isCurlResource) {
-
- $progress = [
- 'code' => $notification_code,
- 'filesize' => $filesize,
- 'transferred' => $bytes_transferred,
- 'percent' => $filesize <= 0 ? '-' : round(($bytes_transferred * 100) / $filesize, 1)
- ];
-
- if (self::$callback !== null) {
- call_user_func_array(self::$callback, [$progress]);
- }
- }
- }
- }
-
- /**
- * Checks if cURL is available
- * @return boolean
- */
- public static function isCurlAvailable()
- {
- return function_exists('curl_version');
- }
-
- /**
- * Checks if the remote fopen request is enabled in PHP
- * @return boolean
- */
- public static function isFopenAvailable()
- {
- return preg_match('/1|yes|on|true/i', ini_get('allow_url_fopen'));
- }
-
- /**
- * Automatically picks the preferred method
- * @return string The response of the request
- */
- private static function getAuto()
- {
- if (self::isFopenAvailable()) {
- return self::getFopen(func_get_args());
- }
-
- if (self::isCurlAvailable()) {
- return self::getCurl(func_get_args());
- }
- }
-
- /**
- * Starts a HTTP request via cURL
- * @return string The response of the request
- */
- private static function getCurl()
- {
- $args = func_get_args();
- $args = count($args) > 1 ? $args : array_shift($args);
-
- $uri = $args[0];
- $options = $args[1];
- $callback = $args[2];
-
- $ch = curl_init($uri);
- curl_setopt_array($ch, $options['curl']);
-
- if ($callback) {
- curl_setopt_array(
- $ch,
- [
- CURLOPT_NOPROGRESS => false,
- CURLOPT_PROGRESSFUNCTION => ['self', 'progress']
- ]
- );
- }
-
- $response = curl_exec($ch);
-
- if ($errno = curl_errno($ch)) {
- $error_message = curl_strerror($errno);
- throw new \RuntimeException("cURL error ({$errno}):\n {$error_message}");
- }
-
- curl_close($ch);
-
- return $response;
- }
-
- /**
- * Starts a HTTP request via fopen
- * @return string The response of the request
- */
- private static function getFopen()
- {
- if (count($args = func_get_args()) == 1) {
- $args = $args[0];
- }
-
- $uri = $args[0];
- $options = $args[1];
- $callback = $args[2];
-
- if ($callback) {
- $options['fopen']['notification'] = ['self', 'progress'];
- }
-
- $stream = stream_context_create(['http' => $options['fopen']], $options['fopen']);
- $content = @file_get_contents($uri, false, $stream);
-
- if ($content === false) {
- throw new \RuntimeException("Error while trying to download '$uri'");
- }
-
- return $content;
- }
-}
diff --git a/src/system/src/Grav/Common/GPM/Upgrader.php b/src/system/src/Grav/Common/GPM/Upgrader.php
deleted file mode 100644
index 590ad4d..0000000
--- a/src/system/src/Grav/Common/GPM/Upgrader.php
+++ /dev/null
@@ -1,93 +0,0 @@
-remote = new Remote\Grav($refresh, $callback);
- }
-
- /**
- * Returns the release date of the latest version of Grav
- * @return string
- */
- public function getReleaseDate()
- {
- return $this->remote->getDate();
- }
-
- /**
- * Returns the version of the installed Grav
- * @return string
- */
- public function getLocalVersion()
- {
- return GRAV_VERSION;
- }
-
- /**
- * Returns the version of the remotely available Grav
- * @return string
- */
- public function getRemoteVersion()
- {
- return $this->remote->getVersion();
- }
-
- /**
- * Returns an array of assets available to download remotely
- * @return array
- */
- public function getAssets()
- {
- return $this->remote->getAssets();
- }
-
- /**
- * Returns the changelog list for each version of Grav
- * @param string $diff the version number to start the diff from
- *
- * @return array return the changelog list for each version
- */
- public function getChangelog($diff = null)
- {
- return $this->remote->getChangelog($diff);
- }
-
- /**
- * Checks if the currently installed Grav is upgradable to a newer version
- * @return boolean True if it's upgradable, False otherwise.
- */
- public function isUpgradable()
- {
- return version_compare($this->getLocalVersion(), $this->getRemoteVersion(), "<");
- }
-
- /**
- * Checks if Grav is currently symbolically linked
- * @return boolean True if Grav is symlinked, False otherwise.
- */
-
- public function isSymlink()
- {
- return $this->remote->isSymlink();
- }
-}
diff --git a/src/system/src/Grav/Common/Getters.php b/src/system/src/Grav/Common/Getters.php
deleted file mode 100644
index 857dcca..0000000
--- a/src/system/src/Grav/Common/Getters.php
+++ /dev/null
@@ -1,150 +0,0 @@
-offsetSet($offset, $value);
- }
-
- /**
- * Magic getter method
- *
- * @param mixed $offset Medium name value
- * @return mixed Medium value
- */
- public function __get($offset)
- {
- return $this->offsetGet($offset);
- }
-
- /**
- * Magic method to determine if the attribute is set
- *
- * @param mixed $offset Medium name value
- * @return boolean True if the value is set
- */
- public function __isset($offset)
- {
- return $this->offsetExists($offset);
- }
-
- /**
- * Magic method to unset the attribute
- *
- * @param mixed $offset The name value to unset
- */
- public function __unset($offset)
- {
- $this->offsetUnset($offset);
- }
-
- /**
- * @param mixed $offset
- * @return bool
- */
- public function offsetExists($offset)
- {
- if ($this->gettersVariable) {
- $var = $this->gettersVariable;
- return isset($this->{$var}[$offset]);
- } else {
- return isset($this->{$offset});
- }
- }
-
- /**
- * @param mixed $offset
- * @return mixed
- */
- public function offsetGet($offset)
- {
- if ($this->gettersVariable) {
- $var = $this->gettersVariable;
- return isset($this->{$var}[$offset]) ? $this->{$var}[$offset] : null;
- } else {
- return isset($this->{$offset}) ? $this->{$offset} : null;
- }
- }
-
- /**
- * @param mixed $offset
- * @param mixed $value
- */
- public function offsetSet($offset, $value)
- {
- if ($this->gettersVariable) {
- $var = $this->gettersVariable;
- $this->{$var}[$offset] = $value;
- } else {
- $this->{$offset} = $value;
- }
- }
-
- /**
- * @param mixed $offset
- */
- public function offsetUnset($offset)
- {
- if ($this->gettersVariable) {
- $var = $this->gettersVariable;
- unset($this->{$var}[$offset]);
- } else {
- unset($this->{$offset});
- }
- }
-
- /**
- * @return int
- */
- public function count()
- {
- if ($this->gettersVariable) {
- $var = $this->gettersVariable;
- count($this->{$var});
- } else {
- count($this->toArray());
- }
- }
-
- /**
- * Returns an associative array of object properties.
- *
- * @return array
- */
- public function toArray()
- {
- if ($this->gettersVariable) {
- $var = $this->gettersVariable;
- return $this->{$var};
- } else {
- $properties = (array) $this;
- $list = array();
- foreach ($properties as $property => $value) {
- if ($property[0] != "\0") $list[$property] = $value;
- }
- return $list;
- }
- }
-}
diff --git a/src/system/src/Grav/Common/Grav.php b/src/system/src/Grav/Common/Grav.php
deleted file mode 100644
index d60cfd0..0000000
--- a/src/system/src/Grav/Common/Grav.php
+++ /dev/null
@@ -1,510 +0,0 @@
- $value) {
- $instance->offsetSet($key, $value);
- }
- }
-
- return self::$instance;
- }
-
- protected static function load(array $values)
- {
- $container = new static($values);
-
- $container['grav'] = $container;
-
-
-
- $container['debugger'] = new Debugger();
- $container['debugger']->startTimer('_init', 'Initialize');
-
- $container->register(new LoggerServiceProvider);
-
- $container->register(new ErrorServiceProvider);
-
- $container['uri'] = function ($c) {
- return new Uri($c);
- };
-
- $container['task'] = function ($c) {
- return !empty($_POST['task']) ? $_POST['task'] : $c['uri']->param('task');
- };
-
- $container['events'] = function ($c) {
- return new EventDispatcher;
- };
- $container['cache'] = function ($c) {
- return new Cache($c);
- };
- $container['session'] = function ($c) {
- return new Session($c);
- };
- $container['plugins'] = function ($c) {
- return new Plugins();
- };
- $container['themes'] = function ($c) {
- return new Themes($c);
- };
- $container['twig'] = function ($c) {
- return new Twig($c);
- };
- $container['taxonomy'] = function ($c) {
- return new Taxonomy($c);
- };
- $container['language'] = function ($c) {
- return new Language($c);
- };
-
- $container['pages'] = function ($c) {
- return new Page\Pages($c);
- };
-
- $container['assets'] = new Assets();
-
- $container['page'] = function ($c) {
- /** @var Pages $pages */
- $pages = $c['pages'];
- /** @var Language $language */
- $language = $c['language'];
-
- /** @var Uri $uri */
- $uri = $c['uri'];
-
- $path = rtrim($uri->path(), '/');
- $path = $path ?: '/';
-
- $page = $pages->dispatch($path);
-
- // Redirection tests
- if ($page) {
- // Language-specific redirection scenarios
- if ($language->enabled()) {
- if ($language->isLanguageInUrl() && !$language->isIncludeDefaultLanguage()) {
- $c->redirect($page->route());
- }
- if (!$language->isLanguageInUrl() && $language->isIncludeDefaultLanguage()) {
- $c->redirectLangSafe($page->route());
- }
- }
- // Default route test and redirect
- if ($c['config']->get('system.pages.redirect_default_route') && $page->route() != $path) {
- $c->redirectLangSafe($page->route());
- }
- }
-
- // if page is not found, try some fallback stuff
- if (!$page || !$page->routable()) {
-
- // Try fallback URL stuff...
- $c->fallbackUrl($page, $path);
-
- // If no page found, fire event
- $event = $c->fireEvent('onPageNotFound');
-
- if (isset($event->page)) {
- $page = $event->page;
- } else {
- throw new \RuntimeException('Page Not Found', 404);
- }
- }
- return $page;
- };
- $container['output'] = function ($c) {
- return $c['twig']->processSite($c['uri']->extension());
- };
- $container['browser'] = function ($c) {
- return new Browser();
- };
-
- $container['base_url_absolute'] = function ($c) {
- return $c['config']->get('system.base_url_absolute') ?: $c['uri']->rootUrl(true);
- };
- $container['base_url_relative'] = function ($c) {
- return $c['config']->get('system.base_url_relative') ?: $c['uri']->rootUrl(false);
- };
- $container['base_url'] = function ($c) {
- return $c['config']->get('system.absolute_urls') ? $c['base_url_absolute'] : $c['base_url_relative'];
- };
-
- $container->register(new StreamsServiceProvider);
- $container->register(new ConfigServiceProvider);
-
- $container['inflector'] = new Inflector();
-
- $container['debugger']->stopTimer('_init');
-
- return $container;
- }
-
- public function process()
- {
- /** @var Debugger $debugger */
- $debugger = $this['debugger'];
-
-
-
- // Initialize configuration.
- $debugger->startTimer('_config', 'Configuration');
- $this['config']->init();
- $this['errors']->resetHandlers();
- $this['uri']->init();
- $this['session']->init();
-
- $debugger->init();
- $this['config']->debug();
- $debugger->stopTimer('_config');
-
- // Use output buffering to prevent headers from being sent too early.
- ob_start();
- if ($this['config']->get('system.cache.gzip')) {
- ob_start('ob_gzhandler');
- }
-
- // Initialize the timezone
- if ($this['config']->get('system.timezone')) {
- date_default_timezone_set($this['config']->get('system.timezone'));
- }
-
- // Initialize Locale if set and configured
- if ($this['language']->enabled() && $this['config']->get('system.languages.override_locale')) {
- setlocale(LC_ALL, $this['language']->getLanguage());
- } elseif ($this['config']->get('system.default_locale')) {
- setlocale(LC_ALL, $this['config']->get('system.default_locale'));
- }
-
- $debugger->startTimer('streams', 'Streams');
- $this['streams'];
- $debugger->stopTimer('streams');
-
- $debugger->startTimer('plugins', 'Plugins');
- $this['plugins']->init();
- $this->fireEvent('onPluginsInitialized');
- $debugger->stopTimer('plugins');
-
- $debugger->startTimer('themes', 'Themes');
- $this['themes']->init();
- $this->fireEvent('onThemeInitialized');
- $debugger->stopTimer('themes');
-
- $task = $this['task'];
- if ($task) {
- $this->fireEvent('onTask.' . $task);
- }
-
- $this['assets']->init();
- $this->fireEvent('onAssetsInitialized');
-
- $debugger->startTimer('twig', 'Twig');
- $this['twig']->init();
- $debugger->stopTimer('twig');
-
- $debugger->startTimer('pages', 'Pages');
- $this['pages']->init();
- $this->fireEvent('onPagesInitialized');
- $debugger->stopTimer('pages');
- $this->fireEvent('onPageInitialized');
-
- $debugger->addAssets();
-
- // Process whole page as required
- $debugger->startTimer('render', 'Render');
- $this->output = $this['output'];
- $this->fireEvent('onOutputGenerated');
- $debugger->stopTimer('render');
-
- // Set the header type
- $this->header();
- echo $this->output;
- $debugger->render();
-
- $this->fireEvent('onOutputRendered');
-
- register_shutdown_function([$this, 'shutdown']);
- }
-
- /**
- * Redirect browser to another location.
- *
- * @param string $route Internal route.
- * @param int $code Redirection code (30x)
- */
- public function redirect($route, $code = null)
- {
- /** @var Uri $uri */
- $uri = $this['uri'];
-
- //Check for code in route
- $regex = '/.*(\[(30[1-7])\])$/';
- preg_match($regex, $route, $matches);
- if ($matches) {
- $route = str_replace($matches[1], '', $matches[0]);
- $code = $matches[2];
- }
-
- if ($code == null) {
- $code = $this['config']->get('system.pages.redirect_default_code', 301);
- }
-
- if (isset($this['session'])) {
- $this['session']->close();
- }
-
- if ($uri->isExternal($route)) {
- $url = $route;
- } else {
- $url = rtrim($uri->rootUrl(), '/') .'/'. trim($route, '/');
- }
-
- header("Location: {$url}", true, $code);
- exit();
- }
-
- /**
- * Redirect browser to another location taking language into account (preferred)
- *
- * @param string $route Internal route.
- * @param int $code Redirection code (30x)
- */
- public function redirectLangSafe($route, $code = null)
- {
- /** @var Language $language */
- $language = $this['language'];
-
- if (!$this['uri']->isExternal($route) && $language->enabled() && $language->isIncludeDefaultLanguage()) {
- return $this->redirect($language->getLanguage() . $route, $code);
- } else {
- return $this->redirect($route, $code);
- }
- }
-
- /**
- * Returns mime type for the file format.
- *
- * @param string $format
- * @return string
- */
- public function mime($format)
- {
- switch ($format) {
- case 'json':
- return 'application/json';
- case 'html':
- return 'text/html';
- case 'atom':
- return 'application/atom+xml';
- case 'rss':
- return 'application/rss+xml';
- case 'xml':
- return 'application/xml';
- }
- return 'text/html';
- }
-
- /**
- * Set response header.
- */
- public function header()
- {
- $extension = $this['uri']->extension();
-
- /** @var Page $page */
- $page = $this['page'];
-
- header('Content-type: ' . $this->mime($extension));
-
- // Calculate Expires Headers if set to > 0
- $expires = $page->expires();
-
- if ($expires > 0) {
- $expires_date = gmdate('D, d M Y H:i:s', time() + $expires) . ' GMT';
- header('Cache-Control: max-age=' . $expires);
- header('Expires: '. $expires_date);
- }
-
- // Set the last modified time
- if ($page->lastModified()) {
- $last_modified_date = gmdate('D, d M Y H:i:s', $page->modified()) . ' GMT';
- header('Last-Modified: ' . $last_modified_date);
- }
-
- // Calculate a Hash based on the raw file
- if ($page->eTag()) {
- header('ETag: ' . md5($page->raw() . $page->modified()));
- }
-
- // Set debugger data in headers
- if (!($extension === null || $extension == 'html')) {
- $this['debugger']->enabled(false);
- }
-
- // Set HTTP response code
- if (isset($this['page']->header()->http_response_code)) {
- http_response_code($this['page']->header()->http_response_code);
- }
-
- // Vary: Accept-Encoding
- if ($this['config']->get('system.pages.vary_accept_encoding', false)) {
- header('Vary: Accept-Encoding');
- }
- }
-
- /**
- * Fires an event with optional parameters.
- *
- * @param string $eventName
- * @param Event $event
- * @return Event
- */
- public function fireEvent($eventName, Event $event = null)
- {
- /** @var EventDispatcher $events */
- $events = $this['events'];
- return $events->dispatch($eventName, $event);
- }
-
- /**
- * Set the final content length for the page and flush the buffer
- *
- */
- public function shutdown()
- {
- if ($this['config']->get('system.debugger.shutdown.close_connection')) {
- //stop user abort
- if (function_exists('ignore_user_abort')) {
- @ignore_user_abort(true);
- }
-
- // close the session
- if (isset($this['session'])) {
- $this['session']->close();
- }
-
- // flush buffer if gzip buffer was started
- if ($this['config']->get('system.cache.gzip')) {
- ob_end_flush(); // gzhandler buffer
- }
-
- // get lengh and close the connection
- header('Content-Length: ' . ob_get_length());
- header("Connection: close");
-
- // flush the regular buffer
- ob_end_flush();
- @ob_flush();
- flush();
-
- // fix for fastcgi close connection issue
- if (function_exists('fastcgi_finish_request')) {
- @fastcgi_finish_request();
- }
-
- }
-
- $this->fireEvent('onShutdown');
- }
-
- /**
- * This attempts to find media, other files, and download them
- * @param $page
- * @param $path
- */
- protected function fallbackUrl($page, $path)
- {
- /** @var Uri $uri */
- $uri = $this['uri'];
-
- /** @var Config $config */
- $config = $this['config'];
-
- $uri_extension = $uri->extension();
-
- // Only allow whitelisted types to fallback
- if (!in_array($uri_extension, $config->get('system.pages.fallback_types'))) {
- return;
- }
-
- $path_parts = pathinfo($path);
- $page = $this['pages']->dispatch($path_parts['dirname'], true);
- if ($page) {
- $media = $page->media()->all();
-
- $parsed_url = parse_url(urldecode($uri->basename()));
-
- $media_file = $parsed_url['path'];
-
- // if this is a media object, try actions first
- if (isset($media[$media_file])) {
- $medium = $media[$media_file];
- foreach ($uri->query(null, true) as $action => $params) {
- if (in_array($action, ImageMedium::$magic_actions)) {
- call_user_func_array(array(&$medium, $action), explode(',', $params));
- }
- }
- Utils::download($medium->path(), false);
- }
-
- // unsupported media type, try to download it...
- if ($uri_extension) {
- $extension = $uri_extension;
- } else {
- if (isset($path_parts['extension'])) {
- $extension = $path_parts['extension'];
- } else {
- $extension = null;
- }
- }
-
- if ($extension) {
- $download = true;
- if (in_array(ltrim($extension, '.'), $config->get('system.media.unsupported_inline_types', []))) {
- $download = false;
- }
- Utils::download($page->path() . DIRECTORY_SEPARATOR . $uri->basename(), $download);
- }
- }
- }
-}
diff --git a/src/system/src/Grav/Common/GravTrait.php b/src/system/src/Grav/Common/GravTrait.php
deleted file mode 100644
index 1710173..0000000
--- a/src/system/src/Grav/Common/GravTrait.php
+++ /dev/null
@@ -1,29 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Truncator {
-
- public static $default_options = array(
- 'ellipsis' => '…',
- 'break' => ' ',
- 'length_in_chars' => false,
- 'word_safe' => false,
- );
-
- // These tags are allowed to have an ellipsis inside
- public static $ellipsable_tags = array(
- 'p', 'ol', 'ul', 'li',
- 'div', 'header', 'article', 'nav',
- 'section', 'footer', 'aside',
- 'dd', 'dt', 'dl',
- );
-
- public static $self_closing_tags = array(
- 'br', 'hr', 'img',
- );
-
- /**
- * Truncate given HTML string to specified length.
- * If length_in_chars is false it's trimmed by number
- * of words, otherwise by number of characters.
- *
- * @param string $html
- * @param integer $length
- * @param string|array $opts
- * @return string
- */
- public static function truncate($html, $length, $opts=array())
- {
- if (is_string($opts)) $opts = array('ellipsis' => $opts);
- $opts = array_merge(static::$default_options, $opts);
- // wrap the html in case it consists of adjacent nodes like
foo
bar
- $html = mb_convert_encoding("
".$html."
", 'HTML-ENTITIES', 'UTF-8');
-
- $root_node = null;
- // Parse using HTML5Lib if it's available.
- if (class_exists('HTML5Lib\\Parser')) {
- try {
- $doc = \HTML5Lib\Parser::parse($html);
- $root_node = $doc->documentElement->lastChild->lastChild;
- }
- catch (\Exception $e) {
- ;
- }
- }
- if ($root_node === null) {
- // HTML5Lib not available so we'll have to use DOMDocument
- // We'll only be able to parse HTML5 if it's valid XML
- $doc = new DOMDocument('4.01', 'utf-8');
- $doc->formatOutput = false;
- $doc->preserveWhiteSpace = true;
- // loadHTML will fail with HTML5 tags (article, nav, etc)
- // so we need to suppress errors and if it fails to parse we
- // retry with the XML parser instead
- $prev_use_errors = libxml_use_internal_errors(true);
- if ($doc->loadHTML($html)) {
- $root_node = $doc->documentElement->lastChild->lastChild;
- }
- else if ($doc->loadXML($html)) {
- $root_node = $doc->documentElement;
- }
- else {
- libxml_use_internal_errors($prev_use_errors);
- throw new \RuntimeException;
- }
- libxml_use_internal_errors($prev_use_errors);
- }
- list($text, $_, $opts) = static::truncateNode($doc, $root_node, $length, $opts);
-
- $text = mb_substr(mb_substr($text, 0, -6), 5);
-
- return $text;
- }
-
- protected static function truncateNode($doc, $node, $length, $opts)
- {
- if ($length === 0 && !static::ellipsable($node)) {
- return array('', 1, $opts);
- }
- list($inner, $remaining, $opts) = static::innerTruncate($doc, $node, $length, $opts);
- if (0 === mb_strlen($inner)) {
- return array(in_array(mb_strtolower($node->nodeName), static::$self_closing_tags) ? $doc->saveXML($node) : "", $length - $remaining, $opts);
- }
- while($node->firstChild) {
- $node->removeChild($node->firstChild);
- }
- $newNode = $doc->createDocumentFragment();
- // handle the ampersand
- $newNode->appendXml(static::xmlEscape($inner));
- $node->appendChild($newNode);
- return array($doc->saveXML($node), $length - $remaining, $opts);
- }
-
- protected static function innerTruncate($doc, $node, $length, $opts)
- {
- $inner = '';
- $remaining = $length;
- foreach($node->childNodes as $childNode) {
- if ($childNode->nodeType === XML_ELEMENT_NODE) {
- list($txt, $nb, $opts) = static::truncateNode($doc, $childNode, $remaining, $opts);
- }
- else if ($childNode->nodeType === XML_TEXT_NODE) {
- list($txt, $nb, $opts) = static::truncateText($doc, $childNode, $remaining, $opts);
- } else {
- $txt = '';
- $nb = 0;
- }
-
- // unhandle the ampersand
- $txt = static::xmlUnescape($txt);
-
- $remaining -= $nb;
- $inner .= $txt;
- if ($remaining < 0) {
- if (static::ellipsable($node)) {
- $inner = preg_replace('/(?:[\s\pP]+|(?:&(?:[a-z]+|#[0-9]+);?))*$/', '', $inner).$opts['ellipsis'];
- $opts['ellipsis'] = '';
- $opts['was_truncated'] = true;
- }
- break;
- }
- }
- return array($inner, $remaining, $opts);
- }
-
- protected static function truncateText($doc, $node, $length, $opts)
- {
- $string = $node->textContent;
-
- if ($opts['length_in_chars']) {
- $count = mb_strlen($string);
- if ($count <= $length && $length > 0) {
- return array($string, $count, $opts);
- }
- if ($opts['word_safe']) {
- if (false !== ($breakpoint = mb_strpos($string, $opts['break'], $length))) {
- if ($breakpoint < mb_strlen($string) - 1) {
- $string = mb_substr($string, 0, $breakpoint) . $opts['break'];
- }
- }
- return array($string, $count, $opts);
- }
- return array(mb_substr($node->textContent, 0, $length), $count, $opts);
- }
- else {
- preg_match_all('/\s*\S+/', $string, $words);
- $words = $words[0];
- $count = count($words);
- if ($count <= $length && $length > 0) {
- return array($xhtml, $count, $opts);
- }
- return array(implode('', array_slice($words, 0, $length)), $count, $opts);
- }
- }
-
- protected static function ellipsable($node)
- {
- return ($node instanceof DOMDocument)
- || in_array(mb_strtolower($node->nodeName), static::$ellipsable_tags)
- ;
- }
-
- protected static function xmlEscape($string)
- {
- $string = str_replace('&', '&', $string);
- $string = str_replace('', '<?', $string);
- return $string;
- }
-
- protected static function xmlUnescape($string)
- {
- $string = str_replace('&', '&', $string);
- $string = str_replace('<?', '', $string);
- return $string;
- }
-}
diff --git a/src/system/src/Grav/Common/Inflector.php b/src/system/src/Grav/Common/Inflector.php
deleted file mode 100644
index ff1030e..0000000
--- a/src/system/src/Grav/Common/Inflector.php
+++ /dev/null
@@ -1,310 +0,0 @@
-plural)) {
- $language = self::getGrav()['language'];
- $this->plural = $language->translate('INFLECTOR_PLURALS', null, true);
- $this->singular = $language->translate('INFLECTOR_SINGULAR', null, true);
- $this->uncountable = $language->translate('INFLECTOR_UNCOUNTABLE', null, true);
- $this->irregular = $language->translate('INFLECTOR_IRREGULAR', null, true);
- $this->ordinals = $language->translate('INFLECTOR_ORDINALS', null, true);
- }
- }
-
- /**
- * Pluralizes English nouns.
- *
- * @param string $word English noun to pluralize
- * @return string Plural noun
- */
- public function pluralize($word, $count = 2)
- {
- $this->init();
-
- if ($count == 1) {
- return $word;
- }
-
- $lowercased_word = strtolower($word);
-
- foreach ($this->uncountable as $_uncountable) {
- if (substr($lowercased_word, (-1*strlen($_uncountable))) == $_uncountable) {
- return $word;
- }
- }
-
- foreach ($this->irregular as $_plural => $_singular) {
- if (preg_match('/('.$_plural.')$/i', $word, $arr)) {
- return preg_replace('/('.$_plural.')$/i', substr($arr[0], 0, 1).substr($_singular, 1), $word);
- }
- }
-
- foreach ($this->plural as $rule => $replacement) {
- if (preg_match($rule, $word)) {
- return preg_replace($rule, $replacement, $word);
- }
- }
- return false;
-
- }
-
- /**
- * Singularizes English nouns.
- *
- * @param string $word English noun to singularize
- * @param int $count
- * @return string Singular noun.
- */
- public function singularize($word, $count = 1)
- {
- $this->init();
-
- if ($count != 1) {
- return $word;
- }
-
- $lowercased_word = strtolower($word);
- foreach ($this->uncountable as $_uncountable) {
- if (substr($lowercased_word, (-1*strlen($_uncountable))) == $_uncountable) {
- return $word;
- }
- }
-
- foreach ($this->irregular as $_plural => $_singular) {
- if (preg_match('/('.$_singular.')$/i', $word, $arr)) {
- return preg_replace('/('.$_singular.')$/i', substr($arr[0], 0, 1).substr($_plural, 1), $word);
- }
- }
-
- foreach ($this->singular as $rule => $replacement) {
- if (preg_match($rule, $word)) {
- return preg_replace($rule, $replacement, $word);
- }
- }
-
- return $word;
- }
-
- /**
- * Converts an underscored or CamelCase word into a English
- * sentence.
- *
- * The titleize public function converts text like "WelcomePage",
- * "welcome_page" or "welcome page" to this "Welcome
- * Page".
- * If second parameter is set to 'first' it will only
- * capitalize the first character of the title.
- *
- * @param string $word Word to format as tile
- * @param string $uppercase If set to 'first' it will only uppercase the
- * first character. Otherwise it will uppercase all
- * the words in the title.
- * @return string Text formatted as title
- */
- public function titleize($word, $uppercase = '')
- {
- $uppercase = $uppercase == 'first' ? 'ucfirst' : 'ucwords';
- return $uppercase($this->humanize($this->underscorize($word)));
- }
-
- /**
- * Returns given word as CamelCased
- *
- * Converts a word like "send_email" to "SendEmail". It
- * will remove non alphanumeric character from the word, so
- * "who's online" will be converted to "WhoSOnline"
- *
- * @see variablize
- * @param string $word Word to convert to camel case
- * @return string UpperCamelCasedWord
- */
- public function camelize($word)
- {
- return str_replace(' ', '', ucwords(preg_replace('/[^A-Z^a-z^0-9]+/', ' ', $word)));
- }
-
- /**
- * Converts a word "into_it_s_underscored_version"
- *
- * Convert any "CamelCased" or "ordinary Word" into an
- * "underscored_word".
- *
- * This can be really useful for creating friendly URLs.
- *
- * @param string $word Word to underscore
- * @return string Underscored word
- */
- public function underscorize($word)
- {
- $regex1 = preg_replace('/([A-Z]+)([A-Z][a-z])/', '\1_\2', $word);
- $regex2 = preg_replace('/([a-zd])([A-Z])/', '\1_\2', $regex1);
- $regex3 = preg_replace('/[^A-Z^a-z^0-9]+/', '_', $regex2);
- return strtolower($regex3);
- }
-
- /**
- * Converts a word "into-it-s-hyphenated-version"
- *
- * Convert any "CamelCased" or "ordinary Word" into an
- * "hyphenated-word".
- *
- * This can be really useful for creating friendly URLs.
- *
- * @param string $word Word to hyphenate
- * @return string hyphenized word
- */
- public function hyphenize($word)
- {
- $regex1 = preg_replace('/([A-Z]+)([A-Z][a-z])/', '\1-\2', $word);
- $regex2 = preg_replace('/([a-zd])([A-Z])/', '\1-\2', $regex1);
- $regex3 = preg_replace('/[^A-Z^a-z^0-9]+/', '-', $regex2);
- return strtolower($regex3);
- }
-
- /**
- * Returns a human-readable string from $word
- *
- * Returns a human-readable string from $word, by replacing
- * underscores with a space, and by upper-casing the initial
- * character by default.
- *
- * If you need to uppercase all the words you just have to
- * pass 'all' as a second parameter.
- *
- * @param string $word String to "humanize"
- * @param string $uppercase If set to 'all' it will uppercase all the words
- * instead of just the first one.
- * @return string Human-readable word
- */
- public function humanize($word, $uppercase = '')
- {
- $uppercase = $uppercase == 'all' ? 'ucwords' : 'ucfirst';
- return $uppercase(str_replace('_', ' ', preg_replace('/_id$/', '', $word)));
- }
-
- /**
- * Same as camelize but first char is underscored
- *
- * Converts a word like "send_email" to "sendEmail". It
- * will remove non alphanumeric character from the word, so
- * "who's online" will be converted to "whoSOnline"
- *
- * @see camelize
- * @param string $word Word to lowerCamelCase
- * @return string Returns a lowerCamelCasedWord
- */
- public function variablize($word)
- {
- $word = $this->camelize($word);
- return strtolower($word[0]).substr($word, 1);
- }
-
- /**
- * Converts a class name to its table name according to rails
- * naming conventions.
- *
- * Converts "Person" to "people"
- *
- * @see classify
- * @param string $class_name Class name for getting related table_name.
- * @return string plural_table_name
- */
- public function tableize($class_name)
- {
- return $this->pluralize($this->underscore($class_name));
- }
-
- /**
- * Converts a table name to its class name according to rails
- * naming conventions.
- *
- * Converts "people" to "Person"
- *
- * @see tableize
- * @param string $table_name Table name for getting related ClassName.
- * @return string SingularClassName
- */
- public function classify($table_name)
- {
- return $this->camelize($this->singularize($table_name));
- }
-
- /**
- * Converts number to its ordinal English form.
- *
- * This method converts 13 to 13th, 2 to 2nd ...
- *
- * @param integer $number Number to get its ordinal value
- * @return string Ordinal representation of given string.
- */
- public function ordinalize($number)
- {
- $this->init();
-
- if (in_array(($number % 100), range(11, 13))) {
- return $number.$this->ordinals['default'];
- } else {
- switch (($number % 10)) {
- case 1:
- return $number.$this->ordinals['first'];
- break;
- case 2:
- return $number.$this->ordinals['second'];
- break;
- case 3:
- return $number.$this->ordinals['third'];
- break;
- default:
- return $number.$this->ordinals['default'];
- break;
- }
- }
- }
-
- public function monthize($days)
- {
- $now = new \DateTime();
- $end = new \DateTime();
-
- $duration = new \DateInterval("P{$days}D");
-
- $diff = $end->add($duration)->diff($now);
-
- // handle years
- if ($diff->y > 0) {
- $diff->m = $diff->m + 12*$diff->y;
- }
-
- return $diff->m;
- }
-}
diff --git a/src/system/src/Grav/Common/Iterator.php b/src/system/src/Grav/Common/Iterator.php
deleted file mode 100644
index d23f429..0000000
--- a/src/system/src/Grav/Common/Iterator.php
+++ /dev/null
@@ -1,218 +0,0 @@
-items[$key])) ? $this->items[$key] : null;
- }
-
- /**
- * Clone the iterator.
- */
- public function __clone()
- {
- foreach ($this as $key => $value) {
- if (is_object($value)) {
- $this->$key = clone $this->$key;
- }
- }
- }
-
- /**
- * Convents iterator to a comma separated list.
- *
- * @return string
- */
- public function __toString()
- {
- return implode(',', $this->items);
- }
-
- /**
- * Remove item from the list.
- *
- * @param $key
- */
- public function remove($key)
- {
- $this->offsetUnset($key);
- }
-
- /**
- * Return previous item.
- *
- * @return mixed
- */
- public function prev()
- {
- return prev($this->items);
- }
-
- /**
- * Return nth item.
- *
- * @param int $key
- * @return mixed|bool
- */
- public function nth($key)
- {
- $items = array_keys($this->items);
- return (isset($items[$key])) ? $this->offsetGet($items[$key]) : false;
- }
-
- /**
- * Get the first item
- *
- * @return mixed
- */
- public function first()
- {
- $items = array_keys($this->items);
- return $this->offsetGet(array_shift($items));
- }
-
- /**
- * Get the last item
- *
- * @return mixed
- */
- public function last()
- {
- $items = array_keys($this->items);
- return $this->offsetGet(array_pop($items));
- }
-
- /**
- * Reverse the Iterator
- *
- * @return $this
- */
- public function reverse()
- {
- $this->items = array_reverse($this->items);
- return $this;
- }
-
- /**
- * @param mixed $needle Searched value.
- * @return string|bool Key if found, otherwise false.
- */
- public function indexOf($needle)
- {
- foreach (array_values($this->items) as $key => $value) {
- if ($value === $needle) {
- return $key;
- }
- }
- return false;
- }
-
- /**
- * Shuffle items.
- *
- * @return $this
- */
- public function shuffle()
- {
- $keys = array_keys($this->items);
- shuffle($keys);
-
- $new = array();
- foreach ($keys as $key) {
- $new[$key] = $this->items[$key];
- }
-
- $this->items = $new;
-
- return $this;
- }
-
- /**
- * Slice the list.
- *
- * @param int $offset
- * @param int $length
- * @return $this
- */
- public function slice($offset, $length = null)
- {
- $this->items = array_slice($this->items, $offset, $length);
-
- return $this;
- }
-
- /**
- * Pick one or more random entries.
- *
- * @param int $num Specifies how many entries should be picked.
- * @return $this
- */
- public function random($num = 1)
- {
- $this->items = array_intersect_key($this->items, array_flip((array) array_rand($this->items, $num)));
-
- return $this;
- }
-
- /**
- * Append new elements to the list.
- *
- * @param array|Iterator $items Items to be appended. Existing keys will be overridden with the new values.
- * @return $this
- */
- public function append($items)
- {
- if ($items instanceof static) {
- $items = $items->toArray();
- }
- $this->items = array_merge($this->items, (array) $items);
-
- return $this;
- }
-
- /**
- * Filter elements from the list
- * @param callable|null $callback A function the receives ($value, $key) and must return a boolean to indicate filter status
- * @return $this
- */
- public function filter(callable $callback = null)
- {
- foreach ($this->items as $key => $value) {
- if (
- ($callback && !call_user_func($callback, $value, $key)) ||
- (!$callback && !(bool) $value)
- ) {
- unset($this->items[$key]);
- }
- }
-
- return $this;
- }
-}
diff --git a/src/system/src/Grav/Common/Language/Language.php b/src/system/src/Grav/Common/Language/Language.php
deleted file mode 100644
index 5dfe343..0000000
--- a/src/system/src/Grav/Common/Language/Language.php
+++ /dev/null
@@ -1,467 +0,0 @@
-grav = $grav;
- $this->config = $grav['config'];
- $this->languages = $this->config->get('system.languages.supported', []);
- $this->init();
- }
-
- /**
- * Initialize the default and enabled languages
- */
- public function init()
- {
- $this->default = reset($this->languages);
-
- if (empty($this->languages)) {
- $this->enabled = false;
- }
- }
-
- /**
- * Ensure that languages are enabled
- *
- * @return bool
- */
- public function enabled()
- {
- return $this->enabled;
- }
-
- /**
- * Gets the array of supported languages
- *
- * @return array
- */
- public function getLanguages()
- {
- return $this->languages;
- }
-
- /**
- * Sets the current supported languages manually
- *
- * @param $langs
- */
- public function setLanguages($langs)
- {
- $this->languages = $langs;
- $this->init();
- }
-
- /**
- * Gets a pipe-separated string of available languages
- *
- * @return string
- */
- public function getAvailable()
- {
- $languagesArray = $this->languages; //Make local copy
- sort($languagesArray);
- return implode('|', array_reverse($languagesArray));
- }
-
- /**
- * Gets language, active if set, else default
- *
- * @return mixed
- */
- public function getLanguage()
- {
- return $this->active ? $this->active : $this->default;
- }
-
- /**
- * Gets current default language
- *
- * @return mixed
- */
- public function getDefault()
- {
- return $this->default;
- }
-
- /**
- * Sets default language manually
- *
- * @param $lang
- *
- * @return bool
- */
- public function setDefault($lang)
- {
- if ($this->validate($lang)) {
- $this->default = $lang;
-
- return $lang;
- }
-
- return false;
- }
-
- /**
- * Gets current active language
- *
- * @return mixed
- */
- public function getActive()
- {
- return $this->active;
- }
-
- /**
- * Sets active language manually
- *
- * @param $lang
- *
- * @return bool
- */
- public function setActive($lang)
- {
- if ($this->validate($lang)) {
- $this->active = $lang;
-
- return $lang;
- }
-
- return false;
- }
-
- /**
- * Sets the active language based on the first part of the URL
- *
- * @param $uri
- *
- * @return mixed
- */
- public function setActiveFromUri($uri)
- {
- $regex = '/(^\/(' . $this->getAvailable() . '))(?:\/.*|$)/i';
-
- // if languages set
- if ($this->enabled()) {
- // try setting from prefix of URL (/en/blah/blah)
- if (preg_match($regex, $uri, $matches)) {
- $this->lang_in_url = true;
- $this->active = $matches[2];
- $uri = preg_replace("/\\" . $matches[1] . "/", '', $matches[0], 1);
-
- // store in session if different
- if ($this->config->get('system.session.enabled', false)
- && $this->config->get('system.languages.session_store_active', true)
- && $this->grav['session']->active_language != $this->active
- ) {
- $this->grav['session']->active_language = $this->active;
- }
- } else {
- // try getting from session, else no active
- if ($this->config->get('system.session.enabled', false) &&
- $this->config->get('system.languages.session_store_active', true)) {
- $this->active = $this->grav['session']->active_language ?: null;
- }
- // if still null, try from http_accept_language header
- if ($this->active === null && $this->config->get('system.languages.http_accept_language')) {
- $preferred = $this->getBrowserLanguages();
- foreach ($preferred as $lang) {
- if ($this->validate($lang)) {
- $this->active = $lang;
- break;
- }
- }
-
- }
- }
- }
-
- return $uri;
- }
-
- /**
- * Get's a URL prefix based on configuration
- *
- * @param null $lang
- * @return string
- */
- public function getLanguageURLPrefix($lang = null)
- {
- // if active lang is not passed in, use current active
- if (!$lang) {
- $lang = $this->getLanguage();
- }
-
- return $this->isIncludeDefaultLanguage($lang) ? '/' . $lang : '';
- }
-
- /**
- * Test to see if language is default and language should be included in the URL
- *
- * @param null $lang
- * @return bool
- */
- public function isIncludeDefaultLanguage($lang = null)
- {
- // if active lang is not passed in, use current active
- if (!$lang) {
- $lang = $this->getLanguage();
- }
-
- if ($this->default == $lang && $this->config->get('system.languages.include_default_lang') === false) {
- return false;
- } else {
- return true;
- }
- }
-
- /**
- * Simple getter to tell if a language was found in the URL
- *
- * @return bool
- */
- public function isLanguageInUrl()
- {
- return (bool) $this->lang_in_url;
- }
-
-
- /**
- * Gets an array of valid extensions with active first, then fallback extensions
- *
- * @return array
- */
- public function getFallbackPageExtensions($file_ext = null)
- {
- if (empty($this->page_extensions)) {
- if (empty($file_ext)) {
- $file_ext = CONTENT_EXT;
- }
-
- if ($this->enabled()) {
- $valid_lang_extensions = [];
- foreach ($this->languages as $lang) {
- $valid_lang_extensions[] = '.' . $lang . $file_ext;
- }
-
- if ($this->active) {
- $active_extension = '.' . $this->active . $file_ext;
- $key = array_search($active_extension, $valid_lang_extensions);
- unset($valid_lang_extensions[$key]);
- array_unshift($valid_lang_extensions, $active_extension);
- }
-
- $this->page_extensions = array_merge($valid_lang_extensions, (array)$file_ext);
- } else {
- $this->page_extensions = (array)$file_ext;
- }
- }
-
- return $this->page_extensions;
- }
-
- /**
- * Gets an array of languages with active first, then fallback languages
- *
- * @return array
- */
- public function getFallbackLanguages()
- {
- if (empty($this->fallback_languages)) {
- if ($this->enabled()) {
- $fallback_languages = $this->languages;
-
- if ($this->active) {
- $active_extension = $this->active;
- $key = array_search($active_extension, $fallback_languages);
- unset($fallback_languages[$key]);
- array_unshift($fallback_languages, $active_extension);
- }
- $this->fallback_languages = $fallback_languages;
- }
- // always add english in case a translation doesn't exist
- $this->fallback_languages[] = 'en';
- }
-
- return $this->fallback_languages;
- }
-
- /**
- * Ensures the language is valid and supported
- *
- * @param $lang
- *
- * @return bool
- */
- public function validate($lang)
- {
- if (in_array($lang, $this->languages)) {
- return true;
- }
-
- return false;
- }
-
- /**
- * Translate a key and possibly arguments into a string using current lang and fallbacks
- *
- * @param $args first argument is the lookup key value
- * other arguments can be passed and replaced in the translation with sprintf syntax
- * @param Array $languages
- * @param bool $array_support
- * @param bool $html_out
- *
- * @return string
- */
- public function translate($args, Array $languages = null, $array_support = false, $html_out = false)
- {
- if (is_array($args)) {
- $lookup = array_shift($args);
- } else {
- $lookup = $args;
- $args = [];
- }
-
-
- if ($this->config->get('system.languages.translations', true)) {
- if ($this->enabled() && $lookup) {
- if (empty($languages)) {
- if ($this->config->get('system.languages.translations_fallback', true)) {
- $languages = $this->getFallbackLanguages();
- } else {
- $languages = (array)$this->getDefault();
- }
- }
- } else {
- $languages = ['en'];
- }
-
- foreach ((array)$languages as $lang) {
- $translation = $this->getTranslation($lang, $lookup, $array_support);
-
- if ($translation) {
- if (count($args) >= 1) {
- return vsprintf($translation, $args);
- } else {
- return $translation;
- }
- }
- }
- }
-
- if ($html_out) {
- return '' . $lookup . '';
- } else {
- return $lookup;
- }
- }
-
- /**
- * Translate Array
- *
- * @param $key
- * @param $index
- * @param null $languages
- * @param bool $html_out
- *
- * @return string
- */
- public function translateArray($key, $index, $languages = null, $html_out = false)
- {
- if ($this->config->get('system.languages.translations', true)) {
- if ($this->enabled() && $key) {
- if (empty($languages)) {
- if ($this->config->get('system.languages.translations_fallback', true)) {
- $languages = $this->getFallbackLanguages();
- } else {
- $languages = (array)$this->getDefault();
- }
- }
- } else {
- $languages = ['en'];
- }
-
- foreach ((array)$languages as $lang) {
- $translation_array = (array)$this->config->getLanguages()->get($lang . '.' . $key, null);
- if ($translation_array && array_key_exists($index, $translation_array)) {
- return $translation_array[$index];
- }
- }
- }
-
- if ($html_out) {
- return '' . $key . '[' . $index . ']';
- } else {
- return $key . '[' . $index . ']';
- }
- }
-
- /**
- * Lookup the translation text for a given lang and key
- *
- * @param $lang lang code
- * @param $key key to lookup with
- * @param bool $array_support
- *
- * @return string
- */
- public function getTranslation($lang, $key, $array_support = false)
- {
- $translation = $this->config->getLanguages()->get($lang . '.' . $key, null);
- if (!$array_support && is_array($translation)) {
- return (string)array_shift($translation);
- }
-
- return $translation;
- }
-
- public function getBrowserLanguages($accept_langs = [])
- {
- if (empty($this->http_accept_language)) {
- if (empty($accept_langs) && isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
- $accept_langs = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
- } else {
- return $accept_langs;
- }
-
- foreach (explode(',', $accept_langs) as $k => $pref) {
- // split $pref again by ';q='
- // and decorate the language entries by inverted position
- if (false !== ($i = strpos($pref, ';q='))) {
- $langs[substr($pref, 0, $i)] = array((float)substr($pref, $i + 3), -$k);
- } else {
- $langs[$pref] = array(1, -$k);
- }
- }
- arsort($langs);
-
- // no need to undecorate, because we're only interested in the keys
- $this->http_accept_language = array_keys($langs);
- }
- return $this->http_accept_language;
- }
-
-}
diff --git a/src/system/src/Grav/Common/Language/LanguageCodes.php b/src/system/src/Grav/Common/Language/LanguageCodes.php
deleted file mode 100644
index 2683c8b..0000000
--- a/src/system/src/Grav/Common/Language/LanguageCodes.php
+++ /dev/null
@@ -1,774 +0,0 @@
- [
- "name" => "Abkhaz",
- "nativeName" => "аҧсуа"
- ],
- "aa" => [
- "name" => "Afar",
- "nativeName" => "Afaraf"
- ],
- "af" => [
- "name" => "Afrikaans",
- "nativeName" => "Afrikaans"
- ],
- "ak" => [
- "name" => "Akan",
- "nativeName" => "Akan"
- ],
- "sq" => [
- "name" => "Albanian",
- "nativeName" => "Shqip"
- ],
- "am" => [
- "name" => "Amharic",
- "nativeName" => "አማርኛ"
- ],
- "ar" => [
- "name" => "Arabic",
- "nativeName" => "العربية"
- ],
- "an" => [
- "name" => "Aragonese",
- "nativeName" => "Aragonés"
- ],
- "hy" => [
- "name" => "Armenian",
- "nativeName" => "Հայերեն"
- ],
- "as" => [
- "name" => "Assamese",
- "nativeName" => "অসমীয়া"
- ],
- "av" => [
- "name" => "Avaric",
- "nativeName" => "авар мацӀ"
- ],
- "ae" => [
- "name" => "Avestan",
- "nativeName" => "avesta"
- ],
- "ay" => [
- "name" => "Aymara",
- "nativeName" => "aymar aru"
- ],
- "az" => [
- "name" => "Azerbaijani",
- "nativeName" => "azərbaycan dili"
- ],
- "bm" => [
- "name" => "Bambara",
- "nativeName" => "bamanankan"
- ],
- "ba" => [
- "name" => "Bashkir",
- "nativeName" => "башҡорт теле"
- ],
- "eu" => [
- "name" => "Basque",
- "nativeName" => "euskara"
- ],
- "be" => [
- "name" => "Belarusian",
- "nativeName" => "Беларуская"
- ],
- "bn" => [
- "name" => "Bengali",
- "nativeName" => "বাংলা"
- ],
- "bh" => [
- "name" => "Bihari",
- "nativeName" => "भोजपुरी"
- ],
- "bi" => [
- "name" => "Bislama",
- "nativeName" => "Bislama"
- ],
- "bs" => [
- "name" => "Bosnian",
- "nativeName" => "bosanski jezik"
- ],
- "br" => [
- "name" => "Breton",
- "nativeName" => "brezhoneg"
- ],
- "bg" => [
- "name" => "Bulgarian",
- "nativeName" => "български език"
- ],
- "my" => [
- "name" => "Burmese",
- "nativeName" => "ဗမာစာ"
- ],
- "ca" => [
- "name" => "Catalan",
- "nativeName" => "Català"
- ],
- "ch" => [
- "name" => "Chamorro",
- "nativeName" => "Chamoru"
- ],
- "ce" => [
- "name" => "Chechen",
- "nativeName" => "нохчийн мотт"
- ],
- "ny" => [
- "name" => "Chichewa",
- "nativeName" => "chiCheŵa"
- ],
- "zh" => [
- "name" => "Chinese",
- "nativeName" => "中文"
- ],
- "cv" => [
- "name" => "Chuvash",
- "nativeName" => "чӑваш чӗлхи"
- ],
- "kw" => [
- "name" => "Cornish",
- "nativeName" => "Kernewek"
- ],
- "co" => [
- "name" => "Corsican",
- "nativeName" => "corsu"
- ],
- "cr" => [
- "name" => "Cree",
- "nativeName" => "ᓀᐦᐃᔭᐍᐏᐣ"
- ],
- "hr" => [
- "name" => "Croatian",
- "nativeName" => "hrvatski"
- ],
- "cs" => [
- "name" => "Czech",
- "nativeName" => "česky"
- ],
- "da" => [
- "name" => "Danish",
- "nativeName" => "dansk"
- ],
- "dv" => [
- "name" => "Divehi",
- "nativeName" => "ދިވެހި"
- ],
- "nl" => [
- "name" => "Dutch",
- "nativeName" => "Nederlands"
- ],
- "en" => [
- "name" => "English",
- "nativeName" => "English"
- ],
- "eo" => [
- "name" => "Esperanto",
- "nativeName" => "Esperanto"
- ],
- "et" => [
- "name" => "Estonian",
- "nativeName" => "eesti"
- ],
- "ee" => [
- "name" => "Ewe",
- "nativeName" => "Eʋegbe"
- ],
- "fo" => [
- "name" => "Faroese",
- "nativeName" => "føroyskt"
- ],
- "fj" => [
- "name" => "Fijian",
- "nativeName" => "vosa Vakaviti"
- ],
- "fi" => [
- "name" => "Finnish",
- "nativeName" => "suomi"
- ],
- "fr" => [
- "name" => "French",
- "nativeName" => "français"
- ],
- "ff" => [
- "name" => "Fula",
- "nativeName" => "Fulfulde"
- ],
- "gl" => [
- "name" => "Galician",
- "nativeName" => "Galego"
- ],
- "ka" => [
- "name" => "Georgian",
- "nativeName" => "ქართული"
- ],
- "de" => [
- "name" => "German",
- "nativeName" => "Deutsch"
- ],
- "el" => [
- "name" => "Greek",
- "nativeName" => "Ελληνικά"
- ],
- "gn" => [
- "name" => "Guaraní",
- "nativeName" => "Avañeẽ"
- ],
- "gu" => [
- "name" => "Gujarati",
- "nativeName" => "ગુજરાતી"
- ],
- "ht" => [
- "name" => "Haitian",
- "nativeName" => "Kreyòl ayisyen"
- ],
- "ha" => [
- "name" => "Hausa",
- "nativeName" => "هَوُسَ"
- ],
- "he" => [
- "name" => "Hebrew",
- "nativeName" => "עברית"
- ],
- "hz" => [
- "name" => "Herero",
- "nativeName" => "Otjiherero"
- ],
- "hi" => [
- "name" => "Hindi",
- "nativeName" => "हिन्दी"
- ],
- "ho" => [
- "name" => "Hiri Motu",
- "nativeName" => "Hiri Motu"
- ],
- "hu" => [
- "name" => "Hungarian",
- "nativeName" => "Magyar"
- ],
- "ia" => [
- "name" => "Interlingua",
- "nativeName" => "Interlingua"
- ],
- "id" => [
- "name" => "Indonesian",
- "nativeName" => "Bahasa Indonesia"
- ],
- "ie" => [
- "name" => "Interlingue",
- "nativeName" => "Interlingue"
- ],
- "ga" => [
- "name" => "Irish",
- "nativeName" => "Gaeilge"
- ],
- "ig" => [
- "name" => "Igbo",
- "nativeName" => "Asụsụ Igbo"
- ],
- "ik" => [
- "name" => "Inupiaq",
- "nativeName" => "Iñupiaq"
- ],
- "io" => [
- "name" => "Ido",
- "nativeName" => "Ido"
- ],
- "is" => [
- "name" => "Icelandic",
- "nativeName" => "Íslenska"
- ],
- "it" => [
- "name" => "Italian",
- "nativeName" => "Italiano"
- ],
- "iu" => [
- "name" => "Inuktitut",
- "nativeName" => "ᐃᓄᒃᑎᑐᑦ"
- ],
- "ja" => [
- "name" => "Japanese",
- "nativeName" => "日本語"
- ],
- "jv" => [
- "name" => "Javanese",
- "nativeName" => "basa Jawa"
- ],
- "kl" => [
- "name" => "Kalaallisut",
- "nativeName" => "kalaallisut"
- ],
- "kn" => [
- "name" => "Kannada",
- "nativeName" => "ಕನ್ನಡ"
- ],
- "kr" => [
- "name" => "Kanuri",
- "nativeName" => "Kanuri"
- ],
- "ks" => [
- "name" => "Kashmiri",
- "nativeName" => "कश्मीरी"
- ],
- "kk" => [
- "name" => "Kazakh",
- "nativeName" => "Қазақ тілі"
- ],
- "km" => [
- "name" => "Khmer",
- "nativeName" => "ភាសាខ្មែរ"
- ],
- "ki" => [
- "name" => "Kikuyu",
- "nativeName" => "Gĩkũyũ"
- ],
- "rw" => [
- "name" => "Kinyarwanda",
- "nativeName" => "Ikinyarwanda"
- ],
- "ky" => [
- "name" => "Kirghiz",
- "nativeName" => "кыргыз тили"
- ],
- "kv" => [
- "name" => "Komi",
- "nativeName" => "коми кыв"
- ],
- "kg" => [
- "name" => "Kongo",
- "nativeName" => "KiKongo"
- ],
- "ko" => [
- "name" => "Korean",
- "nativeName" => "한국어"
- ],
- "ku" => [
- "name" => "Kurdish",
- "nativeName" => "كوردی"
- ],
- "kj" => [
- "name" => "Kwanyama",
- "nativeName" => "Kuanyama"
- ],
- "la" => [
- "name" => "Latin",
- "nativeName" => "latine"
- ],
- "lb" => [
- "name" => "Luxembourgish",
- "nativeName" => "Lëtzebuergesch"
- ],
- "lg" => [
- "name" => "Luganda",
- "nativeName" => "Luganda"
- ],
- "li" => [
- "name" => "Limburgish",
- "nativeName" => "Limburgs"
- ],
- "ln" => [
- "name" => "Lingala",
- "nativeName" => "Lingála"
- ],
- "lo" => [
- "name" => "Lao",
- "nativeName" => "ພາສາລາວ"
- ],
- "lt" => [
- "name" => "Lithuanian",
- "nativeName" => "lietuvių kalba"
- ],
- "lu" => [
- "name" => "Luba-Katanga",
- "nativeName" => "Luba-Katanga"
- ],
- "lv" => [
- "name" => "Latvian",
- "nativeName" => "latviešu valoda"
- ],
- "gv" => [
- "name" => "Manx",
- "nativeName" => "Gaelg"
- ],
- "mk" => [
- "name" => "Macedonian",
- "nativeName" => "македонски јазик"
- ],
- "mg" => [
- "name" => "Malagasy",
- "nativeName" => "Malagasy fiteny"
- ],
- "ms" => [
- "name" => "Malay",
- "nativeName" => "بهاس ملايو"
- ],
- "ml" => [
- "name" => "Malayalam",
- "nativeName" => "മലയാളം"
- ],
- "mt" => [
- "name" => "Maltese",
- "nativeName" => "Malti"
- ],
- "mi" => [
- "name" => "Māori",
- "nativeName" => "te reo Māori"
- ],
- "mr" => [
- "name" => "Marathi",
- "nativeName" => "मराठी"
- ],
- "mh" => [
- "name" => "Marshallese",
- "nativeName" => "Kajin M̧ajeļ"
- ],
- "mn" => [
- "name" => "Mongolian",
- "nativeName" => "монгол"
- ],
- "na" => [
- "name" => "Nauru",
- "nativeName" => "Ekakairũ Naoero"
- ],
- "nv" => [
- "name" => "Navajo",
- "nativeName" => "Diné bizaad"
- ],
- "nb" => [
- "name" => "Norwegian Bokmål",
- "nativeName" => "Norsk bokmål"
- ],
- "nd" => [
- "name" => "North Ndebele",
- "nativeName" => "isiNdebele"
- ],
- "ne" => [
- "name" => "Nepali",
- "nativeName" => "नेपाली"
- ],
- "ng" => [
- "name" => "Ndonga",
- "nativeName" => "Owambo"
- ],
- "nn" => [
- "name" => "Norwegian Nynorsk",
- "nativeName" => "Norsk nynorsk"
- ],
- "no" => [
- "name" => "Norwegian",
- "nativeName" => "Norsk"
- ],
- "ii" => [
- "name" => "Nuosu",
- "nativeName" => "ꆈꌠ꒿ Nuosuhxop"
- ],
- "nr" => [
- "name" => "South Ndebele",
- "nativeName" => "isiNdebele"
- ],
- "oc" => [
- "name" => "Occitan",
- "nativeName" => "Occitan"
- ],
- "oj" => [
- "name" => "Ojibwe, Ojibwa",
- "nativeName" => "ᐊᓂᔑᓈᐯᒧᐎᓐ"
- ],
- "cu" => [
- "name" => "Church Slavic",
- "nativeName" => "ѩзыкъ словѣньскъ"
- ],
- "om" => [
- "name" => "Oromo",
- "nativeName" => "Afaan Oromoo"
- ],
- "or" => [
- "name" => "Oriya",
- "nativeName" => "ଓଡ଼ିଆ"
- ],
- "os" => [
- "name" => "Ossetian",
- "nativeName" => "ирон æвзаг"
- ],
- "pa" => [
- "name" => "Panjabi",
- "nativeName" => "ਪੰਜਾਬੀ"
- ],
- "pi" => [
- "name" => "Pāli",
- "nativeName" => "पाऴि"
- ],
- "fa" => [
- "name" => "Persian",
- "nativeName" => "فارسی"
- ],
- "pl" => [
- "name" => "Polish",
- "nativeName" => "polski"
- ],
- "ps" => [
- "name" => "Pashto",
- "nativeName" => "پښتو"
- ],
- "pt" => [
- "name" => "Portuguese",
- "nativeName" => "Português"
- ],
- "qu" => [
- "name" => "Quechua",
- "nativeName" => "Runa Simi"
- ],
- "rm" => [
- "name" => "Romansh",
- "nativeName" => "rumantsch grischun"
- ],
- "rn" => [
- "name" => "Kirundi",
- "nativeName" => "kiRundi"
- ],
- "ro" => [
- "name" => "Romanian",
- "nativeName" => "română"
- ],
- "ru" => [
- "name" => "Russian",
- "nativeName" => "Русский"
- ],
- "sa" => [
- "name" => "Sanskrit",
- "nativeName" => "संस्कृतम्"
- ],
- "sc" => [
- "name" => "Sardinian",
- "nativeName" => "sardu"
- ],
- "sd" => [
- "name" => "Sindhi",
- "nativeName" => "सिन्धी"
- ],
- "se" => [
- "name" => "Northern Sami",
- "nativeName" => "Davvisámegiella"
- ],
- "sm" => [
- "name" => "Samoan",
- "nativeName" => "gagana faa Samoa"
- ],
- "sg" => [
- "name" => "Sango",
- "nativeName" => "yângâ tî sängö"
- ],
- "sr" => [
- "name" => "Serbian",
- "nativeName" => "српски језик"
- ],
- "gd" => [
- "name" => "Scottish Gaelic",
- "nativeName" => "Gàidhlig"
- ],
- "sn" => [
- "name" => "Shona",
- "nativeName" => "chiShona"
- ],
- "si" => [
- "name" => "Sinhala",
- "nativeName" => "සිංහල"
- ],
- "sk" => [
- "name" => "Slovak",
- "nativeName" => "slovenčina"
- ],
- "sl" => [
- "name" => "Slovene",
- "nativeName" => "slovenščina"
- ],
- "so" => [
- "name" => "Somali",
- "nativeName" => "Soomaaliga"
- ],
- "st" => [
- "name" => "Southern Sotho",
- "nativeName" => "Sesotho"
- ],
- "es" => [
- "name" => "Spanish",
- "nativeName" => "Español"
- ],
- "su" => [
- "name" => "Sundanese",
- "nativeName" => "Basa Sunda"
- ],
- "sw" => [
- "name" => "Swahili",
- "nativeName" => "Kiswahili"
- ],
- "ss" => [
- "name" => "Swati",
- "nativeName" => "SiSwati"
- ],
- "sv" => [
- "name" => "Swedish",
- "nativeName" => "svenska"
- ],
- "ta" => [
- "name" => "Tamil",
- "nativeName" => "தமிழ்"
- ],
- "te" => [
- "name" => "Telugu",
- "nativeName" => "తెలుగు"
- ],
- "tg" => [
- "name" => "Tajik",
- "nativeName" => "тоҷикӣ"
- ],
- "th" => [
- "name" => "Thai",
- "nativeName" => "ไทย"
- ],
- "ti" => [
- "name" => "Tigrinya",
- "nativeName" => "ትግርኛ"
- ],
- "bo" => [
- "name" => "Tibetan",
- "nativeName" => "བོད་ཡིག"
- ],
- "tk" => [
- "name" => "Turkmen",
- "nativeName" => "Türkmen"
- ],
- "tl" => [
- "name" => "Tagalog",
- "nativeName" => "Wikang Tagalog"
- ],
- "tn" => [
- "name" => "Tswana",
- "nativeName" => "Setswana"
- ],
- "to" => [
- "name" => "Tonga",
- "nativeName" => "faka Tonga"
- ],
- "tr" => [
- "name" => "Turkish",
- "nativeName" => "Türkçe"
- ],
- "ts" => [
- "name" => "Tsonga",
- "nativeName" => "Xitsonga"
- ],
- "tt" => [
- "name" => "Tatar",
- "nativeName" => "татарча"
- ],
- "tw" => [
- "name" => "Twi",
- "nativeName" => "Twi"
- ],
- "ty" => [
- "name" => "Tahitian",
- "nativeName" => "Reo Tahiti"
- ],
- "ug" => [
- "name" => "Uighur",
- "nativeName" => "Uyƣurqə"
- ],
- "uk" => [
- "name" => "Ukrainian",
- "nativeName" => "українська"
- ],
- "ur" => [
- "name" => "Urdu",
- "nativeName" => "اردو"
- ],
- "uz" => [
- "name" => "Uzbek",
- "nativeName" => "zbek"
- ],
- "ve" => [
- "name" => "Venda",
- "nativeName" => "Tshivenḓa"
- ],
- "vi" => [
- "name" => "Vietnamese",
- "nativeName" => "Tiếng Việt"
- ],
- "vo" => [
- "name" => "Volapük",
- "nativeName" => "Volapük"
- ],
- "wa" => [
- "name" => "Walloon",
- "nativeName" => "Walon"
- ],
- "cy" => [
- "name" => "Welsh",
- "nativeName" => "Cymraeg"
- ],
- "wo" => [
- "name" => "Wolof",
- "nativeName" => "Wollof"
- ],
- "fy" => [
- "name" => "Western Frisian",
- "nativeName" => "Frysk"
- ],
- "xh" => [
- "name" => "Xhosa",
- "nativeName" => "isiXhosa"
- ],
- "yi" => [
- "name" => "Yiddish",
- "nativeName" => "ייִדיש"
- ],
- "yo" => [
- "name" => "Yoruba",
- "nativeName" => "Yorùbá"
- ],
- "za" => [
- "name" => "Zhuang",
- "nativeName" => "Saɯ cueŋƅ"
- ]
- ];
-
- public static function getName($code)
- {
- return static::get($code, 'name');
- }
-
- public static function getNativeName($code)
- {
- if (strlen($code) == 2) {
- return static::get($code, 'nativeName');
- } else {
- return static::get(substr($code, 0, 2), 'nativeName') . ' (' . substr($code, -2) . ')';
- }
- }
-
- public static function getNames(array $keys)
- {
- $results = [];
- foreach ($keys as $key) {
- if (isset(static::$codes[$key])) {
- $results[$key] = static::$codes[$key];
- }
-
- }
- return $results;
- }
-
- protected static function get($code, $type)
- {
- if (isset(static::$codes[$code][$type])) {
- return static::$codes[$code][$type];
- } else {
- return false;
- }
- }
-}
diff --git a/src/system/src/Grav/Common/Markdown/Parsedown.php b/src/system/src/Grav/Common/Markdown/Parsedown.php
deleted file mode 100644
index f453a54..0000000
--- a/src/system/src/Grav/Common/Markdown/Parsedown.php
+++ /dev/null
@@ -1,13 +0,0 @@
-init($page, $defaults);
- }
-
-}
diff --git a/src/system/src/Grav/Common/Markdown/ParsedownExtra.php b/src/system/src/Grav/Common/Markdown/ParsedownExtra.php
deleted file mode 100644
index 526e5f9..0000000
--- a/src/system/src/Grav/Common/Markdown/ParsedownExtra.php
+++ /dev/null
@@ -1,13 +0,0 @@
-init($page, $defaults);
- }
-}
diff --git a/src/system/src/Grav/Common/Markdown/ParsedownGravTrait.php b/src/system/src/Grav/Common/Markdown/ParsedownGravTrait.php
deleted file mode 100644
index 25da6ff..0000000
--- a/src/system/src/Grav/Common/Markdown/ParsedownGravTrait.php
+++ /dev/null
@@ -1,220 +0,0 @@
-page = $page;
- $this->pages = self::getGrav()['pages'];
- $this->BlockTypes['{'] [] = "TwigTag";
- $this->base_url = rtrim(self::getGrav()['base_url'] . self::getGrav()['pages']->base(), '/');
- $this->pages_dir = self::getGrav()['locator']->findResource('page://');
- $this->special_chars = array('>' => 'gt', '<' => 'lt', '"' => 'quot');
-
- if ($defaults === null) {
- $defaults = self::getGrav()['config']->get('system.pages.markdown');
- }
-
- $this->setBreaksEnabled($defaults['auto_line_breaks']);
- $this->setUrlsLinked($defaults['auto_url_links']);
- $this->setMarkupEscaped($defaults['escape_markup']);
- $this->setSpecialChars($defaults['special_chars']);
- }
-
- /**
- * Make the element function publicly accessible, Medium uses this to render from Twig
- *
- * @param array $Element
- * @return string markup
- */
- public function elementToHtml(array $Element)
- {
- return $this->element($Element);
- }
-
- /**
- * Setter for special chars
- *
- * @param $special_chars
- *
- * @return $this
- */
- function setSpecialChars($special_chars)
- {
- $this->special_chars = $special_chars;
-
- return $this;
- }
-
- /**
- * Ensure Twig tags are treated as block level items with no tags
- */
- protected function blockTwigTag($Line)
- {
- if (preg_match('/[{%|{{|{#].*[#}|}}|%}]/', $Line['body'], $matches)) {
- $Block = array(
- 'markup' => $Line['body'],
- );
- return $Block;
- }
- }
-
- protected function inlineSpecialCharacter($Excerpt)
- {
- if ($Excerpt['text'][0] === '&' && ! preg_match('/^?\w+;/', $Excerpt['text'])) {
- return array(
- 'markup' => '&',
- 'extent' => 1,
- );
- }
-
- if (isset($this->special_chars[$Excerpt['text'][0]])) {
- return array(
- 'markup' => '&'.$this->special_chars[$Excerpt['text'][0]].';',
- 'extent' => 1,
- );
- }
- }
-
- protected function inlineImage($excerpt)
- {
- if (preg_match($this->twig_link_regex, $excerpt['text'], $matches)) {
- $excerpt['text'] = str_replace($matches[1], '/', $excerpt['text']);
- $excerpt = parent::inlineImage($excerpt);
- $excerpt['element']['attributes']['src'] = $matches[1];
- $excerpt['extent'] = $excerpt['extent'] + strlen($matches[1]) - 1;
- return $excerpt;
- } else {
- $excerpt['type'] = 'image';
- $excerpt = parent::inlineImage($excerpt);
- }
-
- // Some stuff we will need
- $actions = array();
- $media = null;
-
- // if this is an image
- if (isset($excerpt['element']['attributes']['src'])) {
- $alt = $excerpt['element']['attributes']['alt'] ?: '';
- $title = $excerpt['element']['attributes']['title'] ?: '';
- $class = isset($excerpt['element']['attributes']['class']) ? $excerpt['element']['attributes']['class'] : '';
-
- //get the url and parse it
- $url = parse_url(htmlspecialchars_decode($excerpt['element']['attributes']['src']));
-
- // if there is no host set but there is a path, the file is local
- if (!isset($url['host']) && isset($url['path'])) {
- $path_parts = pathinfo($url['path']);
-
- // get the local path to page media if possible
- if ($path_parts['dirname'] == $this->page->url(false, false, false)) {
- $url['path'] = urldecode($path_parts['basename']);
- // get the media objects for this page
- $media = $this->page->media();
- } else {
- // see if this is an external page to this one
- $page_route = str_replace($this->base_url, '', $path_parts['dirname']);
-
- $ext_page = $this->pages->dispatch($page_route, true);
- if ($ext_page) {
- $media = $ext_page->media();
- $url['path'] = urldecode($path_parts['basename']);
- }
- }
-
- // if there is a media file that matches the path referenced..
- if ($media && isset($media->all()[$url['path']])) {
- // get the medium object
- $medium = $media->all()[$url['path']];
-
- // if there is a query, then parse it and build action calls
- if (isset($url['query'])) {
- $actions = array_reduce(explode('&', $url['query']), function ($carry, $item) {
- $parts = explode('=', $item, 2);
- $value = isset($parts[1]) ? $parts[1] : null;
- $carry[] = [ 'method' => $parts[0], 'params' => $value ];
-
- return $carry;
- }, []);
- }
-
- // loop through actions for the image and call them
- foreach ($actions as $action) {
- $medium = call_user_func_array(array($medium, $action['method']), explode(',', urldecode($action['params'])));
- }
-
- if (isset($url['fragment'])) {
- $medium->urlHash($url['fragment']);
- }
-
- $excerpt['element'] = $medium->parseDownElement($title, $alt, $class);
-
- } else {
- // not a current page media file, see if it needs converting to relative
- $excerpt['element']['attributes']['src'] = Uri::buildUrl($url);
- }
- }
- }
-
- return $excerpt;
- }
-
- protected function inlineLink($excerpt)
- {
- if (isset($excerpt['type'])) {
- $type = $excerpt['type'];
- } else {
- $type = 'link';
- }
-
- // do some trickery to get around Parsedown requirement for valid URL if its Twig in there
- if (preg_match($this->twig_link_regex, $excerpt['text'], $matches)) {
- $excerpt['text'] = str_replace($matches[1], '/', $excerpt['text']);
- $excerpt = parent::inlineLink($excerpt);
- $excerpt['element']['attributes']['href'] = $matches[1];
- $excerpt['extent'] = $excerpt['extent'] + strlen($matches[1]) - 1;
- return $excerpt;
- } else {
- $excerpt = parent::inlineLink($excerpt);
- }
-
- // if this is a link
- if (isset($excerpt['element']['attributes']['href'])) {
- $url = parse_url(htmlspecialchars_decode($excerpt['element']['attributes']['href']));
-
- // if there is no scheme, the file is local
- if (!isset($url['scheme']) && (count($url) > 0)) {
- // convert the URl is required
- $excerpt['element']['attributes']['href'] = Uri::convertUrl($this->page, Uri::buildUrl($url), $type);
- }
- }
-
- return $excerpt;
- }
-}
diff --git a/src/system/src/Grav/Common/Page/Collection.php b/src/system/src/Grav/Common/Page/Collection.php
deleted file mode 100644
index b5836bd..0000000
--- a/src/system/src/Grav/Common/Page/Collection.php
+++ /dev/null
@@ -1,458 +0,0 @@
-params = $params;
- $this->pages = $pages ? $pages : Grav::instance()->offsetGet('pages');
- }
-
- public function params()
- {
- return $this->params;
- }
-
- /**
- * Add a single page to a collection
- *
- * @param Page $page
- * @return $this
- */
- public function addPage(Page $page)
- {
- $this->items[$page->path()] = ['slug' => $page->slug()];
- return $this;
- }
-
- /**
- *
- * Create a copy of this collection
- *
- * @return static
- */
- public function copy()
- {
- return new static($this->items, $this->params, $this->pages);
- }
-
- /**
- * Set parameters to the Collection
- *
- * @param array $params
- * @return $this
- */
- public function setParams(array $params)
- {
- $this->params = array_merge($this->params, $params);
- return $this;
- }
-
- /**
- * Returns current page.
- *
- * @return Page
- */
- public function current()
- {
- $current = parent::key();
- return $this->pages->get($current);
- }
-
- /**
- * Returns current slug.
- *
- * @return mixed
- */
- public function key()
- {
- $current = parent::current();
- return $current['slug'];
- }
-
- /**
- * Returns the value at specified offset.
- *
- * @param mixed $offset The offset to retrieve.
- * @return mixed Can return all value types.
- */
- public function offsetGet($offset)
- {
- return !empty($this->items[$offset]) ? $this->pages->get($offset) : null;
- }
-
- /**
- * Remove item from the list.
- *
- * @param Page|string|null $key
- * @return $this|void
- * @throws \InvalidArgumentException
- */
- public function remove($key = null)
- {
- if ($key instanceof Page) {
- $key = $key->path();
- } elseif (is_null($key)) {
- $key = key($this->items);
- }
- if (!is_string($key)) {
- throw new \InvalidArgumentException('Invalid argument $key.');
- }
-
- parent::remove($key);
- return $this;
- }
-
- /**
- * Reorder collection.
- *
- * @param string $by
- * @param string $dir
- * @param array $manual
- * @return $this
- */
- public function order($by, $dir = 'asc', $manual = null)
- {
- $this->items = $this->pages->sortCollection($this, $by, $dir, $manual);
-
- return $this;
- }
-
- /**
- * Check to see if this item is the first in the collection.
- *
- * @param string $path
- * @return boolean True if item is first.
- */
- public function isFirst($path)
- {
- if ($this->items && $path == array_keys($this->items)[0]) {
- return true;
- } else {
- return false;
- }
- }
-
- /**
- * Check to see if this item is the last in the collection.
- *
- * @param string $path
- * @return boolean True if item is last.
- */
- public function isLast($path)
- {
- if ($this->items && $path == array_keys($this->items)[count($this->items)-1]) {
- return true;
- } else {
- return false;
- }
- }
-
- /**
- * Gets the previous sibling based on current position.
- *
- * @param string $path
- * @return Page The previous item.
- */
- public function prevSibling($path)
- {
- return $this->adjacentSibling($path, -1);
- }
-
- /**
- * Gets the next sibling based on current position.
- *
- * @param string $path
- * @return Page The next item.
- */
- public function nextSibling($path)
- {
- return $this->adjacentSibling($path, 1);
- }
-
- /**
- * Returns the adjacent sibling based on a direction.
- *
- * @param string $path
- * @param integer $direction either -1 or +1
- * @return Page The sibling item.
- */
- public function adjacentSibling($path, $direction = 1)
- {
- $values = array_keys($this->items);
- $keys = array_flip($values);
-
- if (array_key_exists($path, $keys)) {
- $index = $keys[$path] - $direction;
-
- return isset($values[$index]) ? $this->offsetGet($values[$index]) : $this;
- }
- return $this;
-
- }
-
- /**
- * Returns the item in the current position.
- *
- * @param string $path the path the item
- * @return Page Item in the array the the current position.
- */
- public function currentPosition($path)
- {
- return array_search($path, array_keys($this->items));
- }
-
- /**
- * Returns the items between a set of date ranges of either the page date field (default) or
- * an arbitrary datetime page field where end date is optional
- * Dates can be passed in as text that strtotime() can process
- * http://php.net/manual/en/function.strtotime.php
- *
- * @param $startDate
- * @param bool $endDate
- * @param $field
- *
- * @return $this
- * @throws \Exception
- */
- public function dateRange($startDate, $endDate = false, $field = false)
- {
- $start = Utils::date2timestamp($startDate);
- $end = $endDate ? Utils::date2timestamp($endDate) : strtotime("now +1000 years");
-
- $date_range = [];
-
- foreach ($this->items as $path => $slug) {
- $page = $this->pages->get($path);
- if ($page !== null) {
- $date = $field ? strtotime($page->value($field)) : $page->date();
-
- if ($date > $start && $date < $end) {
- $date_range[$path] = $slug;
- }
- }
- }
- $this->items = $date_range;
- return $this;
- }
-
- /**
- * Creates new collection with only visible pages
- *
- * @return Collection The collection with only visible pages
- */
- public function visible()
- {
- $visible = [];
-
- foreach ($this->items as $path => $slug) {
- $page = $this->pages->get($path);
- if ($page !== null && $page->visible()) {
- $visible[$path] = $slug;
- }
- }
- $this->items = $visible;
- return $this;
- }
-
- /**
- * Creates new collection with only non-visible pages
- *
- * @return Collection The collection with only non-visible pages
- */
- public function nonVisible()
- {
- $visible = [];
-
- foreach ($this->items as $path => $slug) {
- $page = $this->pages->get($path);
- if ($page !== null && !$page->visible()) {
- $visible[$path] = $slug;
- }
- }
- $this->items = $visible;
- return $this;
- }
-
- /**
- * Creates new collection with only modular pages
- *
- * @return Collection The collection with only modular pages
- */
- public function modular()
- {
- $modular = [];
-
- foreach ($this->items as $path => $slug) {
- $page = $this->pages->get($path);
- if ($page !== null && $page->modular()) {
- $modular[$path] = $slug;
- }
- }
- $this->items = $modular;
- return $this;
- }
-
- /**
- * Creates new collection with only non-modular pages
- *
- * @return Collection The collection with only non-modular pages
- */
- public function nonModular()
- {
- $modular = [];
-
- foreach ($this->items as $path => $slug) {
- $page = $this->pages->get($path);
- if ($page !== null && !$page->modular()) {
- $modular[$path] = $slug;
- }
- }
- $this->items = $modular;
- return $this;
- }
-
- /**
- * Creates new collection with only published pages
- *
- * @return Collection The collection with only published pages
- */
- public function published()
- {
- $published = [];
-
- foreach ($this->items as $path => $slug) {
- $page = $this->pages->get($path);
- if ($page !== null && $page->published()) {
- $published[$path] = $slug;
- }
- }
- $this->items = $published;
- return $this;
- }
-
- /**
- * Creates new collection with only non-published pages
- *
- * @return Collection The collection with only non-published pages
- */
- public function nonPublished()
- {
- $published = [];
-
- foreach ($this->items as $path => $slug) {
- $page = $this->pages->get($path);
- if ($page !== null && !$page->published()) {
- $published[$path] = $slug;
- }
- }
- $this->items = $published;
- return $this;
- }
-
- /**
- * Creates new collection with only routable pages
- *
- * @return Collection The collection with only routable pages
- */
- public function routable()
- {
- $routable = [];
-
- foreach ($this->items as $path => $slug) {
- $page = $this->pages->get($path);
-
- if ($page !== null && $page->routable()) {
- $routable[$path] = $slug;
- }
- }
-
- $this->items = $routable;
- return $this;
- }
-
- /**
- * Creates new collection with only non-routable pages
- *
- * @return Collection The collection with only non-routable pages
- */
- public function nonRoutable()
- {
- $routable = [];
-
- foreach ($this->items as $path => $slug) {
- $page = $this->pages->get($path);
- if ($page !== null && !$page->routable()) {
- $routable[$path] = $slug;
- }
- }
- $this->items = $routable;
- return $this;
- }
-
- /**
- * Creates new collection with only pages of the specified type
- *
- * @return Collection The collection
- */
- public function ofType($type)
- {
- $items = [];
-
- foreach ($this->items as $path => $slug) {
- $page = $this->pages->get($path);
- if ($page !== null && $page->template() == $type) {
- $items[$path] = $slug;
- }
- }
-
- $this->items = $items;
- return $this;
- }
-
- /**
- * Creates new collection with only pages of one of the specified types
- *
- * @return Collection The collection
- */
- public function ofOneOfTheseTypes($types)
- {
- $items = [];
-
- foreach ($this->items as $path => $slug) {
- $page = $this->pages->get($path);
- if ($page !== null && in_array($page->template(), $types)) {
- $items[$path] = $slug;
- }
- }
-
- $this->items = $items;
- return $this;
- }
-
-
-
-}
diff --git a/src/system/src/Grav/Common/Page/Header.php b/src/system/src/Grav/Common/Page/Header.php
deleted file mode 100644
index 4be8262..0000000
--- a/src/system/src/Grav/Common/Page/Header.php
+++ /dev/null
@@ -1,11 +0,0 @@
-path = $path;
-
- $iterator = new \FilesystemIterator($path, \FilesystemIterator::UNIX_PATHS | \FilesystemIterator::SKIP_DOTS);
-
- $media = [];
-
- /** @var \DirectoryIterator $info */
- foreach ($iterator as $path => $info) {
- // Ignore folders and Markdown files.
- if (!$info->isFile() || $info->getExtension() == 'md' || $info->getBasename() === '.DS_Store') {
- continue;
- }
-
- // Find out what type we're dealing with
- list($basename, $ext, $type, $extra) = $this->getFileParts($info->getFilename());
-
- $media["{$basename}.{$ext}"] = isset($media["{$basename}.{$ext}"]) ? $media["{$basename}.{$ext}"] : [];
-
- if ($type === 'alternative') {
- $media["{$basename}.{$ext}"][$type] = isset($media["{$basename}.{$ext}"][$type]) ? $media["{$basename}.{$ext}"][$type] : [];
- $media["{$basename}.{$ext}"][$type][$extra] = [ 'file' => $path, 'size' => $info->getSize() ];
- } else {
- $media["{$basename}.{$ext}"][$type] = [ 'file' => $path, 'size' => $info->getSize() ];
- }
- }
-
- foreach ($media as $name => $types) {
- // First prepare the alternatives in case there is no base medium
- if (!empty($types['alternative'])) {
- foreach ($types['alternative'] as $ratio => &$alt) {
- $alt['file'] = MediumFactory::fromFile($alt['file']);
-
- if (!$alt['file']) {
- unset($types['alternative'][$ratio]);
- } else {
- $alt['file']->set('size', $alt['size']);
- }
- }
- }
-
- // Create the base medium
- if (!empty($types['base'])) {
- $medium = MediumFactory::fromFile($types['base']['file']);
- $medium && $medium->set('size', $types['base']['size']);
- } else if (!empty($types['alternative'])) {
- $altMedium = reset($types['alternative']);
- $ratio = key($types['alternative']);
-
- $altMedium = $altMedium['file'];
-
- $medium = MediumFactory::scaledFromMedium($altMedium, $ratio, 1)['file'];
- }
-
- if (!$medium) {
- continue;
- }
-
- if (!empty($types['meta'])) {
- $medium->addMetaFile($types['meta']['file']);
- }
-
- if (!empty($types['thumb'])) {
- // We will not turn it into medium yet because user might never request the thumbnail
- // not wasting any resources on that, maybe we should do this for medium in general?
- $medium->set('thumbnails.page', $types['thumb']['file']);
- }
-
- // Build missing alternatives
- if (!empty($types['alternative'])) {
- $alternatives = $types['alternative'];
-
- $max = max(array_keys($alternatives));
-
- for ($i=2; $i < $max; $i++) {
- if (isset($alternatives[$i])) {
- continue;
- }
-
- $types['alternative'][$i] = MediumFactory::scaledFromMedium($alternatives[$max]['file'], $max, $i);
- }
-
- foreach ($types['alternative'] as $ratio => $altMedium) {
- $medium->addAlternative($ratio, $altMedium['file']);
- }
- }
-
- $this->add($name, $medium);
- }
- }
-
- /**
- * Get medium by filename.
- *
- * @param string $filename
- * @return Medium|null
- */
- public function get($filename)
- {
- return isset($this->instances[$filename]) ? $this->instances[$filename] : null;
- }
-
- /**
- * Get a list of all media.
- *
- * @return array|Medium[]
- */
- public function all()
- {
- ksort($this->instances, SORT_NATURAL | SORT_FLAG_CASE);
- return $this->instances;
- }
-
- /**
- * Get a list of all image media.
- *
- * @return array|Medium[]
- */
- public function images()
- {
- ksort($this->images, SORT_NATURAL | SORT_FLAG_CASE);
- return $this->images;
- }
-
- /**
- * Get a list of all video media.
- *
- * @return array|Medium[]
- */
- public function videos()
- {
- ksort($this->videos, SORT_NATURAL | SORT_FLAG_CASE);
- return $this->videos;
- }
-
- /**
- * Get a list of all audio media.
- *
- * @return array|Medium[]
- */
- public function audios()
- {
- ksort($this->audios, SORT_NATURAL | SORT_FLAG_CASE);
- return $this->audios;
- }
-
- /**
- * Get a list of all file media.
- *
- * @return array|Medium[]
- */
- public function files()
- {
- ksort($this->files, SORT_NATURAL | SORT_FLAG_CASE);
- return $this->files;
- }
-
- /**
- * @internal
- */
- protected function add($name, $file)
- {
- $this->instances[$name] = $file;
- switch ($file->type) {
- case 'image':
- $this->images[$name] = $file;
- break;
- case 'video':
- $this->videos[$name] = $file;
- break;
- case 'audio':
- $this->audios[$name] = $file;
- break;
- default:
- $this->files[$name] = $file;
- }
- }
-
- /**
- * Get filename, extension and meta part.
- *
- * @param string $filename
- * @return array
- */
- protected function getFileParts($filename)
- {
- $fileParts = explode('.', $filename);
-
- $name = array_shift($fileParts);
- $type = 'base';
- $extra = null;
-
- if (preg_match('/(.*)@(\d+)x\.(.*)$/', $filename, $matches)) {
- $name = $matches[1];
- $extension = $matches[3];
- $extra = (int) $matches[2];
- $type = 'alternative';
-
- if ($extra === 1) {
- $type = 'base';
- $extra = null;
- }
- } else {
- $extension = null;
- while (($part = array_shift($fileParts)) !== null) {
- if ($part != 'meta' && $part != 'thumb') {
- if (isset($extension)) {
- $name .= '.' . $extension;
- }
- $extension = $part;
- } else {
- $type = $part;
- $extra = '.' . $part . '.' . implode('.', $fileParts);
- break;
- }
- }
- }
-
- return array($name, $extension, $type, $extra);
- }
-}
diff --git a/src/system/src/Grav/Common/Page/Medium/AudioMedium.php b/src/system/src/Grav/Common/Page/Medium/AudioMedium.php
deleted file mode 100644
index 0eaafd6..0000000
--- a/src/system/src/Grav/Common/Page/Medium/AudioMedium.php
+++ /dev/null
@@ -1,45 +0,0 @@
-url($reset);
-
- return [
- 'name' => 'audio',
- 'text' => '