no podcast

This commit is contained in:
qo-op 2020-06-08 02:23:08 +02:00
parent f529525469
commit 839e2c3bb6
209 changed files with 0 additions and 110282 deletions

View File

@ -1,20 +0,0 @@
categories.xml
config.php
freebox-content.txt
rsscache_*
feed.xml
media/*
images/*
!media/index.htm
!images/itunes_image.jpg
!images/smiley_default_freebox.png

View File

@ -1,674 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
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.
{one line to give the program's name and a brief idea of what it does.}
Copyright (C) {year} {name of author}
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 <http://www.gnu.org/licenses/>.
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:
{project} Copyright (C) {year} {fullname}
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
<http://www.gnu.org/licenses/>.
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
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

View File

@ -1,26 +0,0 @@
# Podcast Generator
Podcast Generator (PG) is an open source Content Management System written in PHP
and specifically designed for podcast publishing. It provides the user with the tools
to easily manage all of the aspects related to the publication of a podcast, from
the upload of episodes to its submission to the iTunes store.
Visit the **official website** for more information, documentation, demo and to download the latest stable release:
http://podcastgenerator.net
## Download the latest release
Download the latest stable release on the official website:
http://podcastgenerator.net/download
## Documentation
A comprehensive documentation is available at:
http://podcastgenerator.net/documentation
## Demo
A fully-functional live demo of Podcast generator is available at:
http://podcastgenerator.net/demo

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,29 +0,0 @@
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
// also https://github.com/JamesHeinrich/getID3 //
/////////////////////////////////////////////////////////////////
*****************************************************************
*****************************************************************
getID3() is released under multiple licenses. You may choose
from the following licenses, and use getID3 according to the
terms of the license most suitable to your project.
GNU GPL: https://gnu.org/licenses/gpl.html (v3)
https://gnu.org/licenses/old-licenses/gpl-2.0.html (v2)
https://gnu.org/licenses/old-licenses/gpl-1.0.html (v1)
GNU LGPL: https://gnu.org/licenses/lgpl.html (v3)
Mozilla MPL: http://www.mozilla.org/MPL/2.0/ (v2)
getID3 Commercial License: http://getid3.org/#gCL (payment required)
*****************************************************************
*****************************************************************
Copies of each of the above licenses are included in the 'licenses'
directory of the getID3 distribution.

View File

@ -1,513 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
// also https://github.com/JamesHeinrich/getID3 //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.archive.zip.php //
// module for analyzing pkZip files //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
class getid3_zip extends getid3_handler
{
public function Analyze() {
$info = &$this->getid3->info;
$info['fileformat'] = 'zip';
$info['zip']['encoding'] = 'ISO-8859-1';
$info['zip']['files'] = array();
$info['zip']['compressed_size'] = 0;
$info['zip']['uncompressed_size'] = 0;
$info['zip']['entries_count'] = 0;
if (!getid3_lib::intValueSupported($info['filesize'])) {
$info['error'][] = 'File is larger than '.round(PHP_INT_MAX / 1073741824).'GB, not supported by PHP';
return false;
} else {
$EOCDsearchData = '';
$EOCDsearchCounter = 0;
while ($EOCDsearchCounter++ < 512) {
$this->fseek(-128 * $EOCDsearchCounter, SEEK_END);
$EOCDsearchData = $this->fread(128).$EOCDsearchData;
if (strstr($EOCDsearchData, 'PK'."\x05\x06")) {
$EOCDposition = strpos($EOCDsearchData, 'PK'."\x05\x06");
$this->fseek((-128 * $EOCDsearchCounter) + $EOCDposition, SEEK_END);
$info['zip']['end_central_directory'] = $this->ZIPparseEndOfCentralDirectory();
$this->fseek($info['zip']['end_central_directory']['directory_offset']);
$info['zip']['entries_count'] = 0;
while ($centraldirectoryentry = $this->ZIPparseCentralDirectory($this->getid3->fp)) {
$info['zip']['central_directory'][] = $centraldirectoryentry;
$info['zip']['entries_count']++;
$info['zip']['compressed_size'] += $centraldirectoryentry['compressed_size'];
$info['zip']['uncompressed_size'] += $centraldirectoryentry['uncompressed_size'];
//if ($centraldirectoryentry['uncompressed_size'] > 0) { zero-byte files are valid
if (!empty($centraldirectoryentry['filename'])) {
$info['zip']['files'] = getid3_lib::array_merge_clobber($info['zip']['files'], getid3_lib::CreateDeepArray($centraldirectoryentry['filename'], '/', $centraldirectoryentry['uncompressed_size']));
}
}
if ($info['zip']['entries_count'] == 0) {
$info['error'][] = 'No Central Directory entries found (truncated file?)';
return false;
}
if (!empty($info['zip']['end_central_directory']['comment'])) {
$info['zip']['comments']['comment'][] = $info['zip']['end_central_directory']['comment'];
}
if (isset($info['zip']['central_directory'][0]['compression_method'])) {
$info['zip']['compression_method'] = $info['zip']['central_directory'][0]['compression_method'];
}
if (isset($info['zip']['central_directory'][0]['flags']['compression_speed'])) {
$info['zip']['compression_speed'] = $info['zip']['central_directory'][0]['flags']['compression_speed'];
}
if (isset($info['zip']['compression_method']) && ($info['zip']['compression_method'] == 'store') && !isset($info['zip']['compression_speed'])) {
$info['zip']['compression_speed'] = 'store';
}
// secondary check - we (should) already have all the info we NEED from the Central Directory above, but scanning each
// Local File Header entry will
foreach ($info['zip']['central_directory'] as $central_directory_entry) {
$this->fseek($central_directory_entry['entry_offset']);
if ($fileentry = $this->ZIPparseLocalFileHeader()) {
$info['zip']['entries'][] = $fileentry;
} else {
$info['warning'][] = 'Error parsing Local File Header at offset '.$central_directory_entry['entry_offset'];
}
}
if (!empty($info['zip']['files']['[Content_Types].xml']) &&
!empty($info['zip']['files']['_rels']['.rels']) &&
!empty($info['zip']['files']['docProps']['app.xml']) &&
!empty($info['zip']['files']['docProps']['core.xml'])) {
// http://technet.microsoft.com/en-us/library/cc179224.aspx
$info['fileformat'] = 'zip.msoffice';
if (!empty($ThisFileInfo['zip']['files']['ppt'])) {
$info['mime_type'] = 'application/vnd.openxmlformats-officedocument.presentationml.presentation';
} elseif (!empty($ThisFileInfo['zip']['files']['xl'])) {
$info['mime_type'] = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
} elseif (!empty($ThisFileInfo['zip']['files']['word'])) {
$info['mime_type'] = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
}
}
return true;
}
}
}
if (!$this->getZIPentriesFilepointer()) {
unset($info['zip']);
$info['fileformat'] = '';
$info['error'][] = 'Cannot find End Of Central Directory (truncated file?)';
return false;
}
// central directory couldn't be found and/or parsed
// scan through actual file data entries, recover as much as possible from probable trucated file
if ($info['zip']['compressed_size'] > ($info['filesize'] - 46 - 22)) {
$info['error'][] = 'Warning: Truncated file! - Total compressed file sizes ('.$info['zip']['compressed_size'].' bytes) is greater than filesize minus Central Directory and End Of Central Directory structures ('.($info['filesize'] - 46 - 22).' bytes)';
}
$info['error'][] = 'Cannot find End Of Central Directory - returned list of files in [zip][entries] array may not be complete';
foreach ($info['zip']['entries'] as $key => $valuearray) {
$info['zip']['files'][$valuearray['filename']] = $valuearray['uncompressed_size'];
}
return true;
}
public function getZIPHeaderFilepointerTopDown() {
$info = &$this->getid3->info;
$info['fileformat'] = 'zip';
$info['zip']['compressed_size'] = 0;
$info['zip']['uncompressed_size'] = 0;
$info['zip']['entries_count'] = 0;
rewind($this->getid3->fp);
while ($fileentry = $this->ZIPparseLocalFileHeader()) {
$info['zip']['entries'][] = $fileentry;
$info['zip']['entries_count']++;
}
if ($info['zip']['entries_count'] == 0) {
$info['error'][] = 'No Local File Header entries found';
return false;
}
$info['zip']['entries_count'] = 0;
while ($centraldirectoryentry = $this->ZIPparseCentralDirectory($this->getid3->fp)) {
$info['zip']['central_directory'][] = $centraldirectoryentry;
$info['zip']['entries_count']++;
$info['zip']['compressed_size'] += $centraldirectoryentry['compressed_size'];
$info['zip']['uncompressed_size'] += $centraldirectoryentry['uncompressed_size'];
}
if ($info['zip']['entries_count'] == 0) {
$info['error'][] = 'No Central Directory entries found (truncated file?)';
return false;
}
if ($EOCD = $this->ZIPparseEndOfCentralDirectory()) {
$info['zip']['end_central_directory'] = $EOCD;
} else {
$info['error'][] = 'No End Of Central Directory entry found (truncated file?)';
return false;
}
if (!empty($info['zip']['end_central_directory']['comment'])) {
$info['zip']['comments']['comment'][] = $info['zip']['end_central_directory']['comment'];
}
return true;
}
public function getZIPentriesFilepointer() {
$info = &$this->getid3->info;
$info['zip']['compressed_size'] = 0;
$info['zip']['uncompressed_size'] = 0;
$info['zip']['entries_count'] = 0;
rewind($this->getid3->fp);
while ($fileentry = $this->ZIPparseLocalFileHeader()) {
$info['zip']['entries'][] = $fileentry;
$info['zip']['entries_count']++;
$info['zip']['compressed_size'] += $fileentry['compressed_size'];
$info['zip']['uncompressed_size'] += $fileentry['uncompressed_size'];
}
if ($info['zip']['entries_count'] == 0) {
$info['error'][] = 'No Local File Header entries found';
return false;
}
return true;
}
public function ZIPparseLocalFileHeader() {
$LocalFileHeader['offset'] = $this->ftell();
$ZIPlocalFileHeader = $this->fread(30);
$LocalFileHeader['raw']['signature'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 0, 4));
if ($LocalFileHeader['raw']['signature'] != 0x04034B50) { // "PK\x03\x04"
// invalid Local File Header Signature
$this->fseek($LocalFileHeader['offset']); // seek back to where filepointer originally was so it can be handled properly
return false;
}
$LocalFileHeader['raw']['extract_version'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 4, 2));
$LocalFileHeader['raw']['general_flags'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 6, 2));
$LocalFileHeader['raw']['compression_method'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 8, 2));
$LocalFileHeader['raw']['last_mod_file_time'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 10, 2));
$LocalFileHeader['raw']['last_mod_file_date'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 12, 2));
$LocalFileHeader['raw']['crc_32'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 14, 4));
$LocalFileHeader['raw']['compressed_size'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 18, 4));
$LocalFileHeader['raw']['uncompressed_size'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 22, 4));
$LocalFileHeader['raw']['filename_length'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 26, 2));
$LocalFileHeader['raw']['extra_field_length'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 28, 2));
$LocalFileHeader['extract_version'] = sprintf('%1.1f', $LocalFileHeader['raw']['extract_version'] / 10);
$LocalFileHeader['host_os'] = $this->ZIPversionOSLookup(($LocalFileHeader['raw']['extract_version'] & 0xFF00) >> 8);
$LocalFileHeader['compression_method'] = $this->ZIPcompressionMethodLookup($LocalFileHeader['raw']['compression_method']);
$LocalFileHeader['compressed_size'] = $LocalFileHeader['raw']['compressed_size'];
$LocalFileHeader['uncompressed_size'] = $LocalFileHeader['raw']['uncompressed_size'];
$LocalFileHeader['flags'] = $this->ZIPparseGeneralPurposeFlags($LocalFileHeader['raw']['general_flags'], $LocalFileHeader['raw']['compression_method']);
$LocalFileHeader['last_modified_timestamp'] = $this->DOStime2UNIXtime($LocalFileHeader['raw']['last_mod_file_date'], $LocalFileHeader['raw']['last_mod_file_time']);
$FilenameExtrafieldLength = $LocalFileHeader['raw']['filename_length'] + $LocalFileHeader['raw']['extra_field_length'];
if ($FilenameExtrafieldLength > 0) {
$ZIPlocalFileHeader .= $this->fread($FilenameExtrafieldLength);
if ($LocalFileHeader['raw']['filename_length'] > 0) {
$LocalFileHeader['filename'] = substr($ZIPlocalFileHeader, 30, $LocalFileHeader['raw']['filename_length']);
}
if ($LocalFileHeader['raw']['extra_field_length'] > 0) {
$LocalFileHeader['raw']['extra_field_data'] = substr($ZIPlocalFileHeader, 30 + $LocalFileHeader['raw']['filename_length'], $LocalFileHeader['raw']['extra_field_length']);
}
}
if ($LocalFileHeader['compressed_size'] == 0) {
// *Could* be a zero-byte file
// But could also be a file written on the fly that didn't know compressed filesize beforehand.
// Correct compressed filesize should be in the data_descriptor located after this file data, and also in Central Directory (at end of zip file)
if (!empty($this->getid3->info['zip']['central_directory'])) {
foreach ($this->getid3->info['zip']['central_directory'] as $central_directory_entry) {
if ($central_directory_entry['entry_offset'] == $LocalFileHeader['offset']) {
if ($central_directory_entry['compressed_size'] > 0) {
// overwrite local zero value (but not ['raw']'compressed_size']) so that seeking for data_descriptor (and next file entry) works correctly
$LocalFileHeader['compressed_size'] = $central_directory_entry['compressed_size'];
}
break;
}
}
}
}
$LocalFileHeader['data_offset'] = $this->ftell();
$this->fseek($LocalFileHeader['compressed_size'], SEEK_CUR); // this should (but may not) match value in $LocalFileHeader['raw']['compressed_size'] -- $LocalFileHeader['compressed_size'] could have been overwritten above with value from Central Directory
if ($LocalFileHeader['flags']['data_descriptor_used']) {
$DataDescriptor = $this->fread(16);
$LocalFileHeader['data_descriptor']['signature'] = getid3_lib::LittleEndian2Int(substr($DataDescriptor, 0, 4));
if ($LocalFileHeader['data_descriptor']['signature'] != 0x08074B50) { // "PK\x07\x08"
$this->getid3->warning[] = 'invalid Local File Header Data Descriptor Signature at offset '.($this->ftell() - 16).' - expecting 08 07 4B 50, found '.getid3_lib::PrintHexBytes($LocalFileHeader['data_descriptor']['signature']);
$this->fseek($LocalFileHeader['offset']); // seek back to where filepointer originally was so it can be handled properly
return false;
}
$LocalFileHeader['data_descriptor']['crc_32'] = getid3_lib::LittleEndian2Int(substr($DataDescriptor, 4, 4));
$LocalFileHeader['data_descriptor']['compressed_size'] = getid3_lib::LittleEndian2Int(substr($DataDescriptor, 8, 4));
$LocalFileHeader['data_descriptor']['uncompressed_size'] = getid3_lib::LittleEndian2Int(substr($DataDescriptor, 12, 4));
if (!$LocalFileHeader['raw']['compressed_size'] && $LocalFileHeader['data_descriptor']['compressed_size']) {
foreach ($this->getid3->info['zip']['central_directory'] as $central_directory_entry) {
if ($central_directory_entry['entry_offset'] == $LocalFileHeader['offset']) {
if ($LocalFileHeader['data_descriptor']['compressed_size'] == $central_directory_entry['compressed_size']) {
// $LocalFileHeader['compressed_size'] already set from Central Directory
} else {
$this->getid3->info['warning'][] = 'conflicting compressed_size from data_descriptor ('.$LocalFileHeader['data_descriptor']['compressed_size'].') vs Central Directory ('.$central_directory_entry['compressed_size'].') for file at offset '.$LocalFileHeader['offset'];
}
if ($LocalFileHeader['data_descriptor']['uncompressed_size'] == $central_directory_entry['uncompressed_size']) {
$LocalFileHeader['uncompressed_size'] = $LocalFileHeader['data_descriptor']['uncompressed_size'];
} else {
$this->getid3->info['warning'][] = 'conflicting uncompressed_size from data_descriptor ('.$LocalFileHeader['data_descriptor']['uncompressed_size'].') vs Central Directory ('.$central_directory_entry['uncompressed_size'].') for file at offset '.$LocalFileHeader['offset'];
}
break;
}
}
}
}
return $LocalFileHeader;
}
public function ZIPparseCentralDirectory() {
$CentralDirectory['offset'] = $this->ftell();
$ZIPcentralDirectory = $this->fread(46);
$CentralDirectory['raw']['signature'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 0, 4));
if ($CentralDirectory['raw']['signature'] != 0x02014B50) {
// invalid Central Directory Signature
$this->fseek($CentralDirectory['offset']); // seek back to where filepointer originally was so it can be handled properly
return false;
}
$CentralDirectory['raw']['create_version'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 4, 2));
$CentralDirectory['raw']['extract_version'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 6, 2));
$CentralDirectory['raw']['general_flags'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 8, 2));
$CentralDirectory['raw']['compression_method'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 10, 2));
$CentralDirectory['raw']['last_mod_file_time'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 12, 2));
$CentralDirectory['raw']['last_mod_file_date'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 14, 2));
$CentralDirectory['raw']['crc_32'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 16, 4));
$CentralDirectory['raw']['compressed_size'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 20, 4));
$CentralDirectory['raw']['uncompressed_size'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 24, 4));
$CentralDirectory['raw']['filename_length'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 28, 2));
$CentralDirectory['raw']['extra_field_length'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 30, 2));
$CentralDirectory['raw']['file_comment_length'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 32, 2));
$CentralDirectory['raw']['disk_number_start'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 34, 2));
$CentralDirectory['raw']['internal_file_attrib'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 36, 2));
$CentralDirectory['raw']['external_file_attrib'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 38, 4));
$CentralDirectory['raw']['local_header_offset'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 42, 4));
$CentralDirectory['entry_offset'] = $CentralDirectory['raw']['local_header_offset'];
$CentralDirectory['create_version'] = sprintf('%1.1f', $CentralDirectory['raw']['create_version'] / 10);
$CentralDirectory['extract_version'] = sprintf('%1.1f', $CentralDirectory['raw']['extract_version'] / 10);
$CentralDirectory['host_os'] = $this->ZIPversionOSLookup(($CentralDirectory['raw']['extract_version'] & 0xFF00) >> 8);
$CentralDirectory['compression_method'] = $this->ZIPcompressionMethodLookup($CentralDirectory['raw']['compression_method']);
$CentralDirectory['compressed_size'] = $CentralDirectory['raw']['compressed_size'];
$CentralDirectory['uncompressed_size'] = $CentralDirectory['raw']['uncompressed_size'];
$CentralDirectory['flags'] = $this->ZIPparseGeneralPurposeFlags($CentralDirectory['raw']['general_flags'], $CentralDirectory['raw']['compression_method']);
$CentralDirectory['last_modified_timestamp'] = $this->DOStime2UNIXtime($CentralDirectory['raw']['last_mod_file_date'], $CentralDirectory['raw']['last_mod_file_time']);
$FilenameExtrafieldCommentLength = $CentralDirectory['raw']['filename_length'] + $CentralDirectory['raw']['extra_field_length'] + $CentralDirectory['raw']['file_comment_length'];
if ($FilenameExtrafieldCommentLength > 0) {
$FilenameExtrafieldComment = $this->fread($FilenameExtrafieldCommentLength);
if ($CentralDirectory['raw']['filename_length'] > 0) {
$CentralDirectory['filename'] = substr($FilenameExtrafieldComment, 0, $CentralDirectory['raw']['filename_length']);
}
if ($CentralDirectory['raw']['extra_field_length'] > 0) {
$CentralDirectory['raw']['extra_field_data'] = substr($FilenameExtrafieldComment, $CentralDirectory['raw']['filename_length'], $CentralDirectory['raw']['extra_field_length']);
}
if ($CentralDirectory['raw']['file_comment_length'] > 0) {
$CentralDirectory['file_comment'] = substr($FilenameExtrafieldComment, $CentralDirectory['raw']['filename_length'] + $CentralDirectory['raw']['extra_field_length'], $CentralDirectory['raw']['file_comment_length']);
}
}
return $CentralDirectory;
}
public function ZIPparseEndOfCentralDirectory() {
$EndOfCentralDirectory['offset'] = $this->ftell();
$ZIPendOfCentralDirectory = $this->fread(22);
$EndOfCentralDirectory['signature'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 0, 4));
if ($EndOfCentralDirectory['signature'] != 0x06054B50) {
// invalid End Of Central Directory Signature
$this->fseek($EndOfCentralDirectory['offset']); // seek back to where filepointer originally was so it can be handled properly
return false;
}
$EndOfCentralDirectory['disk_number_current'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 4, 2));
$EndOfCentralDirectory['disk_number_start_directory'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 6, 2));
$EndOfCentralDirectory['directory_entries_this_disk'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 8, 2));
$EndOfCentralDirectory['directory_entries_total'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 10, 2));
$EndOfCentralDirectory['directory_size'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 12, 4));
$EndOfCentralDirectory['directory_offset'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 16, 4));
$EndOfCentralDirectory['comment_length'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 20, 2));
if ($EndOfCentralDirectory['comment_length'] > 0) {
$EndOfCentralDirectory['comment'] = $this->fread($EndOfCentralDirectory['comment_length']);
}
return $EndOfCentralDirectory;
}
public static function ZIPparseGeneralPurposeFlags($flagbytes, $compressionmethod) {
// https://users.cs.jmu.edu/buchhofp/forensics/formats/pkzip-printable.html
$ParsedFlags['encrypted'] = (bool) ($flagbytes & 0x0001);
// 0x0002 -- see below
// 0x0004 -- see below
$ParsedFlags['data_descriptor_used'] = (bool) ($flagbytes & 0x0008);
$ParsedFlags['enhanced_deflation'] = (bool) ($flagbytes & 0x0010);
$ParsedFlags['compressed_patched_data'] = (bool) ($flagbytes & 0x0020);
$ParsedFlags['strong_encryption'] = (bool) ($flagbytes & 0x0040);
// 0x0080 - unused
// 0x0100 - unused
// 0x0200 - unused
// 0x0400 - unused
$ParsedFlags['language_encoding'] = (bool) ($flagbytes & 0x0800);
// 0x1000 - reserved
$ParsedFlags['mask_header_values'] = (bool) ($flagbytes & 0x2000);
// 0x4000 - reserved
// 0x8000 - reserved
switch ($compressionmethod) {
case 6:
$ParsedFlags['dictionary_size'] = (($flagbytes & 0x0002) ? 8192 : 4096);
$ParsedFlags['shannon_fano_trees'] = (($flagbytes & 0x0004) ? 3 : 2);
break;
case 8:
case 9:
switch (($flagbytes & 0x0006) >> 1) {
case 0:
$ParsedFlags['compression_speed'] = 'normal';
break;
case 1:
$ParsedFlags['compression_speed'] = 'maximum';
break;
case 2:
$ParsedFlags['compression_speed'] = 'fast';
break;
case 3:
$ParsedFlags['compression_speed'] = 'superfast';
break;
}
break;
}
return $ParsedFlags;
}
public static function ZIPversionOSLookup($index) {
static $ZIPversionOSLookup = array(
0 => 'MS-DOS and OS/2 (FAT / VFAT / FAT32 file systems)',
1 => 'Amiga',
2 => 'OpenVMS',
3 => 'Unix',
4 => 'VM/CMS',
5 => 'Atari ST',
6 => 'OS/2 H.P.F.S.',
7 => 'Macintosh',
8 => 'Z-System',
9 => 'CP/M',
10 => 'Windows NTFS',
11 => 'MVS',
12 => 'VSE',
13 => 'Acorn Risc',
14 => 'VFAT',
15 => 'Alternate MVS',
16 => 'BeOS',
17 => 'Tandem',
18 => 'OS/400',
19 => 'OS/X (Darwin)',
);
return (isset($ZIPversionOSLookup[$index]) ? $ZIPversionOSLookup[$index] : '[unknown]');
}
public static function ZIPcompressionMethodLookup($index) {
// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/ZIP.html
static $ZIPcompressionMethodLookup = array(
0 => 'store',
1 => 'shrink',
2 => 'reduce-1',
3 => 'reduce-2',
4 => 'reduce-3',
5 => 'reduce-4',
6 => 'implode',
7 => 'tokenize',
8 => 'deflate',
9 => 'deflate64',
10 => 'Imploded (old IBM TERSE)',
11 => 'RESERVED[11]',
12 => 'BZIP2',
13 => 'RESERVED[13]',
14 => 'LZMA (EFS)',
15 => 'RESERVED[15]',
16 => 'RESERVED[16]',
17 => 'RESERVED[17]',
18 => 'IBM TERSE (new)',
19 => 'IBM LZ77 z Architecture (PFS)',
96 => 'JPEG recompressed',
97 => 'WavPack compressed',
98 => 'PPMd version I, Rev 1',
);
return (isset($ZIPcompressionMethodLookup[$index]) ? $ZIPcompressionMethodLookup[$index] : '[unknown]');
}
public static function DOStime2UNIXtime($DOSdate, $DOStime) {
// wFatDate
// Specifies the MS-DOS date. The date is a packed 16-bit value with the following format:
// Bits Contents
// 0-4 Day of the month (1-31)
// 5-8 Month (1 = January, 2 = February, and so on)
// 9-15 Year offset from 1980 (add 1980 to get actual year)
$UNIXday = ($DOSdate & 0x001F);
$UNIXmonth = (($DOSdate & 0x01E0) >> 5);
$UNIXyear = (($DOSdate & 0xFE00) >> 9) + 1980;
// wFatTime
// Specifies the MS-DOS time. The time is a packed 16-bit value with the following format:
// Bits Contents
// 0-4 Second divided by 2
// 5-10 Minute (0-59)
// 11-15 Hour (0-23 on a 24-hour clock)
$UNIXsecond = ($DOStime & 0x001F) * 2;
$UNIXminute = (($DOStime & 0x07E0) >> 5);
$UNIXhour = (($DOStime & 0xF800) >> 11);
return gmmktime($UNIXhour, $UNIXminute, $UNIXsecond, $UNIXmonth, $UNIXday, $UNIXyear);
}
}

View File

@ -1,745 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
// also https://github.com/JamesHeinrich/getID3 //
// //
// FLV module by Seth Kaufman <sethØwhirl-i-gig*com> //
// //
// * version 0.1 (26 June 2005) //
// //
// //
// * version 0.1.1 (15 July 2005) //
// minor modifications by James Heinrich <info@getid3.org> //
// //
// * version 0.2 (22 February 2006) //
// Support for On2 VP6 codec and meta information //
// by Steve Webster <steve.websterØfeaturecreep*com> //
// //
// * version 0.3 (15 June 2006) //
// Modified to not read entire file into memory //
// by James Heinrich <info@getid3.org> //
// //
// * version 0.4 (07 December 2007) //
// Bugfixes for incorrectly parsed FLV dimensions //
// and incorrect parsing of onMetaTag //
// by Evgeny Moysevich <moysevichØgmail*com> //
// //
// * version 0.5 (21 May 2009) //
// Fixed parsing of audio tags and added additional codec //
// details. The duration is now read from onMetaTag (if //
// exists), rather than parsing whole file //
// by Nigel Barnes <ngbarnesØhotmail*com> //
// //
// * version 0.6 (24 May 2009) //
// Better parsing of files with h264 video //
// by Evgeny Moysevich <moysevichØgmail*com> //
// //
// * version 0.6.1 (30 May 2011) //
// prevent infinite loops in expGolombUe() //
// //
// * version 0.7.0 (16 Jul 2013) //
// handle GETID3_FLV_VIDEO_VP6FLV_ALPHA //
// improved AVCSequenceParameterSetReader::readData() //
// by Xander Schouwerwou <schouwerwouØgmail*com> //
// //
/////////////////////////////////////////////////////////////////
// //
// module.audio-video.flv.php //
// module for analyzing Shockwave Flash Video files //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
define('GETID3_FLV_TAG_AUDIO', 8);
define('GETID3_FLV_TAG_VIDEO', 9);
define('GETID3_FLV_TAG_META', 18);
define('GETID3_FLV_VIDEO_H263', 2);
define('GETID3_FLV_VIDEO_SCREEN', 3);
define('GETID3_FLV_VIDEO_VP6FLV', 4);
define('GETID3_FLV_VIDEO_VP6FLV_ALPHA', 5);
define('GETID3_FLV_VIDEO_SCREENV2', 6);
define('GETID3_FLV_VIDEO_H264', 7);
define('H264_AVC_SEQUENCE_HEADER', 0);
define('H264_PROFILE_BASELINE', 66);
define('H264_PROFILE_MAIN', 77);
define('H264_PROFILE_EXTENDED', 88);
define('H264_PROFILE_HIGH', 100);
define('H264_PROFILE_HIGH10', 110);
define('H264_PROFILE_HIGH422', 122);
define('H264_PROFILE_HIGH444', 144);
define('H264_PROFILE_HIGH444_PREDICTIVE', 244);
class getid3_flv extends getid3_handler {
const magic = 'FLV';
public $max_frames = 100000; // break out of the loop if too many frames have been scanned; only scan this many if meta frame does not contain useful duration
public function Analyze() {
$info = &$this->getid3->info;
$this->fseek($info['avdataoffset']);
$FLVdataLength = $info['avdataend'] - $info['avdataoffset'];
$FLVheader = $this->fread(5);
$info['fileformat'] = 'flv';
$info['flv']['header']['signature'] = substr($FLVheader, 0, 3);
$info['flv']['header']['version'] = getid3_lib::BigEndian2Int(substr($FLVheader, 3, 1));
$TypeFlags = getid3_lib::BigEndian2Int(substr($FLVheader, 4, 1));
if ($info['flv']['header']['signature'] != self::magic) {
$info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes(self::magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['flv']['header']['signature']).'"';
unset($info['flv'], $info['fileformat']);
return false;
}
$info['flv']['header']['hasAudio'] = (bool) ($TypeFlags & 0x04);
$info['flv']['header']['hasVideo'] = (bool) ($TypeFlags & 0x01);
$FrameSizeDataLength = getid3_lib::BigEndian2Int($this->fread(4));
$FLVheaderFrameLength = 9;
if ($FrameSizeDataLength > $FLVheaderFrameLength) {
$this->fseek($FrameSizeDataLength - $FLVheaderFrameLength, SEEK_CUR);
}
$Duration = 0;
$found_video = false;
$found_audio = false;
$found_meta = false;
$found_valid_meta_playtime = false;
$tagParseCount = 0;
$info['flv']['framecount'] = array('total'=>0, 'audio'=>0, 'video'=>0);
$flv_framecount = &$info['flv']['framecount'];
while ((($this->ftell() + 16) < $info['avdataend']) && (($tagParseCount++ <= $this->max_frames) || !$found_valid_meta_playtime)) {
$ThisTagHeader = $this->fread(16);
$PreviousTagLength = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 0, 4));
$TagType = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 4, 1));
$DataLength = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 5, 3));
$Timestamp = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 8, 3));
$LastHeaderByte = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 15, 1));
$NextOffset = $this->ftell() - 1 + $DataLength;
if ($Timestamp > $Duration) {
$Duration = $Timestamp;
}
$flv_framecount['total']++;
switch ($TagType) {
case GETID3_FLV_TAG_AUDIO:
$flv_framecount['audio']++;
if (!$found_audio) {
$found_audio = true;
$info['flv']['audio']['audioFormat'] = ($LastHeaderByte >> 4) & 0x0F;
$info['flv']['audio']['audioRate'] = ($LastHeaderByte >> 2) & 0x03;
$info['flv']['audio']['audioSampleSize'] = ($LastHeaderByte >> 1) & 0x01;
$info['flv']['audio']['audioType'] = $LastHeaderByte & 0x01;
}
break;
case GETID3_FLV_TAG_VIDEO:
$flv_framecount['video']++;
if (!$found_video) {
$found_video = true;
$info['flv']['video']['videoCodec'] = $LastHeaderByte & 0x07;
$FLVvideoHeader = $this->fread(11);
if ($info['flv']['video']['videoCodec'] == GETID3_FLV_VIDEO_H264) {
// this code block contributed by: moysevichØgmail*com
$AVCPacketType = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 0, 1));
if ($AVCPacketType == H264_AVC_SEQUENCE_HEADER) {
// read AVCDecoderConfigurationRecord
$configurationVersion = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 4, 1));
$AVCProfileIndication = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 5, 1));
$profile_compatibility = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 6, 1));
$lengthSizeMinusOne = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 7, 1));
$numOfSequenceParameterSets = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 8, 1));
if (($numOfSequenceParameterSets & 0x1F) != 0) {
// there is at least one SequenceParameterSet
// read size of the first SequenceParameterSet
//$spsSize = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 9, 2));
$spsSize = getid3_lib::LittleEndian2Int(substr($FLVvideoHeader, 9, 2));
// read the first SequenceParameterSet
$sps = $this->fread($spsSize);
if (strlen($sps) == $spsSize) { // make sure that whole SequenceParameterSet was red
$spsReader = new AVCSequenceParameterSetReader($sps);
$spsReader->readData();
$info['video']['resolution_x'] = $spsReader->getWidth();
$info['video']['resolution_y'] = $spsReader->getHeight();
}
}
}
// end: moysevichØgmail*com
} elseif ($info['flv']['video']['videoCodec'] == GETID3_FLV_VIDEO_H263) {
$PictureSizeType = (getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 3, 2))) >> 7;
$PictureSizeType = $PictureSizeType & 0x0007;
$info['flv']['header']['videoSizeType'] = $PictureSizeType;
switch ($PictureSizeType) {
case 0:
//$PictureSizeEnc = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 5, 2));
//$PictureSizeEnc <<= 1;
//$info['video']['resolution_x'] = ($PictureSizeEnc & 0xFF00) >> 8;
//$PictureSizeEnc = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 6, 2));
//$PictureSizeEnc <<= 1;
//$info['video']['resolution_y'] = ($PictureSizeEnc & 0xFF00) >> 8;
$PictureSizeEnc['x'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 4, 2)) >> 7;
$PictureSizeEnc['y'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 5, 2)) >> 7;
$info['video']['resolution_x'] = $PictureSizeEnc['x'] & 0xFF;
$info['video']['resolution_y'] = $PictureSizeEnc['y'] & 0xFF;
break;
case 1:
$PictureSizeEnc['x'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 4, 3)) >> 7;
$PictureSizeEnc['y'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 6, 3)) >> 7;
$info['video']['resolution_x'] = $PictureSizeEnc['x'] & 0xFFFF;
$info['video']['resolution_y'] = $PictureSizeEnc['y'] & 0xFFFF;
break;
case 2:
$info['video']['resolution_x'] = 352;
$info['video']['resolution_y'] = 288;
break;
case 3:
$info['video']['resolution_x'] = 176;
$info['video']['resolution_y'] = 144;
break;
case 4:
$info['video']['resolution_x'] = 128;
$info['video']['resolution_y'] = 96;
break;
case 5:
$info['video']['resolution_x'] = 320;
$info['video']['resolution_y'] = 240;
break;
case 6:
$info['video']['resolution_x'] = 160;
$info['video']['resolution_y'] = 120;
break;
default:
$info['video']['resolution_x'] = 0;
$info['video']['resolution_y'] = 0;
break;
}
} elseif ($info['flv']['video']['videoCodec'] == GETID3_FLV_VIDEO_VP6FLV_ALPHA) {
/* contributed by schouwerwouØgmail*com */
if (!isset($info['video']['resolution_x'])) { // only when meta data isn't set
$PictureSizeEnc['x'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 6, 2));
$PictureSizeEnc['y'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 7, 2));
$info['video']['resolution_x'] = ($PictureSizeEnc['x'] & 0xFF) << 3;
$info['video']['resolution_y'] = ($PictureSizeEnc['y'] & 0xFF) << 3;
}
/* end schouwerwouØgmail*com */
}
if (!empty($info['video']['resolution_x']) && !empty($info['video']['resolution_y'])) {
$info['video']['pixel_aspect_ratio'] = $info['video']['resolution_x'] / $info['video']['resolution_y'];
}
}
break;
// Meta tag
case GETID3_FLV_TAG_META:
if (!$found_meta) {
$found_meta = true;
$this->fseek(-1, SEEK_CUR);
$datachunk = $this->fread($DataLength);
$AMFstream = new AMFStream($datachunk);
$reader = new AMFReader($AMFstream);
$eventName = $reader->readData();
$info['flv']['meta'][$eventName] = $reader->readData();
unset($reader);
$copykeys = array('framerate'=>'frame_rate', 'width'=>'resolution_x', 'height'=>'resolution_y', 'audiodatarate'=>'bitrate', 'videodatarate'=>'bitrate');
foreach ($copykeys as $sourcekey => $destkey) {
if (isset($info['flv']['meta']['onMetaData'][$sourcekey])) {
switch ($sourcekey) {
case 'width':
case 'height':
$info['video'][$destkey] = intval(round($info['flv']['meta']['onMetaData'][$sourcekey]));
break;
case 'audiodatarate':
$info['audio'][$destkey] = getid3_lib::CastAsInt(round($info['flv']['meta']['onMetaData'][$sourcekey] * 1000));
break;
case 'videodatarate':
case 'frame_rate':
default:
$info['video'][$destkey] = $info['flv']['meta']['onMetaData'][$sourcekey];
break;
}
}
}
if (!empty($info['flv']['meta']['onMetaData']['duration'])) {
$found_valid_meta_playtime = true;
}
}
break;
default:
// noop
break;
}
$this->fseek($NextOffset);
}
$info['playtime_seconds'] = $Duration / 1000;
if ($info['playtime_seconds'] > 0) {
$info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
}
if ($info['flv']['header']['hasAudio']) {
$info['audio']['codec'] = self::audioFormatLookup($info['flv']['audio']['audioFormat']);
$info['audio']['sample_rate'] = self::audioRateLookup($info['flv']['audio']['audioRate']);
$info['audio']['bits_per_sample'] = self::audioBitDepthLookup($info['flv']['audio']['audioSampleSize']);
$info['audio']['channels'] = $info['flv']['audio']['audioType'] + 1; // 0=mono,1=stereo
$info['audio']['lossless'] = ($info['flv']['audio']['audioFormat'] ? false : true); // 0=uncompressed
$info['audio']['dataformat'] = 'flv';
}
if (!empty($info['flv']['header']['hasVideo'])) {
$info['video']['codec'] = self::videoCodecLookup($info['flv']['video']['videoCodec']);
$info['video']['dataformat'] = 'flv';
$info['video']['lossless'] = false;
}
// Set information from meta
if (!empty($info['flv']['meta']['onMetaData']['duration'])) {
$info['playtime_seconds'] = $info['flv']['meta']['onMetaData']['duration'];
$info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
}
if (isset($info['flv']['meta']['onMetaData']['audiocodecid'])) {
$info['audio']['codec'] = self::audioFormatLookup($info['flv']['meta']['onMetaData']['audiocodecid']);
}
if (isset($info['flv']['meta']['onMetaData']['videocodecid'])) {
$info['video']['codec'] = self::videoCodecLookup($info['flv']['meta']['onMetaData']['videocodecid']);
}
return true;
}
public static function audioFormatLookup($id) {
static $lookup = array(
0 => 'Linear PCM, platform endian',
1 => 'ADPCM',
2 => 'mp3',
3 => 'Linear PCM, little endian',
4 => 'Nellymoser 16kHz mono',
5 => 'Nellymoser 8kHz mono',
6 => 'Nellymoser',
7 => 'G.711A-law logarithmic PCM',
8 => 'G.711 mu-law logarithmic PCM',
9 => 'reserved',
10 => 'AAC',
11 => 'Speex',
12 => false, // unknown?
13 => false, // unknown?
14 => 'mp3 8kHz',
15 => 'Device-specific sound',
);
return (isset($lookup[$id]) ? $lookup[$id] : false);
}
public static function audioRateLookup($id) {
static $lookup = array(
0 => 5500,
1 => 11025,
2 => 22050,
3 => 44100,
);
return (isset($lookup[$id]) ? $lookup[$id] : false);
}
public static function audioBitDepthLookup($id) {
static $lookup = array(
0 => 8,
1 => 16,
);
return (isset($lookup[$id]) ? $lookup[$id] : false);
}
public static function videoCodecLookup($id) {
static $lookup = array(
GETID3_FLV_VIDEO_H263 => 'Sorenson H.263',
GETID3_FLV_VIDEO_SCREEN => 'Screen video',
GETID3_FLV_VIDEO_VP6FLV => 'On2 VP6',
GETID3_FLV_VIDEO_VP6FLV_ALPHA => 'On2 VP6 with alpha channel',
GETID3_FLV_VIDEO_SCREENV2 => 'Screen video v2',
GETID3_FLV_VIDEO_H264 => 'Sorenson H.264',
);
return (isset($lookup[$id]) ? $lookup[$id] : false);
}
}
class AMFStream {
public $bytes;
public $pos;
public function __construct(&$bytes) {
$this->bytes =& $bytes;
$this->pos = 0;
}
public function readByte() {
return getid3_lib::BigEndian2Int(substr($this->bytes, $this->pos++, 1));
}
public function readInt() {
return ($this->readByte() << 8) + $this->readByte();
}
public function readLong() {
return ($this->readByte() << 24) + ($this->readByte() << 16) + ($this->readByte() << 8) + $this->readByte();
}
public function readDouble() {
return getid3_lib::BigEndian2Float($this->read(8));
}
public function readUTF() {
$length = $this->readInt();
return $this->read($length);
}
public function readLongUTF() {
$length = $this->readLong();
return $this->read($length);
}
public function read($length) {
$val = substr($this->bytes, $this->pos, $length);
$this->pos += $length;
return $val;
}
public function peekByte() {
$pos = $this->pos;
$val = $this->readByte();
$this->pos = $pos;
return $val;
}
public function peekInt() {
$pos = $this->pos;
$val = $this->readInt();
$this->pos = $pos;
return $val;
}
public function peekLong() {
$pos = $this->pos;
$val = $this->readLong();
$this->pos = $pos;
return $val;
}
public function peekDouble() {
$pos = $this->pos;
$val = $this->readDouble();
$this->pos = $pos;
return $val;
}
public function peekUTF() {
$pos = $this->pos;
$val = $this->readUTF();
$this->pos = $pos;
return $val;
}
public function peekLongUTF() {
$pos = $this->pos;
$val = $this->readLongUTF();
$this->pos = $pos;
return $val;
}
}
class AMFReader {
public $stream;
public function __construct(&$stream) {
$this->stream =& $stream;
}
public function readData() {
$value = null;
$type = $this->stream->readByte();
switch ($type) {
// Double
case 0:
$value = $this->readDouble();
break;
// Boolean
case 1:
$value = $this->readBoolean();
break;
// String
case 2:
$value = $this->readString();
break;
// Object
case 3:
$value = $this->readObject();
break;
// null
case 6:
return null;
break;
// Mixed array
case 8:
$value = $this->readMixedArray();
break;
// Array
case 10:
$value = $this->readArray();
break;
// Date
case 11:
$value = $this->readDate();
break;
// Long string
case 13:
$value = $this->readLongString();
break;
// XML (handled as string)
case 15:
$value = $this->readXML();
break;
// Typed object (handled as object)
case 16:
$value = $this->readTypedObject();
break;
// Long string
default:
$value = '(unknown or unsupported data type)';
break;
}
return $value;
}
public function readDouble() {
return $this->stream->readDouble();
}
public function readBoolean() {
return $this->stream->readByte() == 1;
}
public function readString() {
return $this->stream->readUTF();
}
public function readObject() {
// Get highest numerical index - ignored
// $highestIndex = $this->stream->readLong();
$data = array();
while ($key = $this->stream->readUTF()) {
$data[$key] = $this->readData();
}
// Mixed array record ends with empty string (0x00 0x00) and 0x09
if (($key == '') && ($this->stream->peekByte() == 0x09)) {
// Consume byte
$this->stream->readByte();
}
return $data;
}
public function readMixedArray() {
// Get highest numerical index - ignored
$highestIndex = $this->stream->readLong();
$data = array();
while ($key = $this->stream->readUTF()) {
if (is_numeric($key)) {
$key = (float) $key;
}
$data[$key] = $this->readData();
}
// Mixed array record ends with empty string (0x00 0x00) and 0x09
if (($key == '') && ($this->stream->peekByte() == 0x09)) {
// Consume byte
$this->stream->readByte();
}
return $data;
}
public function readArray() {
$length = $this->stream->readLong();
$data = array();
for ($i = 0; $i < $length; $i++) {
$data[] = $this->readData();
}
return $data;
}
public function readDate() {
$timestamp = $this->stream->readDouble();
$timezone = $this->stream->readInt();
return $timestamp;
}
public function readLongString() {
return $this->stream->readLongUTF();
}
public function readXML() {
return $this->stream->readLongUTF();
}
public function readTypedObject() {
$className = $this->stream->readUTF();
return $this->readObject();
}
}
class AVCSequenceParameterSetReader {
public $sps;
public $start = 0;
public $currentBytes = 0;
public $currentBits = 0;
public $width;
public $height;
public function __construct($sps) {
$this->sps = $sps;
}
public function readData() {
$this->skipBits(8);
$this->skipBits(8);
$profile = $this->getBits(8); // read profile
if ($profile > 0) {
$this->skipBits(8);
$level_idc = $this->getBits(8); // level_idc
$this->expGolombUe(); // seq_parameter_set_id // sps
$this->expGolombUe(); // log2_max_frame_num_minus4
$picOrderType = $this->expGolombUe(); // pic_order_cnt_type
if ($picOrderType == 0) {
$this->expGolombUe(); // log2_max_pic_order_cnt_lsb_minus4
} elseif ($picOrderType == 1) {
$this->skipBits(1); // delta_pic_order_always_zero_flag
$this->expGolombSe(); // offset_for_non_ref_pic
$this->expGolombSe(); // offset_for_top_to_bottom_field
$num_ref_frames_in_pic_order_cnt_cycle = $this->expGolombUe(); // num_ref_frames_in_pic_order_cnt_cycle
for ($i = 0; $i < $num_ref_frames_in_pic_order_cnt_cycle; $i++) {
$this->expGolombSe(); // offset_for_ref_frame[ i ]
}
}
$this->expGolombUe(); // num_ref_frames
$this->skipBits(1); // gaps_in_frame_num_value_allowed_flag
$pic_width_in_mbs_minus1 = $this->expGolombUe(); // pic_width_in_mbs_minus1
$pic_height_in_map_units_minus1 = $this->expGolombUe(); // pic_height_in_map_units_minus1
$frame_mbs_only_flag = $this->getBits(1); // frame_mbs_only_flag
if ($frame_mbs_only_flag == 0) {
$this->skipBits(1); // mb_adaptive_frame_field_flag
}
$this->skipBits(1); // direct_8x8_inference_flag
$frame_cropping_flag = $this->getBits(1); // frame_cropping_flag
$frame_crop_left_offset = 0;
$frame_crop_right_offset = 0;
$frame_crop_top_offset = 0;
$frame_crop_bottom_offset = 0;
if ($frame_cropping_flag) {
$frame_crop_left_offset = $this->expGolombUe(); // frame_crop_left_offset
$frame_crop_right_offset = $this->expGolombUe(); // frame_crop_right_offset
$frame_crop_top_offset = $this->expGolombUe(); // frame_crop_top_offset
$frame_crop_bottom_offset = $this->expGolombUe(); // frame_crop_bottom_offset
}
$this->skipBits(1); // vui_parameters_present_flag
// etc
$this->width = (($pic_width_in_mbs_minus1 + 1) * 16) - ($frame_crop_left_offset * 2) - ($frame_crop_right_offset * 2);
$this->height = ((2 - $frame_mbs_only_flag) * ($pic_height_in_map_units_minus1 + 1) * 16) - ($frame_crop_top_offset * 2) - ($frame_crop_bottom_offset * 2);
}
}
public function skipBits($bits) {
$newBits = $this->currentBits + $bits;
$this->currentBytes += (int)floor($newBits / 8);
$this->currentBits = $newBits % 8;
}
public function getBit() {
$result = (getid3_lib::BigEndian2Int(substr($this->sps, $this->currentBytes, 1)) >> (7 - $this->currentBits)) & 0x01;
$this->skipBits(1);
return $result;
}
public function getBits($bits) {
$result = 0;
for ($i = 0; $i < $bits; $i++) {
$result = ($result << 1) + $this->getBit();
}
return $result;
}
public function expGolombUe() {
$significantBits = 0;
$bit = $this->getBit();
while ($bit == 0) {
$significantBits++;
$bit = $this->getBit();
if ($significantBits > 31) {
// something is broken, this is an emergency escape to prevent infinite loops
return 0;
}
}
return (1 << $significantBits) + $this->getBits($significantBits) - 1;
}
public function expGolombSe() {
$result = $this->expGolombUe();
if (($result & 0x01) == 0) {
return -($result >> 1);
} else {
return ($result + 1) >> 1;
}
}
public function getWidth() {
return $this->width;
}
public function getHeight() {
return $this->height;
}
}

View File

@ -1,606 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
// also https://github.com/JamesHeinrich/getID3 //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.audio-video.mpeg.php //
// module for analyzing MPEG files //
// dependencies: module.audio.mp3.php //
// ///
/////////////////////////////////////////////////////////////////
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.mp3.php', __FILE__, true);
class getid3_mpeg extends getid3_handler {
const START_CODE_BASE = "\x00\x00\x01";
const VIDEO_PICTURE_START = "\x00\x00\x01\x00";
const VIDEO_USER_DATA_START = "\x00\x00\x01\xB2";
const VIDEO_SEQUENCE_HEADER = "\x00\x00\x01\xB3";
const VIDEO_SEQUENCE_ERROR = "\x00\x00\x01\xB4";
const VIDEO_EXTENSION_START = "\x00\x00\x01\xB5";
const VIDEO_SEQUENCE_END = "\x00\x00\x01\xB7";
const VIDEO_GROUP_START = "\x00\x00\x01\xB8";
const AUDIO_START = "\x00\x00\x01\xC0";
public function Analyze() {
$info = &$this->getid3->info;
$info['fileformat'] = 'mpeg';
$this->fseek($info['avdataoffset']);
$MPEGstreamData = $this->fread($this->getid3->option_fread_buffer_size);
$MPEGstreamBaseOffset = 0; // how far are we from the beginning of the file data ($info['avdataoffset'])
$MPEGstreamDataOffset = 0; // how far are we from the beginning of the buffer data (~32kB)
$StartCodeValue = false;
$prevStartCodeValue = false;
$GOPcounter = -1;
$FramesByGOP = array();
$ParsedAVchannels = array();
do {
//echo $MPEGstreamDataOffset.' vs '.(strlen($MPEGstreamData) - 1024).'<Br>';
if ($MPEGstreamDataOffset > (strlen($MPEGstreamData) - 16384)) {
// buffer running low, get more data
//echo 'reading more data<br>';
$MPEGstreamData .= $this->fread($this->getid3->option_fread_buffer_size);
if (strlen($MPEGstreamData) > $this->getid3->option_fread_buffer_size) {
$MPEGstreamData = substr($MPEGstreamData, $MPEGstreamDataOffset);
$MPEGstreamBaseOffset += $MPEGstreamDataOffset;
$MPEGstreamDataOffset = 0;
}
}
if (($StartCodeOffset = strpos($MPEGstreamData, self::START_CODE_BASE, $MPEGstreamDataOffset)) === false) {
//echo 'no more start codes found.<br>';
break;
} else {
$MPEGstreamDataOffset = $StartCodeOffset;
$prevStartCodeValue = $StartCodeValue;
$StartCodeValue = ord(substr($MPEGstreamData, $StartCodeOffset + 3, 1));
//echo 'Found "'.strtoupper(dechex($StartCodeValue)).'" at offset '.($MPEGstreamBaseOffset + $StartCodeOffset).' ($MPEGstreamDataOffset = '.$MPEGstreamDataOffset.')<br>';
}
$MPEGstreamDataOffset += 4;
switch ($StartCodeValue) {
case 0x00: // picture_start_code
if (!empty($info['mpeg']['video']['bitrate_mode']) && ($info['mpeg']['video']['bitrate_mode'] == 'vbr')) {
$bitstream = getid3_lib::BigEndian2Bin(substr($MPEGstreamData, $StartCodeOffset + 4, 4));
$bitstreamoffset = 0;
$PictureHeader = array();
$PictureHeader['temporal_reference'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 10); // 10-bit unsigned integer associated with each input picture. It is incremented by one, modulo 1024, for each input frame. When a frame is coded as two fields the temporal reference in the picture header of both fields is the same. Following a group start header the temporal reference of the earliest picture (in display order) shall be reset to zero.
$PictureHeader['picture_coding_type'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 3); // 3 bits for picture_coding_type
$PictureHeader['vbv_delay'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 16); // 16 bits for vbv_delay
//... etc
$FramesByGOP[$GOPcounter][] = $PictureHeader;
}
break;
case 0xB3: // sequence_header_code
/*
Note: purposely doing the less-pretty (and probably a bit slower) method of using string of bits rather than bitwise operations.
Mostly because PHP 32-bit doesn't handle unsigned integers well for bitwise operation.
Also the MPEG stream is designed as a bitstream and often doesn't align nicely with byte boundaries.
*/
$info['video']['codec'] = 'MPEG-1'; // will be updated if extension_start_code found
$bitstream = getid3_lib::BigEndian2Bin(substr($MPEGstreamData, $StartCodeOffset + 4, 8));
$bitstreamoffset = 0;
$info['mpeg']['video']['raw']['horizontal_size_value'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 12); // 12 bits for horizontal frame size. Note: horizontal_size_extension, if present, will add 2 most-significant bits to this value
$info['mpeg']['video']['raw']['vertical_size_value'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 12); // 12 bits for vertical frame size. Note: vertical_size_extension, if present, will add 2 most-significant bits to this value
$info['mpeg']['video']['raw']['aspect_ratio_information'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 4); // 4 bits for aspect_ratio_information
$info['mpeg']['video']['raw']['frame_rate_code'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 4); // 4 bits for Frame Rate id code
$info['mpeg']['video']['raw']['bitrate'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 18); // 18 bits for bit_rate_value (18 set bits = VBR, otherwise bitrate = this value * 400)
$marker_bit = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // The term "marker_bit" indicates a one bit field in which the value zero is forbidden. These marker bits are introduced at several points in the syntax to avoid start code emulation.
$info['mpeg']['video']['raw']['vbv_buffer_size'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 10); // 10 bits vbv_buffer_size_value
$info['mpeg']['video']['raw']['constrained_param_flag'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: constrained_param_flag
$info['mpeg']['video']['raw']['load_intra_quantiser_matrix'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: load_intra_quantiser_matrix
if ($info['mpeg']['video']['raw']['load_intra_quantiser_matrix']) {
$bitstream .= getid3_lib::BigEndian2Bin(substr($MPEGstreamData, $StartCodeOffset + 12, 64));
for ($i = 0; $i < 64; $i++) {
$info['mpeg']['video']['raw']['intra_quantiser_matrix'][$i] = self::readBitsFromStream($bitstream, $bitstreamoffset, 8);
}
}
$info['mpeg']['video']['raw']['load_non_intra_quantiser_matrix'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1);
if ($info['mpeg']['video']['raw']['load_non_intra_quantiser_matrix']) {
$bitstream .= getid3_lib::BigEndian2Bin(substr($MPEGstreamData, $StartCodeOffset + 12 + ($info['mpeg']['video']['raw']['load_intra_quantiser_matrix'] ? 64 : 0), 64));
for ($i = 0; $i < 64; $i++) {
$info['mpeg']['video']['raw']['non_intra_quantiser_matrix'][$i] = self::readBitsFromStream($bitstream, $bitstreamoffset, 8);
}
}
$info['mpeg']['video']['pixel_aspect_ratio'] = self::videoAspectRatioLookup($info['mpeg']['video']['raw']['aspect_ratio_information']);
$info['mpeg']['video']['pixel_aspect_ratio_text'] = self::videoAspectRatioTextLookup($info['mpeg']['video']['raw']['aspect_ratio_information']);
$info['mpeg']['video']['frame_rate'] = self::videoFramerateLookup($info['mpeg']['video']['raw']['frame_rate_code']);
if ($info['mpeg']['video']['raw']['bitrate'] == 0x3FFFF) { // 18 set bits = VBR
//$this->warning('This version of getID3() ['.$this->getid3->version().'] cannot determine average bitrate of VBR MPEG video files');
$info['mpeg']['video']['bitrate_mode'] = 'vbr';
} else {
$info['mpeg']['video']['bitrate'] = $info['mpeg']['video']['raw']['bitrate'] * 400;
$info['mpeg']['video']['bitrate_mode'] = 'cbr';
$info['video']['bitrate'] = $info['mpeg']['video']['bitrate'];
}
$info['video']['resolution_x'] = $info['mpeg']['video']['raw']['horizontal_size_value'];
$info['video']['resolution_y'] = $info['mpeg']['video']['raw']['vertical_size_value'];
$info['video']['frame_rate'] = $info['mpeg']['video']['frame_rate'];
$info['video']['bitrate_mode'] = $info['mpeg']['video']['bitrate_mode'];
$info['video']['pixel_aspect_ratio'] = $info['mpeg']['video']['pixel_aspect_ratio'];
$info['video']['lossless'] = false;
$info['video']['bits_per_sample'] = 24;
break;
case 0xB5: // extension_start_code
$info['video']['codec'] = 'MPEG-2';
$bitstream = getid3_lib::BigEndian2Bin(substr($MPEGstreamData, $StartCodeOffset + 4, 8)); // 48 bits for Sequence Extension ID; 61 bits for Sequence Display Extension ID; 59 bits for Sequence Scalable Extension ID
$bitstreamoffset = 0;
$info['mpeg']['video']['raw']['extension_start_code_identifier'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 4); // 4 bits for extension_start_code_identifier
//echo $info['mpeg']['video']['raw']['extension_start_code_identifier'].'<br>';
switch ($info['mpeg']['video']['raw']['extension_start_code_identifier']) {
case 1: // 0001 Sequence Extension ID
$info['mpeg']['video']['raw']['profile_and_level_indication'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 8); // 8 bits for profile_and_level_indication
$info['mpeg']['video']['raw']['progressive_sequence'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: progressive_sequence
$info['mpeg']['video']['raw']['chroma_format'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 2); // 2 bits for chroma_format
$info['mpeg']['video']['raw']['horizontal_size_extension'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 2); // 2 bits for horizontal_size_extension
$info['mpeg']['video']['raw']['vertical_size_extension'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 2); // 2 bits for vertical_size_extension
$info['mpeg']['video']['raw']['bit_rate_extension'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 12); // 12 bits for bit_rate_extension
$marker_bit = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // The term "marker_bit" indicates a one bit field in which the value zero is forbidden. These marker bits are introduced at several points in the syntax to avoid start code emulation.
$info['mpeg']['video']['raw']['vbv_buffer_size_extension'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 8); // 8 bits for vbv_buffer_size_extension
$info['mpeg']['video']['raw']['low_delay'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: low_delay
$info['mpeg']['video']['raw']['frame_rate_extension_n'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 2); // 2 bits for frame_rate_extension_n
$info['mpeg']['video']['raw']['frame_rate_extension_d'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 5); // 5 bits for frame_rate_extension_d
$info['video']['resolution_x'] = ($info['mpeg']['video']['raw']['horizontal_size_extension'] << 12) | $info['mpeg']['video']['raw']['horizontal_size_value'];
$info['video']['resolution_y'] = ($info['mpeg']['video']['raw']['vertical_size_extension'] << 12) | $info['mpeg']['video']['raw']['vertical_size_value'];
$info['video']['interlaced'] = !$info['mpeg']['video']['raw']['progressive_sequence'];
$info['mpeg']['video']['interlaced'] = !$info['mpeg']['video']['raw']['progressive_sequence'];
$info['mpeg']['video']['chroma_format'] = self::chromaFormatTextLookup($info['mpeg']['video']['raw']['chroma_format']);
break;
case 2: // 0010 Sequence Display Extension ID
$info['mpeg']['video']['raw']['video_format'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 3); // 3 bits for video_format
$info['mpeg']['video']['raw']['colour_description'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: colour_description
if ($info['mpeg']['video']['raw']['colour_description']) {
$info['mpeg']['video']['raw']['colour_primaries'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 8); // 8 bits for colour_primaries
$info['mpeg']['video']['raw']['transfer_characteristics'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 8); // 8 bits for transfer_characteristics
$info['mpeg']['video']['raw']['matrix_coefficients'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 8); // 8 bits for matrix_coefficients
}
$info['mpeg']['video']['raw']['display_horizontal_size'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 14); // 14 bits for display_horizontal_size
$marker_bit = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // The term "marker_bit" indicates a one bit field in which the value zero is forbidden. These marker bits are introduced at several points in the syntax to avoid start code emulation.
$info['mpeg']['video']['raw']['display_vertical_size'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 14); // 14 bits for display_vertical_size
$info['mpeg']['video']['video_format'] = self::videoFormatTextLookup($info['mpeg']['video']['raw']['video_format']);
break;
case 3: // 0011 Quant Matrix Extension ID
break;
case 5: // 0101 Sequence Scalable Extension ID
$info['mpeg']['video']['raw']['scalable_mode'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 2); // 2 bits for scalable_mode
$info['mpeg']['video']['raw']['layer_id'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 4); // 4 bits for layer_id
if ($info['mpeg']['video']['raw']['scalable_mode'] == 1) { // "spatial scalability"
$info['mpeg']['video']['raw']['lower_layer_prediction_horizontal_size'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 14); // 14 bits for lower_layer_prediction_horizontal_size
$marker_bit = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // The term "marker_bit" indicates a one bit field in which the value zero is forbidden. These marker bits are introduced at several points in the syntax to avoid start code emulation.
$info['mpeg']['video']['raw']['lower_layer_prediction_vertical_size'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 14); // 14 bits for lower_layer_prediction_vertical_size
$info['mpeg']['video']['raw']['horizontal_subsampling_factor_m'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 5); // 5 bits for horizontal_subsampling_factor_m
$info['mpeg']['video']['raw']['horizontal_subsampling_factor_n'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 5); // 5 bits for horizontal_subsampling_factor_n
$info['mpeg']['video']['raw']['vertical_subsampling_factor_m'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 5); // 5 bits for vertical_subsampling_factor_m
$info['mpeg']['video']['raw']['vertical_subsampling_factor_n'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 5); // 5 bits for vertical_subsampling_factor_n
} elseif ($info['mpeg']['video']['raw']['scalable_mode'] == 3) { // "temporal scalability"
$info['mpeg']['video']['raw']['picture_mux_enable'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: picture_mux_enable
if ($info['mpeg']['video']['raw']['picture_mux_enable']) {
$info['mpeg']['video']['raw']['mux_to_progressive_sequence'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: mux_to_progressive_sequence
}
$info['mpeg']['video']['raw']['picture_mux_order'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 3); // 3 bits for picture_mux_order
$info['mpeg']['video']['raw']['picture_mux_factor'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 3); // 3 bits for picture_mux_factor
}
$info['mpeg']['video']['scalable_mode'] = self::scalableModeTextLookup($info['mpeg']['video']['raw']['scalable_mode']);
break;
case 7: // 0111 Picture Display Extension ID
break;
case 8: // 1000 Picture Coding Extension ID
$info['mpeg']['video']['raw']['f_code_00'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 4); // 4 bits for f_code[0][0] (forward horizontal)
$info['mpeg']['video']['raw']['f_code_01'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 4); // 4 bits for f_code[0][1] (forward vertical)
$info['mpeg']['video']['raw']['f_code_10'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 4); // 4 bits for f_code[1][0] (backward horizontal)
$info['mpeg']['video']['raw']['f_code_11'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 4); // 4 bits for f_code[1][1] (backward vertical)
$info['mpeg']['video']['raw']['intra_dc_precision'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 2); // 2 bits for intra_dc_precision
$info['mpeg']['video']['raw']['picture_structure'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 2); // 2 bits for picture_structure
$info['mpeg']['video']['raw']['top_field_first'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: top_field_first
$info['mpeg']['video']['raw']['frame_pred_frame_dct'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: frame_pred_frame_dct
$info['mpeg']['video']['raw']['concealment_motion_vectors'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: concealment_motion_vectors
$info['mpeg']['video']['raw']['q_scale_type'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: q_scale_type
$info['mpeg']['video']['raw']['intra_vlc_format'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: intra_vlc_format
$info['mpeg']['video']['raw']['alternate_scan'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: alternate_scan
$info['mpeg']['video']['raw']['repeat_first_field'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: repeat_first_field
$info['mpeg']['video']['raw']['chroma_420_type'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: chroma_420_type
$info['mpeg']['video']['raw']['progressive_frame'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: progressive_frame
$info['mpeg']['video']['raw']['composite_display_flag'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: composite_display_flag
if ($info['mpeg']['video']['raw']['composite_display_flag']) {
$info['mpeg']['video']['raw']['v_axis'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: v_axis
$info['mpeg']['video']['raw']['field_sequence'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 3); // 3 bits for field_sequence
$info['mpeg']['video']['raw']['sub_carrier'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: sub_carrier
$info['mpeg']['video']['raw']['burst_amplitude'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 7); // 7 bits for burst_amplitude
$info['mpeg']['video']['raw']['sub_carrier_phase'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 8); // 8 bits for sub_carrier_phase
}
$info['mpeg']['video']['intra_dc_precision_bits'] = $info['mpeg']['video']['raw']['intra_dc_precision'] + 8;
$info['mpeg']['video']['picture_structure'] = self::pictureStructureTextLookup($info['mpeg']['video']['raw']['picture_structure']);
break;
case 9: // 1001 Picture Spatial Scalable Extension ID
break;
case 10: // 1010 Picture Temporal Scalable Extension ID
break;
default:
$this->warning('Unexpected $info[mpeg][video][raw][extension_start_code_identifier] value of '.$info['mpeg']['video']['raw']['extension_start_code_identifier']);
break;
}
break;
case 0xB8: // group_of_pictures_header
$GOPcounter++;
if ($info['mpeg']['video']['bitrate_mode'] == 'vbr') {
$bitstream = getid3_lib::BigEndian2Bin(substr($MPEGstreamData, $StartCodeOffset + 4, 4)); // 27 bits needed for group_of_pictures_header
$bitstreamoffset = 0;
$GOPheader = array();
$GOPheader['byte_offset'] = $MPEGstreamBaseOffset + $StartCodeOffset;
$GOPheader['drop_frame_flag'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: drop_frame_flag
$GOPheader['time_code_hours'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 5); // 5 bits for time_code_hours
$GOPheader['time_code_minutes'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 6); // 6 bits for time_code_minutes
$marker_bit = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // The term "marker_bit" indicates a one bit field in which the value zero is forbidden. These marker bits are introduced at several points in the syntax to avoid start code emulation.
$GOPheader['time_code_seconds'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 6); // 6 bits for time_code_seconds
$GOPheader['time_code_pictures'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 6); // 6 bits for time_code_pictures
$GOPheader['closed_gop'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: closed_gop
$GOPheader['broken_link'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: broken_link
$time_code_separator = ($GOPheader['drop_frame_flag'] ? ';' : ':'); // While non-drop time code is displayed with colons separating the digit pairs—"HH:MM:SS:FF"—drop frame is usually represented with a semi-colon (;) or period (.) as the divider between all the digit pairs—"HH;MM;SS;FF", "HH.MM.SS.FF"
$GOPheader['time_code'] = sprintf('%02d'.$time_code_separator.'%02d'.$time_code_separator.'%02d'.$time_code_separator.'%02d', $GOPheader['time_code_hours'], $GOPheader['time_code_minutes'], $GOPheader['time_code_seconds'], $GOPheader['time_code_pictures']);
$info['mpeg']['group_of_pictures'][] = $GOPheader;
}
break;
case 0xC0: // audio stream
case 0xC1: // audio stream
case 0xC2: // audio stream
case 0xC3: // audio stream
case 0xC4: // audio stream
case 0xC5: // audio stream
case 0xC6: // audio stream
case 0xC7: // audio stream
case 0xC8: // audio stream
case 0xC9: // audio stream
case 0xCA: // audio stream
case 0xCB: // audio stream
case 0xCC: // audio stream
case 0xCD: // audio stream
case 0xCE: // audio stream
case 0xCF: // audio stream
case 0xD0: // audio stream
case 0xD1: // audio stream
case 0xD2: // audio stream
case 0xD3: // audio stream
case 0xD4: // audio stream
case 0xD5: // audio stream
case 0xD6: // audio stream
case 0xD7: // audio stream
case 0xD8: // audio stream
case 0xD9: // audio stream
case 0xDA: // audio stream
case 0xDB: // audio stream
case 0xDC: // audio stream
case 0xDD: // audio stream
case 0xDE: // audio stream
case 0xDF: // audio stream
//case 0xE0: // video stream
//case 0xE1: // video stream
//case 0xE2: // video stream
//case 0xE3: // video stream
//case 0xE4: // video stream
//case 0xE5: // video stream
//case 0xE6: // video stream
//case 0xE7: // video stream
//case 0xE8: // video stream
//case 0xE9: // video stream
//case 0xEA: // video stream
//case 0xEB: // video stream
//case 0xEC: // video stream
//case 0xED: // video stream
//case 0xEE: // video stream
//case 0xEF: // video stream
if (isset($ParsedAVchannels[$StartCodeValue])) {
break;
}
$ParsedAVchannels[$StartCodeValue] = $StartCodeValue;
// http://en.wikipedia.org/wiki/Packetized_elementary_stream
// http://dvd.sourceforge.net/dvdinfo/pes-hdr.html
/*
$PackedElementaryStream = array();
if ($StartCodeValue >= 0xE0) {
$PackedElementaryStream['stream_type'] = 'video';
$PackedElementaryStream['stream_id'] = $StartCodeValue - 0xE0;
} else {
$PackedElementaryStream['stream_type'] = 'audio';
$PackedElementaryStream['stream_id'] = $StartCodeValue - 0xC0;
}
$PackedElementaryStream['packet_length'] = getid3_lib::BigEndian2Int(substr($MPEGstreamData, $StartCodeOffset + 4, 2));
$bitstream = getid3_lib::BigEndian2Bin(substr($MPEGstreamData, $StartCodeOffset + 6, 3)); // more may be needed below
$bitstreamoffset = 0;
$PackedElementaryStream['marker_bits'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 2); // 2 bits for marker_bits -- should be "10" = 2
echo 'marker_bits = '.$PackedElementaryStream['marker_bits'].'<br>';
$PackedElementaryStream['scrambling_control'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 2); // 2 bits for scrambling_control -- 00 implies not scrambled
$PackedElementaryStream['priority'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: priority
$PackedElementaryStream['data_alignment_indicator'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: data_alignment_indicator -- 1 indicates that the PES packet header is immediately followed by the video start code or audio syncword
$PackedElementaryStream['copyright'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: copyright -- 1 implies copyrighted
$PackedElementaryStream['original_or_copy'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: original_or_copy -- 1 implies original
$PackedElementaryStream['pts_flag'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: pts_flag -- Presentation Time Stamp
$PackedElementaryStream['dts_flag'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: dts_flag -- Decode Time Stamp
$PackedElementaryStream['escr_flag'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: escr_flag -- Elementary Stream Clock Reference
$PackedElementaryStream['es_rate_flag'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: es_rate_flag -- Elementary Stream [data] Rate
$PackedElementaryStream['dsm_trick_mode_flag'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: dsm_trick_mode_flag -- DSM trick mode - not used by DVD
$PackedElementaryStream['additional_copy_info_flag'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: additional_copy_info_flag
$PackedElementaryStream['crc_flag'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: crc_flag
$PackedElementaryStream['extension_flag'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 1); // 1 bit flag: extension_flag
$PackedElementaryStream['pes_remain_header_length'] = self::readBitsFromStream($bitstream, $bitstreamoffset, 8); // 1 bit flag: priority
$additional_header_bytes = 0;
$additional_header_bytes += ($PackedElementaryStream['pts_flag'] ? 5 : 0);
$additional_header_bytes += ($PackedElementaryStream['dts_flag'] ? 5 : 0);
$additional_header_bytes += ($PackedElementaryStream['escr_flag'] ? 6 : 0);
$additional_header_bytes += ($PackedElementaryStream['es_rate_flag'] ? 3 : 0);
$additional_header_bytes += ($PackedElementaryStream['additional_copy_info_flag'] ? 1 : 0);
$additional_header_bytes += ($PackedElementaryStream['crc_flag'] ? 2 : 0);
$additional_header_bytes += ($PackedElementaryStream['extension_flag'] ? 1 : 0);
$PackedElementaryStream['additional_header_bytes'] = $additional_header_bytes;
$bitstream .= getid3_lib::BigEndian2Bin(substr($MPEGstreamData, $StartCodeOffset + 9, $additional_header_bytes));
$info['mpeg']['packed_elementary_streams'][$PackedElementaryStream['stream_type']][$PackedElementaryStream['stream_id']][] = $PackedElementaryStream;
*/
$getid3_temp = new getID3();
$getid3_temp->openfile($this->getid3->filename);
$getid3_temp->info = $info;
$getid3_mp3 = new getid3_mp3($getid3_temp);
for ($i = 0; $i <= 7; $i++) {
// some files have the MPEG-audio header 8 bytes after the end of the $00 $00 $01 $C0 signature, some have it up to 13 bytes (or more?) after
// I have no idea why or what the difference is, so this is a stupid hack.
// If anybody has any better idea of what's going on, please let me know - info@getid3.org
$getid3_temp->info = $info; // only overwrite real data if valid header found
//echo 'audio at? '.($MPEGstreamBaseOffset + $StartCodeOffset + 4 + 8 + $i).'<br>';
if ($getid3_mp3->decodeMPEGaudioHeader($MPEGstreamBaseOffset + $StartCodeOffset + 4 + 8 + $i, $getid3_temp->info, false)) {
//echo 'yes!<br>';
$info = $getid3_temp->info;
$info['audio']['bitrate_mode'] = 'cbr';
$info['audio']['lossless'] = false;
break;
}
}
unset($getid3_temp, $getid3_mp3);
break;
case 0xBC: // Program Stream Map
case 0xBD: // Private stream 1 (non MPEG audio, subpictures)
case 0xBE: // Padding stream
case 0xBF: // Private stream 2 (navigation data)
case 0xF0: // ECM stream
case 0xF1: // EMM stream
case 0xF2: // DSM-CC stream
case 0xF3: // ISO/IEC_13522_stream
case 0xF4: // ITU-I Rec. H.222.1 type A
case 0xF5: // ITU-I Rec. H.222.1 type B
case 0xF6: // ITU-I Rec. H.222.1 type C
case 0xF7: // ITU-I Rec. H.222.1 type D
case 0xF8: // ITU-I Rec. H.222.1 type E
case 0xF9: // ancilliary stream
case 0xFA: // ISO/IEC 14496-1 SL-packtized stream
case 0xFB: // ISO/IEC 14496-1 FlexMux stream
case 0xFC: // metadata stream
case 0xFD: // extended stream ID
case 0xFE: // reserved data stream
case 0xFF: // program stream directory
// ignore
break;
default:
// ignore
break;
}
} while (true);
// // Temporary hack to account for interleaving overhead:
// if (!empty($info['video']['bitrate']) && !empty($info['audio']['bitrate'])) {
// $info['playtime_seconds'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / ($info['video']['bitrate'] + $info['audio']['bitrate']);
//
// // Interleaved MPEG audio/video files have a certain amount of overhead that varies
// // by both video and audio bitrates, and not in any sensible, linear/logarithmic pattern
// // Use interpolated lookup tables to approximately guess how much is overhead, because
// // playtime is calculated as filesize / total-bitrate
// $info['playtime_seconds'] *= self::systemNonOverheadPercentage($info['video']['bitrate'], $info['audio']['bitrate']);
//
// //switch ($info['video']['bitrate']) {
// // case('5000000'):
// // $multiplier = 0.93292642112380355828048824319889;
// // break;
// // case('5500000'):
// // $multiplier = 0.93582895375200989965359777343219;
// // break;
// // case('6000000'):
// // $multiplier = 0.93796247714820932532911373859139;
// // break;
// // case('7000000'):
// // $multiplier = 0.9413264083635103463010117778776;
// // break;
// // default:
// // $multiplier = 1;
// // break;
// //}
// //$info['playtime_seconds'] *= $multiplier;
// //$info['warning'][] = 'Interleaved MPEG audio/video playtime may be inaccurate. With current hack should be within a few seconds of accurate. Report to info@getid3.org if off by more than 10 seconds.';
// if ($info['video']['bitrate'] < 50000) {
// $this->warning('Interleaved MPEG audio/video playtime may be slightly inaccurate for video bitrates below 100kbps. Except in extreme low-bitrate situations, error should be less than 1%. Report to info@getid3.org if greater than this.');
// }
// }
//
/*
$time_prev = 0;
$byte_prev = 0;
$vbr_bitrates = array();
foreach ($info['mpeg']['group_of_pictures'] as $gopkey => $gopdata) {
$time_this = ($gopdata['time_code_hours'] * 3600) + ($gopdata['time_code_minutes'] * 60) + $gopdata['time_code_seconds'] + ($gopdata['time_code_seconds'] / 30);
$byte_this = $gopdata['byte_offset'];
if ($gopkey > 0) {
if ($time_this > $time_prev) {
$bytedelta = $byte_this - $byte_prev;
$timedelta = $time_this - $time_prev;
$this_bitrate = ($bytedelta * 8) / $timedelta;
echo $gopkey.': ('.number_format($time_prev, 2).'-'.number_format($time_this, 2).') '.number_format($bytedelta).' bytes over '.number_format($timedelta, 3).' seconds = '.number_format($this_bitrate / 1000, 2).'kbps<br>';
$time_prev = $time_this;
$byte_prev = $byte_this;
$vbr_bitrates[] = $this_bitrate;
}
}
}
echo 'average_File_bitrate = '.number_format(array_sum($vbr_bitrates) / count($vbr_bitrates), 1).'<br>';
*/
//echo '<pre>'.print_r($FramesByGOP, true).'</pre>';
if (!empty($info['mpeg']['video']['bitrate_mode']) && ($info['mpeg']['video']['bitrate_mode'] == 'vbr')) {
$last_GOP_id = max(array_keys($FramesByGOP));
$frames_in_last_GOP = count($FramesByGOP[$last_GOP_id]);
$gopdata = &$info['mpeg']['group_of_pictures'][$last_GOP_id];
$info['playtime_seconds'] = ($gopdata['time_code_hours'] * 3600) + ($gopdata['time_code_minutes'] * 60) + $gopdata['time_code_seconds'] + (($gopdata['time_code_pictures'] + $frames_in_last_GOP + 1) / $info['mpeg']['video']['frame_rate']);
if (!isset($info['video']['bitrate'])) {
$overall_bitrate = ($info['avdataend'] - $info['avdataoffset']) * 8 / $info['playtime_seconds'];
$info['video']['bitrate'] = $overall_bitrate - (isset($info['audio']['bitrate']) ? $info['audio']['bitrate'] : 0);
}
unset($info['mpeg']['group_of_pictures']);
}
return true;
}
private function readBitsFromStream(&$bitstream, &$bitstreamoffset, $bits_to_read, $return_singlebit_as_boolean=true) {
$return = bindec(substr($bitstream, $bitstreamoffset, $bits_to_read));
$bitstreamoffset += $bits_to_read;
if (($bits_to_read == 1) && $return_singlebit_as_boolean) {
$return = (bool) $return;
}
return $return;
}
public static function systemNonOverheadPercentage($VideoBitrate, $AudioBitrate) {
$OverheadPercentage = 0;
$AudioBitrate = max(min($AudioBitrate / 1000, 384), 32); // limit to range of 32kbps - 384kbps (should be only legal bitrates, but maybe VBR?)
$VideoBitrate = max(min($VideoBitrate / 1000, 10000), 10); // limit to range of 10kbps - 10Mbps (beyond that curves flatten anyways, no big loss)
//OMBB[audiobitrate] = array(video-10kbps, video-100kbps, video-1000kbps, video-10000kbps)
$OverheadMultiplierByBitrate[32] = array(0, 0.9676287944368530, 0.9802276264360310, 0.9844916183244460, 0.9852821845179940);
$OverheadMultiplierByBitrate[48] = array(0, 0.9779100089209830, 0.9787770035359320, 0.9846738664076130, 0.9852683013799960);
$OverheadMultiplierByBitrate[56] = array(0, 0.9731249855367600, 0.9776624308938040, 0.9832606361852130, 0.9843922606633340);
$OverheadMultiplierByBitrate[64] = array(0, 0.9755642683275760, 0.9795256705493390, 0.9836573009193170, 0.9851122539404470);
$OverheadMultiplierByBitrate[96] = array(0, 0.9788025247497290, 0.9798553314148700, 0.9822956869792560, 0.9834815119124690);
$OverheadMultiplierByBitrate[128] = array(0, 0.9816940050925480, 0.9821675936072120, 0.9829756927470870, 0.9839763420152050);
$OverheadMultiplierByBitrate[160] = array(0, 0.9825894094561180, 0.9820913399073960, 0.9823907143253970, 0.9832821783651570);
$OverheadMultiplierByBitrate[192] = array(0, 0.9832038474336260, 0.9825731694317960, 0.9821028622712400, 0.9828262076447620);
$OverheadMultiplierByBitrate[224] = array(0, 0.9836516298538770, 0.9824718601823890, 0.9818302180625380, 0.9823735101626480);
$OverheadMultiplierByBitrate[256] = array(0, 0.9845863022094920, 0.9837229411967540, 0.9824521662210830, 0.9828645172100790);
$OverheadMultiplierByBitrate[320] = array(0, 0.9849565280263180, 0.9837683142805110, 0.9822885275960400, 0.9824424382727190);
$OverheadMultiplierByBitrate[384] = array(0, 0.9856094774357600, 0.9844573394432720, 0.9825970399837330, 0.9824673808303890);
$BitrateToUseMin = 32;
$BitrateToUseMax = 32;
$previousBitrate = 32;
foreach ($OverheadMultiplierByBitrate as $key => $value) {
if ($AudioBitrate >= $previousBitrate) {
$BitrateToUseMin = $previousBitrate;
}
if ($AudioBitrate < $key) {
$BitrateToUseMax = $key;
break;
}
$previousBitrate = $key;
}
$FactorA = ($BitrateToUseMax - $AudioBitrate) / ($BitrateToUseMax - $BitrateToUseMin);
$VideoBitrateLog10 = log10($VideoBitrate);
$VideoFactorMin1 = $OverheadMultiplierByBitrate[$BitrateToUseMin][floor($VideoBitrateLog10)];
$VideoFactorMin2 = $OverheadMultiplierByBitrate[$BitrateToUseMax][floor($VideoBitrateLog10)];
$VideoFactorMax1 = $OverheadMultiplierByBitrate[$BitrateToUseMin][ceil($VideoBitrateLog10)];
$VideoFactorMax2 = $OverheadMultiplierByBitrate[$BitrateToUseMax][ceil($VideoBitrateLog10)];
$FactorV = $VideoBitrateLog10 - floor($VideoBitrateLog10);
$OverheadPercentage = $VideoFactorMin1 * $FactorA * $FactorV;
$OverheadPercentage += $VideoFactorMin2 * (1 - $FactorA) * $FactorV;
$OverheadPercentage += $VideoFactorMax1 * $FactorA * (1 - $FactorV);
$OverheadPercentage += $VideoFactorMax2 * (1 - $FactorA) * (1 - $FactorV);
return $OverheadPercentage;
}
public static function videoFramerateLookup($rawframerate) {
$lookup = array(0, 23.976, 24, 25, 29.97, 30, 50, 59.94, 60);
return (isset($lookup[$rawframerate]) ? (float) $lookup[$rawframerate] : (float) 0);
}
public static function videoAspectRatioLookup($rawaspectratio) {
$lookup = array(0, 1, 0.6735, 0.7031, 0.7615, 0.8055, 0.8437, 0.8935, 0.9157, 0.9815, 1.0255, 1.0695, 1.0950, 1.1575, 1.2015, 0);
return (isset($lookup[$rawaspectratio]) ? (float) $lookup[$rawaspectratio] : (float) 0);
}
public static function videoAspectRatioTextLookup($rawaspectratio) {
$lookup = array('forbidden', 'square pixels', '0.6735', '16:9, 625 line, PAL', '0.7615', '0.8055', '16:9, 525 line, NTSC', '0.8935', '4:3, 625 line, PAL, CCIR601', '0.9815', '1.0255', '1.0695', '4:3, 525 line, NTSC, CCIR601', '1.1575', '1.2015', 'reserved');
return (isset($lookup[$rawaspectratio]) ? $lookup[$rawaspectratio] : '');
}
public static function videoFormatTextLookup($video_format) {
// ISO/IEC 13818-2, section 6.3.6, Table 6-6. Meaning of video_format
$lookup = array('component', 'PAL', 'NTSC', 'SECAM', 'MAC', 'Unspecified video format', 'reserved(6)', 'reserved(7)');
return (isset($lookup[$video_format]) ? $lookup[$video_format] : '');
}
public static function scalableModeTextLookup($scalable_mode) {
// ISO/IEC 13818-2, section 6.3.8, Table 6-10. Definition of scalable_mode
$lookup = array('data partitioning', 'spatial scalability', 'SNR scalability', 'temporal scalability');
return (isset($lookup[$scalable_mode]) ? $lookup[$scalable_mode] : '');
}
public static function pictureStructureTextLookup($picture_structure) {
// ISO/IEC 13818-2, section 6.3.11, Table 6-14 Meaning of picture_structure
$lookup = array('reserved', 'Top Field', 'Bottom Field', 'Frame picture');
return (isset($lookup[$picture_structure]) ? $lookup[$picture_structure] : '');
}
public static function chromaFormatTextLookup($chroma_format) {
// ISO/IEC 13818-2, section 6.3.11, Table 6-14 Meaning of picture_structure
$lookup = array('reserved', '4:2:0', '4:2:2', '4:4:4');
return (isset($lookup[$chroma_format]) ? $lookup[$chroma_format] : '');
}
}

View File

@ -1,443 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
// also https://github.com/JamesHeinrich/getID3 //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.audio.flac.php //
// module for analyzing FLAC and OggFLAC audio files //
// dependencies: module.audio.ogg.php //
// ///
/////////////////////////////////////////////////////////////////
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ogg.php', __FILE__, true);
/**
* @tutorial http://flac.sourceforge.net/format.html
*/
class getid3_flac extends getid3_handler
{
const syncword = 'fLaC';
public function Analyze() {
$info = &$this->getid3->info;
$this->fseek($info['avdataoffset']);
$StreamMarker = $this->fread(4);
if ($StreamMarker != self::syncword) {
return $this->error('Expecting "'.getid3_lib::PrintHexBytes(self::syncword).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($StreamMarker).'"');
}
$info['fileformat'] = 'flac';
$info['audio']['dataformat'] = 'flac';
$info['audio']['bitrate_mode'] = 'vbr';
$info['audio']['lossless'] = true;
// parse flac container
return $this->parseMETAdata();
}
public function parseMETAdata() {
$info = &$this->getid3->info;
do {
$BlockOffset = $this->ftell();
$BlockHeader = $this->fread(4);
$LBFBT = getid3_lib::BigEndian2Int(substr($BlockHeader, 0, 1));
$LastBlockFlag = (bool) ($LBFBT & 0x80);
$BlockType = ($LBFBT & 0x7F);
$BlockLength = getid3_lib::BigEndian2Int(substr($BlockHeader, 1, 3));
$BlockTypeText = self::metaBlockTypeLookup($BlockType);
if (($BlockOffset + 4 + $BlockLength) > $info['avdataend']) {
$this->error('METADATA_BLOCK_HEADER.BLOCK_TYPE ('.$BlockTypeText.') at offset '.$BlockOffset.' extends beyond end of file');
break;
}
if ($BlockLength < 1) {
$this->error('METADATA_BLOCK_HEADER.BLOCK_LENGTH ('.$BlockLength.') at offset '.$BlockOffset.' is invalid');
break;
}
$info['flac'][$BlockTypeText]['raw'] = array();
$BlockTypeText_raw = &$info['flac'][$BlockTypeText]['raw'];
$BlockTypeText_raw['offset'] = $BlockOffset;
$BlockTypeText_raw['last_meta_block'] = $LastBlockFlag;
$BlockTypeText_raw['block_type'] = $BlockType;
$BlockTypeText_raw['block_type_text'] = $BlockTypeText;
$BlockTypeText_raw['block_length'] = $BlockLength;
if ($BlockTypeText_raw['block_type'] != 0x06) { // do not read attachment data automatically
$BlockTypeText_raw['block_data'] = $this->fread($BlockLength);
}
switch ($BlockTypeText) {
case 'STREAMINFO': // 0x00
if (!$this->parseSTREAMINFO($BlockTypeText_raw['block_data'])) {
return false;
}
break;
case 'PADDING': // 0x01
unset($info['flac']['PADDING']); // ignore
break;
case 'APPLICATION': // 0x02
if (!$this->parseAPPLICATION($BlockTypeText_raw['block_data'])) {
return false;
}
break;
case 'SEEKTABLE': // 0x03
if (!$this->parseSEEKTABLE($BlockTypeText_raw['block_data'])) {
return false;
}
break;
case 'VORBIS_COMMENT': // 0x04
if (!$this->parseVORBIS_COMMENT($BlockTypeText_raw['block_data'])) {
return false;
}
break;
case 'CUESHEET': // 0x05
if (!$this->parseCUESHEET($BlockTypeText_raw['block_data'])) {
return false;
}
break;
case 'PICTURE': // 0x06
if (!$this->parsePICTURE()) {
return false;
}
break;
default:
$this->warning('Unhandled METADATA_BLOCK_HEADER.BLOCK_TYPE ('.$BlockType.') at offset '.$BlockOffset);
}
unset($info['flac'][$BlockTypeText]['raw']);
$info['avdataoffset'] = $this->ftell();
}
while ($LastBlockFlag === false);
// handle tags
if (!empty($info['flac']['VORBIS_COMMENT']['comments'])) {
$info['flac']['comments'] = $info['flac']['VORBIS_COMMENT']['comments'];
}
if (!empty($info['flac']['VORBIS_COMMENT']['vendor'])) {
$info['audio']['encoder'] = str_replace('reference ', '', $info['flac']['VORBIS_COMMENT']['vendor']);
}
// copy attachments to 'comments' array if nesesary
if (isset($info['flac']['PICTURE']) && ($this->getid3->option_save_attachments !== getID3::ATTACHMENTS_NONE)) {
foreach ($info['flac']['PICTURE'] as $entry) {
if (!empty($entry['data'])) {
$info['flac']['comments']['picture'][] = array('image_mime'=>$entry['image_mime'], 'data'=>$entry['data']);
}
}
}
if (isset($info['flac']['STREAMINFO'])) {
if (!$this->isDependencyFor('matroska')) {
$info['flac']['compressed_audio_bytes'] = $info['avdataend'] - $info['avdataoffset'];
}
$info['flac']['uncompressed_audio_bytes'] = $info['flac']['STREAMINFO']['samples_stream'] * $info['flac']['STREAMINFO']['channels'] * ($info['flac']['STREAMINFO']['bits_per_sample'] / 8);
if ($info['flac']['uncompressed_audio_bytes'] == 0) {
return $this->error('Corrupt FLAC file: uncompressed_audio_bytes == zero');
}
if (!empty($info['flac']['compressed_audio_bytes'])) {
$info['flac']['compression_ratio'] = $info['flac']['compressed_audio_bytes'] / $info['flac']['uncompressed_audio_bytes'];
}
}
// set md5_data_source - built into flac 0.5+
if (isset($info['flac']['STREAMINFO']['audio_signature'])) {
if ($info['flac']['STREAMINFO']['audio_signature'] === str_repeat("\x00", 16)) {
$this->warning('FLAC STREAMINFO.audio_signature is null (known issue with libOggFLAC)');
}
else {
$info['md5_data_source'] = '';
$md5 = $info['flac']['STREAMINFO']['audio_signature'];
for ($i = 0; $i < strlen($md5); $i++) {
$info['md5_data_source'] .= str_pad(dechex(ord($md5[$i])), 2, '00', STR_PAD_LEFT);
}
if (!preg_match('/^[0-9a-f]{32}$/', $info['md5_data_source'])) {
unset($info['md5_data_source']);
}
}
}
if (isset($info['flac']['STREAMINFO']['bits_per_sample'])) {
$info['audio']['bits_per_sample'] = $info['flac']['STREAMINFO']['bits_per_sample'];
if ($info['audio']['bits_per_sample'] == 8) {
// special case
// must invert sign bit on all data bytes before MD5'ing to match FLAC's calculated value
// MD5sum calculates on unsigned bytes, but FLAC calculated MD5 on 8-bit audio data as signed
$this->warning('FLAC calculates MD5 data strangely on 8-bit audio, so the stored md5_data_source value will not match the decoded WAV file');
}
}
return true;
}
private function parseSTREAMINFO($BlockData) {
$info = &$this->getid3->info;
$info['flac']['STREAMINFO'] = array();
$streaminfo = &$info['flac']['STREAMINFO'];
$streaminfo['min_block_size'] = getid3_lib::BigEndian2Int(substr($BlockData, 0, 2));
$streaminfo['max_block_size'] = getid3_lib::BigEndian2Int(substr($BlockData, 2, 2));
$streaminfo['min_frame_size'] = getid3_lib::BigEndian2Int(substr($BlockData, 4, 3));
$streaminfo['max_frame_size'] = getid3_lib::BigEndian2Int(substr($BlockData, 7, 3));
$SRCSBSS = getid3_lib::BigEndian2Bin(substr($BlockData, 10, 8));
$streaminfo['sample_rate'] = getid3_lib::Bin2Dec(substr($SRCSBSS, 0, 20));
$streaminfo['channels'] = getid3_lib::Bin2Dec(substr($SRCSBSS, 20, 3)) + 1;
$streaminfo['bits_per_sample'] = getid3_lib::Bin2Dec(substr($SRCSBSS, 23, 5)) + 1;
$streaminfo['samples_stream'] = getid3_lib::Bin2Dec(substr($SRCSBSS, 28, 36));
$streaminfo['audio_signature'] = substr($BlockData, 18, 16);
if (!empty($streaminfo['sample_rate'])) {
$info['audio']['bitrate_mode'] = 'vbr';
$info['audio']['sample_rate'] = $streaminfo['sample_rate'];
$info['audio']['channels'] = $streaminfo['channels'];
$info['audio']['bits_per_sample'] = $streaminfo['bits_per_sample'];
$info['playtime_seconds'] = $streaminfo['samples_stream'] / $streaminfo['sample_rate'];
if ($info['playtime_seconds'] > 0) {
if (!$this->isDependencyFor('matroska')) {
$info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
}
else {
$this->warning('Cannot determine audio bitrate because total stream size is unknown');
}
}
} else {
return $this->error('Corrupt METAdata block: STREAMINFO');
}
return true;
}
private function parseAPPLICATION($BlockData) {
$info = &$this->getid3->info;
$ApplicationID = getid3_lib::BigEndian2Int(substr($BlockData, 0, 4));
$info['flac']['APPLICATION'][$ApplicationID]['name'] = self::applicationIDLookup($ApplicationID);
$info['flac']['APPLICATION'][$ApplicationID]['data'] = substr($BlockData, 4);
return true;
}
private function parseSEEKTABLE($BlockData) {
$info = &$this->getid3->info;
$offset = 0;
$BlockLength = strlen($BlockData);
$placeholderpattern = str_repeat("\xFF", 8);
while ($offset < $BlockLength) {
$SampleNumberString = substr($BlockData, $offset, 8);
$offset += 8;
if ($SampleNumberString == $placeholderpattern) {
// placeholder point
getid3_lib::safe_inc($info['flac']['SEEKTABLE']['placeholders'], 1);
$offset += 10;
} else {
$SampleNumber = getid3_lib::BigEndian2Int($SampleNumberString);
$info['flac']['SEEKTABLE'][$SampleNumber]['offset'] = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 8));
$offset += 8;
$info['flac']['SEEKTABLE'][$SampleNumber]['samples'] = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 2));
$offset += 2;
}
}
return true;
}
private function parseVORBIS_COMMENT($BlockData) {
$info = &$this->getid3->info;
$getid3_ogg = new getid3_ogg($this->getid3);
if ($this->isDependencyFor('matroska')) {
$getid3_ogg->setStringMode($this->data_string);
}
$getid3_ogg->ParseVorbisComments();
if (isset($info['ogg'])) {
unset($info['ogg']['comments_raw']);
$info['flac']['VORBIS_COMMENT'] = $info['ogg'];
unset($info['ogg']);
}
unset($getid3_ogg);
return true;
}
private function parseCUESHEET($BlockData) {
$info = &$this->getid3->info;
$offset = 0;
$info['flac']['CUESHEET']['media_catalog_number'] = trim(substr($BlockData, $offset, 128), "\0");
$offset += 128;
$info['flac']['CUESHEET']['lead_in_samples'] = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 8));
$offset += 8;
$info['flac']['CUESHEET']['flags']['is_cd'] = (bool) (getid3_lib::BigEndian2Int(substr($BlockData, $offset, 1)) & 0x80);
$offset += 1;
$offset += 258; // reserved
$info['flac']['CUESHEET']['number_tracks'] = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 1));
$offset += 1;
for ($track = 0; $track < $info['flac']['CUESHEET']['number_tracks']; $track++) {
$TrackSampleOffset = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 8));
$offset += 8;
$TrackNumber = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 1));
$offset += 1;
$info['flac']['CUESHEET']['tracks'][$TrackNumber]['sample_offset'] = $TrackSampleOffset;
$info['flac']['CUESHEET']['tracks'][$TrackNumber]['isrc'] = substr($BlockData, $offset, 12);
$offset += 12;
$TrackFlagsRaw = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 1));
$offset += 1;
$info['flac']['CUESHEET']['tracks'][$TrackNumber]['flags']['is_audio'] = (bool) ($TrackFlagsRaw & 0x80);
$info['flac']['CUESHEET']['tracks'][$TrackNumber]['flags']['pre_emphasis'] = (bool) ($TrackFlagsRaw & 0x40);
$offset += 13; // reserved
$info['flac']['CUESHEET']['tracks'][$TrackNumber]['index_points'] = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 1));
$offset += 1;
for ($index = 0; $index < $info['flac']['CUESHEET']['tracks'][$TrackNumber]['index_points']; $index++) {
$IndexSampleOffset = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 8));
$offset += 8;
$IndexNumber = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 1));
$offset += 1;
$offset += 3; // reserved
$info['flac']['CUESHEET']['tracks'][$TrackNumber]['indexes'][$IndexNumber] = $IndexSampleOffset;
}
}
return true;
}
/**
* Parse METADATA_BLOCK_PICTURE flac structure and extract attachment
* External usage: audio.ogg
*/
public function parsePICTURE() {
$info = &$this->getid3->info;
$picture['typeid'] = getid3_lib::BigEndian2Int($this->fread(4));
$picture['type'] = self::pictureTypeLookup($picture['typeid']);
$picture['image_mime'] = $this->fread(getid3_lib::BigEndian2Int($this->fread(4)));
$descr_length = getid3_lib::BigEndian2Int($this->fread(4));
if ($descr_length) {
$picture['description'] = $this->fread($descr_length);
}
$picture['width'] = getid3_lib::BigEndian2Int($this->fread(4));
$picture['height'] = getid3_lib::BigEndian2Int($this->fread(4));
$picture['color_depth'] = getid3_lib::BigEndian2Int($this->fread(4));
$picture['colors_indexed'] = getid3_lib::BigEndian2Int($this->fread(4));
$data_length = getid3_lib::BigEndian2Int($this->fread(4));
if ($picture['image_mime'] == '-->') {
$picture['data'] = $this->fread($data_length);
} else {
$picture['data'] = $this->saveAttachment(
str_replace('/', '_', $picture['type']).'_'.$this->ftell(),
$this->ftell(),
$data_length,
$picture['image_mime']);
}
$info['flac']['PICTURE'][] = $picture;
return true;
}
public static function metaBlockTypeLookup($blocktype) {
static $lookup = array(
0 => 'STREAMINFO',
1 => 'PADDING',
2 => 'APPLICATION',
3 => 'SEEKTABLE',
4 => 'VORBIS_COMMENT',
5 => 'CUESHEET',
6 => 'PICTURE',
);
return (isset($lookup[$blocktype]) ? $lookup[$blocktype] : 'reserved');
}
public static function applicationIDLookup($applicationid) {
// http://flac.sourceforge.net/id.html
static $lookup = array(
0x41544348 => 'FlacFile', // "ATCH"
0x42534F4C => 'beSolo', // "BSOL"
0x42554753 => 'Bugs Player', // "BUGS"
0x43756573 => 'GoldWave cue points (specification)', // "Cues"
0x46696361 => 'CUE Splitter', // "Fica"
0x46746F6C => 'flac-tools', // "Ftol"
0x4D4F5442 => 'MOTB MetaCzar', // "MOTB"
0x4D505345 => 'MP3 Stream Editor', // "MPSE"
0x4D754D4C => 'MusicML: Music Metadata Language', // "MuML"
0x52494646 => 'Sound Devices RIFF chunk storage', // "RIFF"
0x5346464C => 'Sound Font FLAC', // "SFFL"
0x534F4E59 => 'Sony Creative Software', // "SONY"
0x5351455A => 'flacsqueeze', // "SQEZ"
0x54745776 => 'TwistedWave', // "TtWv"
0x55495453 => 'UITS Embedding tools', // "UITS"
0x61696666 => 'FLAC AIFF chunk storage', // "aiff"
0x696D6167 => 'flac-image application for storing arbitrary files in APPLICATION metadata blocks', // "imag"
0x7065656D => 'Parseable Embedded Extensible Metadata (specification)', // "peem"
0x71667374 => 'QFLAC Studio', // "qfst"
0x72696666 => 'FLAC RIFF chunk storage', // "riff"
0x74756E65 => 'TagTuner', // "tune"
0x78626174 => 'XBAT', // "xbat"
0x786D6364 => 'xmcd', // "xmcd"
);
return (isset($lookup[$applicationid]) ? $lookup[$applicationid] : 'reserved');
}
public static function pictureTypeLookup($type_id) {
static $lookup = array (
0 => 'Other',
1 => '32x32 pixels \'file icon\' (PNG only)',
2 => 'Other file icon',
3 => 'Cover (front)',
4 => 'Cover (back)',
5 => 'Leaflet page',
6 => 'Media (e.g. label side of CD)',
7 => 'Lead artist/lead performer/soloist',
8 => 'Artist/performer',
9 => 'Conductor',
10 => 'Band/Orchestra',
11 => 'Composer',
12 => 'Lyricist/text writer',
13 => 'Recording Location',
14 => 'During recording',
15 => 'During performance',
16 => 'Movie/video screen capture',
17 => 'A bright coloured fish',
18 => 'Illustration',
19 => 'Band/artist logotype',
20 => 'Publisher/Studio logotype',
);
return (isset($lookup[$type_id]) ? $lookup[$type_id] : 'reserved');
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,756 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
// also https://github.com/JamesHeinrich/getID3 //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.audio.ogg.php //
// module for analyzing Ogg Vorbis, OggFLAC and Speex files //
// dependencies: module.audio.flac.php //
// ///
/////////////////////////////////////////////////////////////////
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.flac.php', __FILE__, true);
class getid3_ogg extends getid3_handler
{
// http://xiph.org/vorbis/doc/Vorbis_I_spec.html
public function Analyze() {
$info = &$this->getid3->info;
$info['fileformat'] = 'ogg';
// Warn about illegal tags - only vorbiscomments are allowed
if (isset($info['id3v2'])) {
$info['warning'][] = 'Illegal ID3v2 tag present.';
}
if (isset($info['id3v1'])) {
$info['warning'][] = 'Illegal ID3v1 tag present.';
}
if (isset($info['ape'])) {
$info['warning'][] = 'Illegal APE tag present.';
}
// Page 1 - Stream Header
$this->fseek($info['avdataoffset']);
$oggpageinfo = $this->ParseOggPageHeader();
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
if ($this->ftell() >= $this->getid3->fread_buffer_size()) {
$info['error'][] = 'Could not find start of Ogg page in the first '.$this->getid3->fread_buffer_size().' bytes (this might not be an Ogg-Vorbis file?)';
unset($info['fileformat']);
unset($info['ogg']);
return false;
}
$filedata = $this->fread($oggpageinfo['page_length']);
$filedataoffset = 0;
if (substr($filedata, 0, 4) == 'fLaC') {
$info['audio']['dataformat'] = 'flac';
$info['audio']['bitrate_mode'] = 'vbr';
$info['audio']['lossless'] = true;
} elseif (substr($filedata, 1, 6) == 'vorbis') {
$this->ParseVorbisPageHeader($filedata, $filedataoffset, $oggpageinfo);
} elseif (substr($filedata, 0, 8) == 'Speex ') {
// http://www.speex.org/manual/node10.html
$info['audio']['dataformat'] = 'speex';
$info['mime_type'] = 'audio/speex';
$info['audio']['bitrate_mode'] = 'abr';
$info['audio']['lossless'] = false;
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['speex_string'] = substr($filedata, $filedataoffset, 8); // hard-coded to 'Speex '
$filedataoffset += 8;
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['speex_version'] = substr($filedata, $filedataoffset, 20);
$filedataoffset += 20;
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['speex_version_id'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['header_size'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['rate'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['mode'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['mode_bitstream_version'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['nb_channels'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['bitrate'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['framesize'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['vbr'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['frames_per_packet'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['extra_headers'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['reserved1'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['reserved2'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$info['speex']['speex_version'] = trim($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['speex_version']);
$info['speex']['sample_rate'] = $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['rate'];
$info['speex']['channels'] = $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['nb_channels'];
$info['speex']['vbr'] = (bool) $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['vbr'];
$info['speex']['band_type'] = $this->SpeexBandModeLookup($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['mode']);
$info['audio']['sample_rate'] = $info['speex']['sample_rate'];
$info['audio']['channels'] = $info['speex']['channels'];
if ($info['speex']['vbr']) {
$info['audio']['bitrate_mode'] = 'vbr';
}
} elseif (substr($filedata, 0, 7) == "\x80".'theora') {
// http://www.theora.org/doc/Theora.pdf (section 6.2)
$info['ogg']['pageheader']['theora']['theora_magic'] = substr($filedata, $filedataoffset, 7); // hard-coded to "\x80.'theora'
$filedataoffset += 7;
$info['ogg']['pageheader']['theora']['version_major'] = getid3_lib::BigEndian2Int(substr($filedata, $filedataoffset, 1));
$filedataoffset += 1;
$info['ogg']['pageheader']['theora']['version_minor'] = getid3_lib::BigEndian2Int(substr($filedata, $filedataoffset, 1));
$filedataoffset += 1;
$info['ogg']['pageheader']['theora']['version_revision'] = getid3_lib::BigEndian2Int(substr($filedata, $filedataoffset, 1));
$filedataoffset += 1;
$info['ogg']['pageheader']['theora']['frame_width_macroblocks'] = getid3_lib::BigEndian2Int(substr($filedata, $filedataoffset, 2));
$filedataoffset += 2;
$info['ogg']['pageheader']['theora']['frame_height_macroblocks'] = getid3_lib::BigEndian2Int(substr($filedata, $filedataoffset, 2));
$filedataoffset += 2;
$info['ogg']['pageheader']['theora']['resolution_x'] = getid3_lib::BigEndian2Int(substr($filedata, $filedataoffset, 3));
$filedataoffset += 3;
$info['ogg']['pageheader']['theora']['resolution_y'] = getid3_lib::BigEndian2Int(substr($filedata, $filedataoffset, 3));
$filedataoffset += 3;
$info['ogg']['pageheader']['theora']['picture_offset_x'] = getid3_lib::BigEndian2Int(substr($filedata, $filedataoffset, 1));
$filedataoffset += 1;
$info['ogg']['pageheader']['theora']['picture_offset_y'] = getid3_lib::BigEndian2Int(substr($filedata, $filedataoffset, 1));
$filedataoffset += 1;
$info['ogg']['pageheader']['theora']['frame_rate_numerator'] = getid3_lib::BigEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$info['ogg']['pageheader']['theora']['frame_rate_denominator'] = getid3_lib::BigEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$info['ogg']['pageheader']['theora']['pixel_aspect_numerator'] = getid3_lib::BigEndian2Int(substr($filedata, $filedataoffset, 3));
$filedataoffset += 3;
$info['ogg']['pageheader']['theora']['pixel_aspect_denominator'] = getid3_lib::BigEndian2Int(substr($filedata, $filedataoffset, 3));
$filedataoffset += 3;
$info['ogg']['pageheader']['theora']['color_space_id'] = getid3_lib::BigEndian2Int(substr($filedata, $filedataoffset, 1));
$filedataoffset += 1;
$info['ogg']['pageheader']['theora']['nominal_bitrate'] = getid3_lib::BigEndian2Int(substr($filedata, $filedataoffset, 3));
$filedataoffset += 3;
$info['ogg']['pageheader']['theora']['flags'] = getid3_lib::BigEndian2Int(substr($filedata, $filedataoffset, 2));
$filedataoffset += 2;
$info['ogg']['pageheader']['theora']['quality'] = ($info['ogg']['pageheader']['theora']['flags'] & 0xFC00) >> 10;
$info['ogg']['pageheader']['theora']['kfg_shift'] = ($info['ogg']['pageheader']['theora']['flags'] & 0x03E0) >> 5;
$info['ogg']['pageheader']['theora']['pixel_format_id'] = ($info['ogg']['pageheader']['theora']['flags'] & 0x0018) >> 3;
$info['ogg']['pageheader']['theora']['reserved'] = ($info['ogg']['pageheader']['theora']['flags'] & 0x0007) >> 0; // should be 0
$info['ogg']['pageheader']['theora']['color_space'] = self::TheoraColorSpace($info['ogg']['pageheader']['theora']['color_space_id']);
$info['ogg']['pageheader']['theora']['pixel_format'] = self::TheoraPixelFormat($info['ogg']['pageheader']['theora']['pixel_format_id']);
$info['video']['dataformat'] = 'theora';
$info['mime_type'] = 'video/ogg';
//$info['audio']['bitrate_mode'] = 'abr';
//$info['audio']['lossless'] = false;
$info['video']['resolution_x'] = $info['ogg']['pageheader']['theora']['resolution_x'];
$info['video']['resolution_y'] = $info['ogg']['pageheader']['theora']['resolution_y'];
if ($info['ogg']['pageheader']['theora']['frame_rate_denominator'] > 0) {
$info['video']['frame_rate'] = (float) $info['ogg']['pageheader']['theora']['frame_rate_numerator'] / $info['ogg']['pageheader']['theora']['frame_rate_denominator'];
}
if ($info['ogg']['pageheader']['theora']['pixel_aspect_denominator'] > 0) {
$info['video']['pixel_aspect_ratio'] = (float) $info['ogg']['pageheader']['theora']['pixel_aspect_numerator'] / $info['ogg']['pageheader']['theora']['pixel_aspect_denominator'];
}
$info['warning'][] = 'Ogg Theora (v3) not fully supported in this version of getID3 ['.$this->getid3->version().'] -- bitrate, playtime and all audio data are currently unavailable';
} elseif (substr($filedata, 0, 8) == "fishead\x00") {
// Ogg Skeleton version 3.0 Format Specification
// http://xiph.org/ogg/doc/skeleton.html
$filedataoffset += 8;
$info['ogg']['skeleton']['fishead']['raw']['version_major'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 2));
$filedataoffset += 2;
$info['ogg']['skeleton']['fishead']['raw']['version_minor'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 2));
$filedataoffset += 2;
$info['ogg']['skeleton']['fishead']['raw']['presentationtime_numerator'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8));
$filedataoffset += 8;
$info['ogg']['skeleton']['fishead']['raw']['presentationtime_denominator'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8));
$filedataoffset += 8;
$info['ogg']['skeleton']['fishead']['raw']['basetime_numerator'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8));
$filedataoffset += 8;
$info['ogg']['skeleton']['fishead']['raw']['basetime_denominator'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8));
$filedataoffset += 8;
$info['ogg']['skeleton']['fishead']['raw']['utc'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 20));
$filedataoffset += 20;
$info['ogg']['skeleton']['fishead']['version'] = $info['ogg']['skeleton']['fishead']['raw']['version_major'].'.'.$info['ogg']['skeleton']['fishead']['raw']['version_minor'];
$info['ogg']['skeleton']['fishead']['presentationtime'] = $info['ogg']['skeleton']['fishead']['raw']['presentationtime_numerator'] / $info['ogg']['skeleton']['fishead']['raw']['presentationtime_denominator'];
$info['ogg']['skeleton']['fishead']['basetime'] = $info['ogg']['skeleton']['fishead']['raw']['basetime_numerator'] / $info['ogg']['skeleton']['fishead']['raw']['basetime_denominator'];
$info['ogg']['skeleton']['fishead']['utc'] = $info['ogg']['skeleton']['fishead']['raw']['utc'];
$counter = 0;
do {
$oggpageinfo = $this->ParseOggPageHeader();
$info['ogg']['pageheader'][$oggpageinfo['page_seqno'].'.'.$counter++] = $oggpageinfo;
$filedata = $this->fread($oggpageinfo['page_length']);
$this->fseek($oggpageinfo['page_end_offset']);
if (substr($filedata, 0, 8) == "fisbone\x00") {
$filedataoffset = 8;
$info['ogg']['skeleton']['fisbone']['raw']['message_header_offset'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$info['ogg']['skeleton']['fisbone']['raw']['serial_number'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$info['ogg']['skeleton']['fisbone']['raw']['number_header_packets'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$info['ogg']['skeleton']['fisbone']['raw']['granulerate_numerator'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8));
$filedataoffset += 8;
$info['ogg']['skeleton']['fisbone']['raw']['granulerate_denominator'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8));
$filedataoffset += 8;
$info['ogg']['skeleton']['fisbone']['raw']['basegranule'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8));
$filedataoffset += 8;
$info['ogg']['skeleton']['fisbone']['raw']['preroll'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$info['ogg']['skeleton']['fisbone']['raw']['granuleshift'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
$filedataoffset += 1;
$info['ogg']['skeleton']['fisbone']['raw']['padding'] = substr($filedata, $filedataoffset, 3);
$filedataoffset += 3;
} elseif (substr($filedata, 1, 6) == 'theora') {
$info['video']['dataformat'] = 'theora1';
$info['error'][] = 'Ogg Theora (v1) not correctly handled in this version of getID3 ['.$this->getid3->version().']';
//break;
} elseif (substr($filedata, 1, 6) == 'vorbis') {
$this->ParseVorbisPageHeader($filedata, $filedataoffset, $oggpageinfo);
} else {
$info['error'][] = 'unexpected';
//break;
}
//} while ($oggpageinfo['page_seqno'] == 0);
} while (($oggpageinfo['page_seqno'] == 0) && (substr($filedata, 0, 8) != "fisbone\x00"));
$this->fseek($oggpageinfo['page_start_offset']);
$info['error'][] = 'Ogg Skeleton not correctly handled in this version of getID3 ['.$this->getid3->version().']';
//return false;
} else {
$info['error'][] = 'Expecting either "Speex " or "vorbis" identifier strings, found "'.substr($filedata, 0, 8).'"';
unset($info['ogg']);
unset($info['mime_type']);
return false;
}
// Page 2 - Comment Header
$oggpageinfo = $this->ParseOggPageHeader();
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
switch ($info['audio']['dataformat']) {
case 'vorbis':
$filedata = $this->fread($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']);
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['packet_type'] = getid3_lib::LittleEndian2Int(substr($filedata, 0, 1));
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['stream_type'] = substr($filedata, 1, 6); // hard-coded to 'vorbis'
$this->ParseVorbisComments();
break;
case 'flac':
$flac = new getid3_flac($this->getid3);
if (!$flac->parseMETAdata()) {
$info['error'][] = 'Failed to parse FLAC headers';
return false;
}
unset($flac);
break;
case 'speex':
$this->fseek($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length'], SEEK_CUR);
$this->ParseVorbisComments();
break;
}
// Last Page - Number of Samples
if (!getid3_lib::intValueSupported($info['avdataend'])) {
$info['warning'][] = 'Unable to parse Ogg end chunk file (PHP does not support file operations beyond '.round(PHP_INT_MAX / 1073741824).'GB)';
} else {
$this->fseek(max($info['avdataend'] - $this->getid3->fread_buffer_size(), 0));
$LastChunkOfOgg = strrev($this->fread($this->getid3->fread_buffer_size()));
if ($LastOggSpostion = strpos($LastChunkOfOgg, 'SggO')) {
$this->fseek($info['avdataend'] - ($LastOggSpostion + strlen('SggO')));
$info['avdataend'] = $this->ftell();
$info['ogg']['pageheader']['eos'] = $this->ParseOggPageHeader();
$info['ogg']['samples'] = $info['ogg']['pageheader']['eos']['pcm_abs_position'];
if ($info['ogg']['samples'] == 0) {
$info['error'][] = 'Corrupt Ogg file: eos.number of samples == zero';
return false;
}
if (!empty($info['audio']['sample_rate'])) {
$info['ogg']['bitrate_average'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / ($info['ogg']['samples'] / $info['audio']['sample_rate']);
}
}
}
if (!empty($info['ogg']['bitrate_average'])) {
$info['audio']['bitrate'] = $info['ogg']['bitrate_average'];
} elseif (!empty($info['ogg']['bitrate_nominal'])) {
$info['audio']['bitrate'] = $info['ogg']['bitrate_nominal'];
} elseif (!empty($info['ogg']['bitrate_min']) && !empty($info['ogg']['bitrate_max'])) {
$info['audio']['bitrate'] = ($info['ogg']['bitrate_min'] + $info['ogg']['bitrate_max']) / 2;
}
if (isset($info['audio']['bitrate']) && !isset($info['playtime_seconds'])) {
if ($info['audio']['bitrate'] == 0) {
$info['error'][] = 'Corrupt Ogg file: bitrate_audio == zero';
return false;
}
$info['playtime_seconds'] = (float) ((($info['avdataend'] - $info['avdataoffset']) * 8) / $info['audio']['bitrate']);
}
if (isset($info['ogg']['vendor'])) {
$info['audio']['encoder'] = preg_replace('/^Encoded with /', '', $info['ogg']['vendor']);
// Vorbis only
if ($info['audio']['dataformat'] == 'vorbis') {
// Vorbis 1.0 starts with Xiph.Org
if (preg_match('/^Xiph.Org/', $info['audio']['encoder'])) {
if ($info['audio']['bitrate_mode'] == 'abr') {
// Set -b 128 on abr files
$info['audio']['encoder_options'] = '-b '.round($info['ogg']['bitrate_nominal'] / 1000);
} elseif (($info['audio']['bitrate_mode'] == 'vbr') && ($info['audio']['channels'] == 2) && ($info['audio']['sample_rate'] >= 44100) && ($info['audio']['sample_rate'] <= 48000)) {
// Set -q N on vbr files
$info['audio']['encoder_options'] = '-q '.$this->get_quality_from_nominal_bitrate($info['ogg']['bitrate_nominal']);
}
}
if (empty($info['audio']['encoder_options']) && !empty($info['ogg']['bitrate_nominal'])) {
$info['audio']['encoder_options'] = 'Nominal bitrate: '.intval(round($info['ogg']['bitrate_nominal'] / 1000)).'kbps';
}
}
}
return true;
}
public function ParseVorbisPageHeader(&$filedata, &$filedataoffset, &$oggpageinfo) {
$info = &$this->getid3->info;
$info['audio']['dataformat'] = 'vorbis';
$info['audio']['lossless'] = false;
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['packet_type'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
$filedataoffset += 1;
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['stream_type'] = substr($filedata, $filedataoffset, 6); // hard-coded to 'vorbis'
$filedataoffset += 6;
$info['ogg']['bitstreamversion'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$info['ogg']['numberofchannels'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
$filedataoffset += 1;
$info['audio']['channels'] = $info['ogg']['numberofchannels'];
$info['ogg']['samplerate'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
if ($info['ogg']['samplerate'] == 0) {
$info['error'][] = 'Corrupt Ogg file: sample rate == zero';
return false;
}
$info['audio']['sample_rate'] = $info['ogg']['samplerate'];
$info['ogg']['samples'] = 0; // filled in later
$info['ogg']['bitrate_average'] = 0; // filled in later
$info['ogg']['bitrate_max'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$info['ogg']['bitrate_nominal'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$info['ogg']['bitrate_min'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$info['ogg']['blocksize_small'] = pow(2, getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)) & 0x0F);
$info['ogg']['blocksize_large'] = pow(2, (getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)) & 0xF0) >> 4);
$info['ogg']['stop_bit'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)); // must be 1, marks end of packet
$info['audio']['bitrate_mode'] = 'vbr'; // overridden if actually abr
if ($info['ogg']['bitrate_max'] == 0xFFFFFFFF) {
unset($info['ogg']['bitrate_max']);
$info['audio']['bitrate_mode'] = 'abr';
}
if ($info['ogg']['bitrate_nominal'] == 0xFFFFFFFF) {
unset($info['ogg']['bitrate_nominal']);
}
if ($info['ogg']['bitrate_min'] == 0xFFFFFFFF) {
unset($info['ogg']['bitrate_min']);
$info['audio']['bitrate_mode'] = 'abr';
}
return true;
}
public function ParseOggPageHeader() {
// http://xiph.org/ogg/vorbis/doc/framing.html
$oggheader['page_start_offset'] = $this->ftell(); // where we started from in the file
$filedata = $this->fread($this->getid3->fread_buffer_size());
$filedataoffset = 0;
while ((substr($filedata, $filedataoffset++, 4) != 'OggS')) {
if (($this->ftell() - $oggheader['page_start_offset']) >= $this->getid3->fread_buffer_size()) {
// should be found before here
return false;
}
if ((($filedataoffset + 28) > strlen($filedata)) || (strlen($filedata) < 28)) {
if ($this->feof() || (($filedata .= $this->fread($this->getid3->fread_buffer_size())) === false)) {
// get some more data, unless eof, in which case fail
return false;
}
}
}
$filedataoffset += strlen('OggS') - 1; // page, delimited by 'OggS'
$oggheader['stream_structver'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
$filedataoffset += 1;
$oggheader['flags_raw'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
$filedataoffset += 1;
$oggheader['flags']['fresh'] = (bool) ($oggheader['flags_raw'] & 0x01); // fresh packet
$oggheader['flags']['bos'] = (bool) ($oggheader['flags_raw'] & 0x02); // first page of logical bitstream (bos)
$oggheader['flags']['eos'] = (bool) ($oggheader['flags_raw'] & 0x04); // last page of logical bitstream (eos)
$oggheader['pcm_abs_position'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8));
$filedataoffset += 8;
$oggheader['stream_serialno'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$oggheader['page_seqno'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$oggheader['page_checksum'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$oggheader['page_segments'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
$filedataoffset += 1;
$oggheader['page_length'] = 0;
for ($i = 0; $i < $oggheader['page_segments']; $i++) {
$oggheader['segment_table'][$i] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
$filedataoffset += 1;
$oggheader['page_length'] += $oggheader['segment_table'][$i];
}
$oggheader['header_end_offset'] = $oggheader['page_start_offset'] + $filedataoffset;
$oggheader['page_end_offset'] = $oggheader['header_end_offset'] + $oggheader['page_length'];
$this->fseek($oggheader['header_end_offset']);
return $oggheader;
}
// http://xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-810005
public function ParseVorbisComments() {
$info = &$this->getid3->info;
$OriginalOffset = $this->ftell();
$commentdataoffset = 0;
$VorbisCommentPage = 1;
switch ($info['audio']['dataformat']) {
case 'vorbis':
case 'speex':
$CommentStartOffset = $info['ogg']['pageheader'][$VorbisCommentPage]['page_start_offset']; // Second Ogg page, after header block
$this->fseek($CommentStartOffset);
$commentdataoffset = 27 + $info['ogg']['pageheader'][$VorbisCommentPage]['page_segments'];
$commentdata = $this->fread(self::OggPageSegmentLength($info['ogg']['pageheader'][$VorbisCommentPage], 1) + $commentdataoffset);
if ($info['audio']['dataformat'] == 'vorbis') {
$commentdataoffset += (strlen('vorbis') + 1);
}
break;
case 'flac':
$CommentStartOffset = $info['flac']['VORBIS_COMMENT']['raw']['offset'] + 4;
$this->fseek($CommentStartOffset);
$commentdata = $this->fread($info['flac']['VORBIS_COMMENT']['raw']['block_length']);
break;
default:
return false;
}
$VendorSize = getid3_lib::LittleEndian2Int(substr($commentdata, $commentdataoffset, 4));
$commentdataoffset += 4;
$info['ogg']['vendor'] = substr($commentdata, $commentdataoffset, $VendorSize);
$commentdataoffset += $VendorSize;
$CommentsCount = getid3_lib::LittleEndian2Int(substr($commentdata, $commentdataoffset, 4));
$commentdataoffset += 4;
$info['avdataoffset'] = $CommentStartOffset + $commentdataoffset;
$basicfields = array('TITLE', 'ARTIST', 'ALBUM', 'TRACKNUMBER', 'GENRE', 'DATE', 'DESCRIPTION', 'COMMENT');
$ThisFileInfo_ogg_comments_raw = &$info['ogg']['comments_raw'];
for ($i = 0; $i < $CommentsCount; $i++) {
$ThisFileInfo_ogg_comments_raw[$i]['dataoffset'] = $CommentStartOffset + $commentdataoffset;
if ($this->ftell() < ($ThisFileInfo_ogg_comments_raw[$i]['dataoffset'] + 4)) {
if ($oggpageinfo = $this->ParseOggPageHeader()) {
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
$VorbisCommentPage++;
// First, save what we haven't read yet
$AsYetUnusedData = substr($commentdata, $commentdataoffset);
// Then take that data off the end
$commentdata = substr($commentdata, 0, $commentdataoffset);
// Add [headerlength] bytes of dummy data for the Ogg Page Header, just to keep absolute offsets correct
$commentdata .= str_repeat("\x00", 27 + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']);
$commentdataoffset += (27 + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']);
// Finally, stick the unused data back on the end
$commentdata .= $AsYetUnusedData;
//$commentdata .= $this->fread($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']);
$commentdata .= $this->fread($this->OggPageSegmentLength($info['ogg']['pageheader'][$VorbisCommentPage], 1));
}
}
$ThisFileInfo_ogg_comments_raw[$i]['size'] = getid3_lib::LittleEndian2Int(substr($commentdata, $commentdataoffset, 4));
// replace avdataoffset with position just after the last vorbiscomment
$info['avdataoffset'] = $ThisFileInfo_ogg_comments_raw[$i]['dataoffset'] + $ThisFileInfo_ogg_comments_raw[$i]['size'] + 4;
$commentdataoffset += 4;
while ((strlen($commentdata) - $commentdataoffset) < $ThisFileInfo_ogg_comments_raw[$i]['size']) {
if (($ThisFileInfo_ogg_comments_raw[$i]['size'] > $info['avdataend']) || ($ThisFileInfo_ogg_comments_raw[$i]['size'] < 0)) {
$info['warning'][] = 'Invalid Ogg comment size (comment #'.$i.', claims to be '.number_format($ThisFileInfo_ogg_comments_raw[$i]['size']).' bytes) - aborting reading comments';
break 2;
}
$VorbisCommentPage++;
$oggpageinfo = $this->ParseOggPageHeader();
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
// First, save what we haven't read yet
$AsYetUnusedData = substr($commentdata, $commentdataoffset);
// Then take that data off the end
$commentdata = substr($commentdata, 0, $commentdataoffset);
// Add [headerlength] bytes of dummy data for the Ogg Page Header, just to keep absolute offsets correct
$commentdata .= str_repeat("\x00", 27 + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']);
$commentdataoffset += (27 + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']);
// Finally, stick the unused data back on the end
$commentdata .= $AsYetUnusedData;
//$commentdata .= $this->fread($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']);
if (!isset($info['ogg']['pageheader'][$VorbisCommentPage])) {
$info['warning'][] = 'undefined Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.$this->ftell();
break;
}
$readlength = self::OggPageSegmentLength($info['ogg']['pageheader'][$VorbisCommentPage], 1);
if ($readlength <= 0) {
$info['warning'][] = 'invalid length Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.$this->ftell();
break;
}
$commentdata .= $this->fread($readlength);
//$filebaseoffset += $oggpageinfo['header_end_offset'] - $oggpageinfo['page_start_offset'];
}
$ThisFileInfo_ogg_comments_raw[$i]['offset'] = $commentdataoffset;
$commentstring = substr($commentdata, $commentdataoffset, $ThisFileInfo_ogg_comments_raw[$i]['size']);
$commentdataoffset += $ThisFileInfo_ogg_comments_raw[$i]['size'];
if (!$commentstring) {
// no comment?
$info['warning'][] = 'Blank Ogg comment ['.$i.']';
} elseif (strstr($commentstring, '=')) {
$commentexploded = explode('=', $commentstring, 2);
$ThisFileInfo_ogg_comments_raw[$i]['key'] = strtoupper($commentexploded[0]);
$ThisFileInfo_ogg_comments_raw[$i]['value'] = (isset($commentexploded[1]) ? $commentexploded[1] : '');
if ($ThisFileInfo_ogg_comments_raw[$i]['key'] == 'METADATA_BLOCK_PICTURE') {
// http://wiki.xiph.org/VorbisComment#METADATA_BLOCK_PICTURE
// The unencoded format is that of the FLAC picture block. The fields are stored in big endian order as in FLAC, picture data is stored according to the relevant standard.
// http://flac.sourceforge.net/format.html#metadata_block_picture
$flac = new getid3_flac($this->getid3);
$flac->setStringMode(base64_decode($ThisFileInfo_ogg_comments_raw[$i]['value']));
$flac->parsePICTURE();
$info['ogg']['comments']['picture'][] = $flac->getid3->info['flac']['PICTURE'][0];
unset($flac);
} elseif ($ThisFileInfo_ogg_comments_raw[$i]['key'] == 'COVERART') {
$data = base64_decode($ThisFileInfo_ogg_comments_raw[$i]['value']);
$this->notice('Found deprecated COVERART tag, it should be replaced in honor of METADATA_BLOCK_PICTURE structure');
/** @todo use 'coverartmime' where available */
$imageinfo = getid3_lib::GetDataImageSize($data);
if ($imageinfo === false || !isset($imageinfo['mime'])) {
$this->warning('COVERART vorbiscomment tag contains invalid image');
continue;
}
$ogg = new self($this->getid3);
$ogg->setStringMode($data);
$info['ogg']['comments']['picture'][] = array(
'image_mime' => $imageinfo['mime'],
'data' => $ogg->saveAttachment('coverart', 0, strlen($data), $imageinfo['mime']),
);
unset($ogg);
} else {
$info['ogg']['comments'][strtolower($ThisFileInfo_ogg_comments_raw[$i]['key'])][] = $ThisFileInfo_ogg_comments_raw[$i]['value'];
}
} else {
$info['warning'][] = '[known problem with CDex >= v1.40, < v1.50b7] Invalid Ogg comment name/value pair ['.$i.']: '.$commentstring;
}
unset($ThisFileInfo_ogg_comments_raw[$i]);
}
unset($ThisFileInfo_ogg_comments_raw);
// Replay Gain Adjustment
// http://privatewww.essex.ac.uk/~djmrob/replaygain/
if (isset($info['ogg']['comments']) && is_array($info['ogg']['comments'])) {
foreach ($info['ogg']['comments'] as $index => $commentvalue) {
switch ($index) {
case 'rg_audiophile':
case 'replaygain_album_gain':
$info['replay_gain']['album']['adjustment'] = (double) $commentvalue[0];
unset($info['ogg']['comments'][$index]);
break;
case 'rg_radio':
case 'replaygain_track_gain':
$info['replay_gain']['track']['adjustment'] = (double) $commentvalue[0];
unset($info['ogg']['comments'][$index]);
break;
case 'replaygain_album_peak':
$info['replay_gain']['album']['peak'] = (double) $commentvalue[0];
unset($info['ogg']['comments'][$index]);
break;
case 'rg_peak':
case 'replaygain_track_peak':
$info['replay_gain']['track']['peak'] = (double) $commentvalue[0];
unset($info['ogg']['comments'][$index]);
break;
case 'replaygain_reference_loudness':
$info['replay_gain']['reference_volume'] = (double) $commentvalue[0];
unset($info['ogg']['comments'][$index]);
break;
default:
// do nothing
break;
}
}
}
$this->fseek($OriginalOffset);
return true;
}
public static function SpeexBandModeLookup($mode) {
static $SpeexBandModeLookup = array();
if (empty($SpeexBandModeLookup)) {
$SpeexBandModeLookup[0] = 'narrow';
$SpeexBandModeLookup[1] = 'wide';
$SpeexBandModeLookup[2] = 'ultra-wide';
}
return (isset($SpeexBandModeLookup[$mode]) ? $SpeexBandModeLookup[$mode] : null);
}
public static function OggPageSegmentLength($OggInfoArray, $SegmentNumber=1) {
for ($i = 0; $i < $SegmentNumber; $i++) {
$segmentlength = 0;
foreach ($OggInfoArray['segment_table'] as $key => $value) {
$segmentlength += $value;
if ($value < 255) {
break;
}
}
}
return $segmentlength;
}
public static function get_quality_from_nominal_bitrate($nominal_bitrate) {
// decrease precision
$nominal_bitrate = $nominal_bitrate / 1000;
if ($nominal_bitrate < 128) {
// q-1 to q4
$qval = ($nominal_bitrate - 64) / 16;
} elseif ($nominal_bitrate < 256) {
// q4 to q8
$qval = $nominal_bitrate / 32;
} elseif ($nominal_bitrate < 320) {
// q8 to q9
$qval = ($nominal_bitrate + 256) / 64;
} else {
// q9 to q10
$qval = ($nominal_bitrate + 1300) / 180;
}
//return $qval; // 5.031324
//return intval($qval); // 5
return round($qval, 1); // 5 or 4.9
}
public static function TheoraColorSpace($colorspace_id) {
// http://www.theora.org/doc/Theora.pdf (table 6.3)
static $TheoraColorSpaceLookup = array();
if (empty($TheoraColorSpaceLookup)) {
$TheoraColorSpaceLookup[0] = 'Undefined';
$TheoraColorSpaceLookup[1] = 'Rec. 470M';
$TheoraColorSpaceLookup[2] = 'Rec. 470BG';
$TheoraColorSpaceLookup[3] = 'Reserved';
}
return (isset($TheoraColorSpaceLookup[$colorspace_id]) ? $TheoraColorSpaceLookup[$colorspace_id] : null);
}
public static function TheoraPixelFormat($pixelformat_id) {
// http://www.theora.org/doc/Theora.pdf (table 6.4)
static $TheoraPixelFormatLookup = array();
if (empty($TheoraPixelFormatLookup)) {
$TheoraPixelFormatLookup[0] = '4:2:0';
$TheoraPixelFormatLookup[1] = 'Reserved';
$TheoraPixelFormatLookup[2] = '4:2:2';
$TheoraPixelFormatLookup[3] = '4:4:4';
}
return (isset($TheoraPixelFormatLookup[$pixelformat_id]) ? $TheoraPixelFormatLookup[$pixelformat_id] : null);
}
}

View File

@ -1,338 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
// also https://github.com/JamesHeinrich/getID3 //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.graphic.jpg.php //
// module for analyzing JPEG Image files //
// dependencies: PHP compiled with --enable-exif (optional) //
// module.tag.xmp.php (optional) //
// ///
/////////////////////////////////////////////////////////////////
class getid3_jpg extends getid3_handler
{
public function Analyze() {
$info = &$this->getid3->info;
$info['fileformat'] = 'jpg';
$info['video']['dataformat'] = 'jpg';
$info['video']['lossless'] = false;
$info['video']['bits_per_sample'] = 24;
$info['video']['pixel_aspect_ratio'] = (float) 1;
$this->fseek($info['avdataoffset']);
$imageinfo = array();
//list($width, $height, $type) = getid3_lib::GetDataImageSize($this->fread($info['filesize']), $imageinfo);
list($width, $height, $type) = getimagesize($info['filenamepath'], $imageinfo); // http://www.getid3.org/phpBB3/viewtopic.php?t=1474
if (isset($imageinfo['APP13'])) {
// http://php.net/iptcparse
// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/IPTC.html
$iptc_parsed = iptcparse($imageinfo['APP13']);
if (is_array($iptc_parsed)) {
foreach ($iptc_parsed as $iptc_key_raw => $iptc_values) {
list($iptc_record, $iptc_tagkey) = explode('#', $iptc_key_raw);
$iptc_tagkey = intval(ltrim($iptc_tagkey, '0'));
foreach ($iptc_values as $key => $value) {
$IPTCrecordName = $this->IPTCrecordName($iptc_record);
$IPTCrecordTagName = $this->IPTCrecordTagName($iptc_record, $iptc_tagkey);
if (isset($info['iptc']['comments'][$IPTCrecordName][$IPTCrecordTagName])) {
$info['iptc']['comments'][$IPTCrecordName][$IPTCrecordTagName][] = $value;
} else {
$info['iptc']['comments'][$IPTCrecordName][$IPTCrecordTagName] = array($value);
}
}
}
}
}
$returnOK = false;
switch ($type) {
case IMG_JPG:
$info['video']['resolution_x'] = $width;
$info['video']['resolution_y'] = $height;
if (isset($imageinfo['APP1'])) {
if (function_exists('exif_read_data')) {
if (substr($imageinfo['APP1'], 0, 4) == 'Exif') {
//$info['warning'][] = 'known issue: https://bugs.php.net/bug.php?id=62523';
//return false;
$info['jpg']['exif'] = exif_read_data($info['filenamepath'], null, true, false);
} else {
$info['warning'][] = 'exif_read_data() cannot parse non-EXIF data in APP1 (expected "Exif", found "'.substr($imageinfo['APP1'], 0, 4).'")';
}
} else {
$info['warning'][] = 'EXIF parsing only available when '.(GETID3_OS_ISWINDOWS ? 'php_exif.dll enabled' : 'compiled with --enable-exif');
}
}
$returnOK = true;
break;
default:
break;
}
$cast_as_appropriate_keys = array('EXIF', 'IFD0', 'THUMBNAIL');
foreach ($cast_as_appropriate_keys as $exif_key) {
if (isset($info['jpg']['exif'][$exif_key])) {
foreach ($info['jpg']['exif'][$exif_key] as $key => $value) {
$info['jpg']['exif'][$exif_key][$key] = $this->CastAsAppropriate($value);
}
}
}
if (isset($info['jpg']['exif']['GPS'])) {
if (isset($info['jpg']['exif']['GPS']['GPSVersion'])) {
for ($i = 0; $i < 4; $i++) {
$version_subparts[$i] = ord(substr($info['jpg']['exif']['GPS']['GPSVersion'], $i, 1));
}
$info['jpg']['exif']['GPS']['computed']['version'] = 'v'.implode('.', $version_subparts);
}
if (isset($info['jpg']['exif']['GPS']['GPSDateStamp'])) {
$explodedGPSDateStamp = explode(':', $info['jpg']['exif']['GPS']['GPSDateStamp']);
$computed_time[5] = (isset($explodedGPSDateStamp[0]) ? $explodedGPSDateStamp[0] : '');
$computed_time[3] = (isset($explodedGPSDateStamp[1]) ? $explodedGPSDateStamp[1] : '');
$computed_time[4] = (isset($explodedGPSDateStamp[2]) ? $explodedGPSDateStamp[2] : '');
$computed_time = array(0=>0, 1=>0, 2=>0, 3=>0, 4=>0, 5=>0);
if (isset($info['jpg']['exif']['GPS']['GPSTimeStamp']) && is_array($info['jpg']['exif']['GPS']['GPSTimeStamp'])) {
foreach ($info['jpg']['exif']['GPS']['GPSTimeStamp'] as $key => $value) {
$computed_time[$key] = getid3_lib::DecimalizeFraction($value);
}
}
$info['jpg']['exif']['GPS']['computed']['timestamp'] = gmmktime($computed_time[0], $computed_time[1], $computed_time[2], $computed_time[3], $computed_time[4], $computed_time[5]);
}
if (isset($info['jpg']['exif']['GPS']['GPSLatitude']) && is_array($info['jpg']['exif']['GPS']['GPSLatitude'])) {
$direction_multiplier = ((isset($info['jpg']['exif']['GPS']['GPSLatitudeRef']) && ($info['jpg']['exif']['GPS']['GPSLatitudeRef'] == 'S')) ? -1 : 1);
foreach ($info['jpg']['exif']['GPS']['GPSLatitude'] as $key => $value) {
$computed_latitude[$key] = getid3_lib::DecimalizeFraction($value);
}
$info['jpg']['exif']['GPS']['computed']['latitude'] = $direction_multiplier * ($computed_latitude[0] + ($computed_latitude[1] / 60) + ($computed_latitude[2] / 3600));
}
if (isset($info['jpg']['exif']['GPS']['GPSLongitude']) && is_array($info['jpg']['exif']['GPS']['GPSLongitude'])) {
$direction_multiplier = ((isset($info['jpg']['exif']['GPS']['GPSLongitudeRef']) && ($info['jpg']['exif']['GPS']['GPSLongitudeRef'] == 'W')) ? -1 : 1);
foreach ($info['jpg']['exif']['GPS']['GPSLongitude'] as $key => $value) {
$computed_longitude[$key] = getid3_lib::DecimalizeFraction($value);
}
$info['jpg']['exif']['GPS']['computed']['longitude'] = $direction_multiplier * ($computed_longitude[0] + ($computed_longitude[1] / 60) + ($computed_longitude[2] / 3600));
}
if (isset($info['jpg']['exif']['GPS']['GPSAltitudeRef'])) {
$info['jpg']['exif']['GPS']['GPSAltitudeRef'] = ord($info['jpg']['exif']['GPS']['GPSAltitudeRef']); // 0 = above sea level; 1 = below sea level
}
if (isset($info['jpg']['exif']['GPS']['GPSAltitude'])) {
$direction_multiplier = (!empty($info['jpg']['exif']['GPS']['GPSAltitudeRef']) ? -1 : 1); // 0 = above sea level; 1 = below sea level
$info['jpg']['exif']['GPS']['computed']['altitude'] = $direction_multiplier * getid3_lib::DecimalizeFraction($info['jpg']['exif']['GPS']['GPSAltitude']);
}
}
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.xmp.php', __FILE__, true);
if (isset($info['filenamepath'])) {
$image_xmp = new Image_XMP($info['filenamepath']);
$xmp_raw = $image_xmp->getAllTags();
foreach ($xmp_raw as $key => $value) {
if (strpos($key, ':')) {
list($subsection, $tagname) = explode(':', $key);
$info['xmp'][$subsection][$tagname] = $this->CastAsAppropriate($value);
} else {
$info['warning'][] = 'XMP: expecting "<subsection>:<tagname>", found "'.$key.'"';
}
}
}
if (!$returnOK) {
unset($info['fileformat']);
return false;
}
return true;
}
public function CastAsAppropriate($value) {
if (is_array($value)) {
return $value;
} elseif (preg_match('#^[0-9]+/[0-9]+$#', $value)) {
return getid3_lib::DecimalizeFraction($value);
} elseif (preg_match('#^[0-9]+$#', $value)) {
return getid3_lib::CastAsInt($value);
} elseif (preg_match('#^[0-9\.]+$#', $value)) {
return (float) $value;
}
return $value;
}
public function IPTCrecordName($iptc_record) {
// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/IPTC.html
static $IPTCrecordName = array();
if (empty($IPTCrecordName)) {
$IPTCrecordName = array(
1 => 'IPTCEnvelope',
2 => 'IPTCApplication',
3 => 'IPTCNewsPhoto',
7 => 'IPTCPreObjectData',
8 => 'IPTCObjectData',
9 => 'IPTCPostObjectData',
);
}
return (isset($IPTCrecordName[$iptc_record]) ? $IPTCrecordName[$iptc_record] : '');
}
public function IPTCrecordTagName($iptc_record, $iptc_tagkey) {
// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/IPTC.html
static $IPTCrecordTagName = array();
if (empty($IPTCrecordTagName)) {
$IPTCrecordTagName = array(
1 => array( // IPTC EnvelopeRecord Tags
0 => 'EnvelopeRecordVersion',
5 => 'Destination',
20 => 'FileFormat',
22 => 'FileVersion',
30 => 'ServiceIdentifier',
40 => 'EnvelopeNumber',
50 => 'ProductID',
60 => 'EnvelopePriority',
70 => 'DateSent',
80 => 'TimeSent',
90 => 'CodedCharacterSet',
100 => 'UniqueObjectName',
120 => 'ARMIdentifier',
122 => 'ARMVersion',
),
2 => array( // IPTC ApplicationRecord Tags
0 => 'ApplicationRecordVersion',
3 => 'ObjectTypeReference',
4 => 'ObjectAttributeReference',
5 => 'ObjectName',
7 => 'EditStatus',
8 => 'EditorialUpdate',
10 => 'Urgency',
12 => 'SubjectReference',
15 => 'Category',
20 => 'SupplementalCategories',
22 => 'FixtureIdentifier',
25 => 'Keywords',
26 => 'ContentLocationCode',
27 => 'ContentLocationName',
30 => 'ReleaseDate',
35 => 'ReleaseTime',
37 => 'ExpirationDate',
38 => 'ExpirationTime',
40 => 'SpecialInstructions',
42 => 'ActionAdvised',
45 => 'ReferenceService',
47 => 'ReferenceDate',
50 => 'ReferenceNumber',
55 => 'DateCreated',
60 => 'TimeCreated',
62 => 'DigitalCreationDate',
63 => 'DigitalCreationTime',
65 => 'OriginatingProgram',
70 => 'ProgramVersion',
75 => 'ObjectCycle',
80 => 'By-line',
85 => 'By-lineTitle',
90 => 'City',
92 => 'Sub-location',
95 => 'Province-State',
100 => 'Country-PrimaryLocationCode',
101 => 'Country-PrimaryLocationName',
103 => 'OriginalTransmissionReference',
105 => 'Headline',
110 => 'Credit',
115 => 'Source',
116 => 'CopyrightNotice',
118 => 'Contact',
120 => 'Caption-Abstract',
121 => 'LocalCaption',
122 => 'Writer-Editor',
125 => 'RasterizedCaption',
130 => 'ImageType',
131 => 'ImageOrientation',
135 => 'LanguageIdentifier',
150 => 'AudioType',
151 => 'AudioSamplingRate',
152 => 'AudioSamplingResolution',
153 => 'AudioDuration',
154 => 'AudioOutcue',
184 => 'JobID',
185 => 'MasterDocumentID',
186 => 'ShortDocumentID',
187 => 'UniqueDocumentID',
188 => 'OwnerID',
200 => 'ObjectPreviewFileFormat',
201 => 'ObjectPreviewFileVersion',
202 => 'ObjectPreviewData',
221 => 'Prefs',
225 => 'ClassifyState',
228 => 'SimilarityIndex',
230 => 'DocumentNotes',
231 => 'DocumentHistory',
232 => 'ExifCameraInfo',
),
3 => array( // IPTC NewsPhoto Tags
0 => 'NewsPhotoVersion',
10 => 'IPTCPictureNumber',
20 => 'IPTCImageWidth',
30 => 'IPTCImageHeight',
40 => 'IPTCPixelWidth',
50 => 'IPTCPixelHeight',
55 => 'SupplementalType',
60 => 'ColorRepresentation',
64 => 'InterchangeColorSpace',
65 => 'ColorSequence',
66 => 'ICC_Profile',
70 => 'ColorCalibrationMatrix',
80 => 'LookupTable',
84 => 'NumIndexEntries',
85 => 'ColorPalette',
86 => 'IPTCBitsPerSample',
90 => 'SampleStructure',
100 => 'ScanningDirection',
102 => 'IPTCImageRotation',
110 => 'DataCompressionMethod',
120 => 'QuantizationMethod',
125 => 'EndPoints',
130 => 'ExcursionTolerance',
135 => 'BitsPerComponent',
140 => 'MaximumDensityRange',
145 => 'GammaCompensatedValue',
),
7 => array( // IPTC PreObjectData Tags
10 => 'SizeMode',
20 => 'MaxSubfileSize',
90 => 'ObjectSizeAnnounced',
95 => 'MaximumObjectSize',
),
8 => array( // IPTC ObjectData Tags
10 => 'SubFile',
),
9 => array( // IPTC PostObjectData Tags
10 => 'ConfirmedObjectSize',
),
);
}
return (isset($IPTCrecordTagName[$iptc_record][$iptc_tagkey]) ? $IPTCrecordTagName[$iptc_record][$iptc_tagkey] : $iptc_tagkey);
}
}

View File

@ -1,31 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
// also https://github.com/JamesHeinrich/getID3 //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.misc.pdf.php //
// module for analyzing PDF files //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
class getid3_pdf extends getid3_handler
{
public function Analyze() {
$info = &$this->getid3->info;
$info['fileformat'] = 'pdf';
$info['error'][] = 'PDF parsing not enabled in this version of getID3() ['.$this->getid3->version().']';
return false;
}
}

View File

@ -1,371 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
// also https://github.com/JamesHeinrich/getID3 //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.tag.apetag.php //
// module for analyzing APE tags //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
class getid3_apetag extends getid3_handler
{
public $inline_attachments = true; // true: return full data for all attachments; false: return no data for all attachments; integer: return data for attachments <= than this; string: save as file to this directory
public $overrideendoffset = 0;
public function Analyze() {
$info = &$this->getid3->info;
if (!getid3_lib::intValueSupported($info['filesize'])) {
$info['warning'][] = 'Unable to check for APEtags because file is larger than '.round(PHP_INT_MAX / 1073741824).'GB';
return false;
}
$id3v1tagsize = 128;
$apetagheadersize = 32;
$lyrics3tagsize = 10;
if ($this->overrideendoffset == 0) {
$this->fseek(0 - $id3v1tagsize - $apetagheadersize - $lyrics3tagsize, SEEK_END);
$APEfooterID3v1 = $this->fread($id3v1tagsize + $apetagheadersize + $lyrics3tagsize);
//if (preg_match('/APETAGEX.{24}TAG.{125}$/i', $APEfooterID3v1)) {
if (substr($APEfooterID3v1, strlen($APEfooterID3v1) - $id3v1tagsize - $apetagheadersize, 8) == 'APETAGEX') {
// APE tag found before ID3v1
$info['ape']['tag_offset_end'] = $info['filesize'] - $id3v1tagsize;
//} elseif (preg_match('/APETAGEX.{24}$/i', $APEfooterID3v1)) {
} elseif (substr($APEfooterID3v1, strlen($APEfooterID3v1) - $apetagheadersize, 8) == 'APETAGEX') {
// APE tag found, no ID3v1
$info['ape']['tag_offset_end'] = $info['filesize'];
}
} else {
$this->fseek($this->overrideendoffset - $apetagheadersize);
if ($this->fread(8) == 'APETAGEX') {
$info['ape']['tag_offset_end'] = $this->overrideendoffset;
}
}
if (!isset($info['ape']['tag_offset_end'])) {
// APE tag not found
unset($info['ape']);
return false;
}
// shortcut
$thisfile_ape = &$info['ape'];
$this->fseek($thisfile_ape['tag_offset_end'] - $apetagheadersize);
$APEfooterData = $this->fread(32);
if (!($thisfile_ape['footer'] = $this->parseAPEheaderFooter($APEfooterData))) {
$info['error'][] = 'Error parsing APE footer at offset '.$thisfile_ape['tag_offset_end'];
return false;
}
if (isset($thisfile_ape['footer']['flags']['header']) && $thisfile_ape['footer']['flags']['header']) {
$this->fseek($thisfile_ape['tag_offset_end'] - $thisfile_ape['footer']['raw']['tagsize'] - $apetagheadersize);
$thisfile_ape['tag_offset_start'] = $this->ftell();
$APEtagData = $this->fread($thisfile_ape['footer']['raw']['tagsize'] + $apetagheadersize);
} else {
$thisfile_ape['tag_offset_start'] = $thisfile_ape['tag_offset_end'] - $thisfile_ape['footer']['raw']['tagsize'];
$this->fseek($thisfile_ape['tag_offset_start']);
$APEtagData = $this->fread($thisfile_ape['footer']['raw']['tagsize']);
}
$info['avdataend'] = $thisfile_ape['tag_offset_start'];
if (isset($info['id3v1']['tag_offset_start']) && ($info['id3v1']['tag_offset_start'] < $thisfile_ape['tag_offset_end'])) {
$info['warning'][] = 'ID3v1 tag information ignored since it appears to be a false synch in APEtag data';
unset($info['id3v1']);
foreach ($info['warning'] as $key => $value) {
if ($value == 'Some ID3v1 fields do not use NULL characters for padding') {
unset($info['warning'][$key]);
sort($info['warning']);
break;
}
}
}
$offset = 0;
if (isset($thisfile_ape['footer']['flags']['header']) && $thisfile_ape['footer']['flags']['header']) {
if ($thisfile_ape['header'] = $this->parseAPEheaderFooter(substr($APEtagData, 0, $apetagheadersize))) {
$offset += $apetagheadersize;
} else {
$info['error'][] = 'Error parsing APE header at offset '.$thisfile_ape['tag_offset_start'];
return false;
}
}
// shortcut
$info['replay_gain'] = array();
$thisfile_replaygain = &$info['replay_gain'];
for ($i = 0; $i < $thisfile_ape['footer']['raw']['tag_items']; $i++) {
$value_size = getid3_lib::LittleEndian2Int(substr($APEtagData, $offset, 4));
$offset += 4;
$item_flags = getid3_lib::LittleEndian2Int(substr($APEtagData, $offset, 4));
$offset += 4;
if (strstr(substr($APEtagData, $offset), "\x00") === false) {
$info['error'][] = 'Cannot find null-byte (0x00) seperator between ItemKey #'.$i.' and value. ItemKey starts '.$offset.' bytes into the APE tag, at file offset '.($thisfile_ape['tag_offset_start'] + $offset);
return false;
}
$ItemKeyLength = strpos($APEtagData, "\x00", $offset) - $offset;
$item_key = strtolower(substr($APEtagData, $offset, $ItemKeyLength));
// shortcut
$thisfile_ape['items'][$item_key] = array();
$thisfile_ape_items_current = &$thisfile_ape['items'][$item_key];
$thisfile_ape_items_current['offset'] = $thisfile_ape['tag_offset_start'] + $offset;
$offset += ($ItemKeyLength + 1); // skip 0x00 terminator
$thisfile_ape_items_current['data'] = substr($APEtagData, $offset, $value_size);
$offset += $value_size;
$thisfile_ape_items_current['flags'] = $this->parseAPEtagFlags($item_flags);
switch ($thisfile_ape_items_current['flags']['item_contents_raw']) {
case 0: // UTF-8
case 3: // Locator (URL, filename, etc), UTF-8 encoded
$thisfile_ape_items_current['data'] = explode("\x00", trim($thisfile_ape_items_current['data']));
break;
default: // binary data
break;
}
switch (strtolower($item_key)) {
case 'replaygain_track_gain':
$thisfile_replaygain['track']['adjustment'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero!
$thisfile_replaygain['track']['originator'] = 'unspecified';
break;
case 'replaygain_track_peak':
$thisfile_replaygain['track']['peak'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero!
$thisfile_replaygain['track']['originator'] = 'unspecified';
if ($thisfile_replaygain['track']['peak'] <= 0) {
$info['warning'][] = 'ReplayGain Track peak from APEtag appears invalid: '.$thisfile_replaygain['track']['peak'].' (original value = "'.$thisfile_ape_items_current['data'][0].'")';
}
break;
case 'replaygain_album_gain':
$thisfile_replaygain['album']['adjustment'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero!
$thisfile_replaygain['album']['originator'] = 'unspecified';
break;
case 'replaygain_album_peak':
$thisfile_replaygain['album']['peak'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero!
$thisfile_replaygain['album']['originator'] = 'unspecified';
if ($thisfile_replaygain['album']['peak'] <= 0) {
$info['warning'][] = 'ReplayGain Album peak from APEtag appears invalid: '.$thisfile_replaygain['album']['peak'].' (original value = "'.$thisfile_ape_items_current['data'][0].'")';
}
break;
case 'mp3gain_undo':
list($mp3gain_undo_left, $mp3gain_undo_right, $mp3gain_undo_wrap) = explode(',', $thisfile_ape_items_current['data'][0]);
$thisfile_replaygain['mp3gain']['undo_left'] = intval($mp3gain_undo_left);
$thisfile_replaygain['mp3gain']['undo_right'] = intval($mp3gain_undo_right);
$thisfile_replaygain['mp3gain']['undo_wrap'] = (($mp3gain_undo_wrap == 'Y') ? true : false);
break;
case 'mp3gain_minmax':
list($mp3gain_globalgain_min, $mp3gain_globalgain_max) = explode(',', $thisfile_ape_items_current['data'][0]);
$thisfile_replaygain['mp3gain']['globalgain_track_min'] = intval($mp3gain_globalgain_min);
$thisfile_replaygain['mp3gain']['globalgain_track_max'] = intval($mp3gain_globalgain_max);
break;
case 'mp3gain_album_minmax':
list($mp3gain_globalgain_album_min, $mp3gain_globalgain_album_max) = explode(',', $thisfile_ape_items_current['data'][0]);
$thisfile_replaygain['mp3gain']['globalgain_album_min'] = intval($mp3gain_globalgain_album_min);
$thisfile_replaygain['mp3gain']['globalgain_album_max'] = intval($mp3gain_globalgain_album_max);
break;
case 'tracknumber':
if (is_array($thisfile_ape_items_current['data'])) {
foreach ($thisfile_ape_items_current['data'] as $comment) {
$thisfile_ape['comments']['track'][] = $comment;
}
}
break;
case 'cover art (artist)':
case 'cover art (back)':
case 'cover art (band logo)':
case 'cover art (band)':
case 'cover art (colored fish)':
case 'cover art (composer)':
case 'cover art (conductor)':
case 'cover art (front)':
case 'cover art (icon)':
case 'cover art (illustration)':
case 'cover art (lead)':
case 'cover art (leaflet)':
case 'cover art (lyricist)':
case 'cover art (media)':
case 'cover art (movie scene)':
case 'cover art (other icon)':
case 'cover art (other)':
case 'cover art (performance)':
case 'cover art (publisher logo)':
case 'cover art (recording)':
case 'cover art (studio)':
// list of possible cover arts from http://taglib-sharp.sourcearchive.com/documentation/2.0.3.0-2/Ape_2Tag_8cs-source.html
list($thisfile_ape_items_current['filename'], $thisfile_ape_items_current['data']) = explode("\x00", $thisfile_ape_items_current['data'], 2);
$thisfile_ape_items_current['data_offset'] = $thisfile_ape_items_current['offset'] + strlen($thisfile_ape_items_current['filename']."\x00");
$thisfile_ape_items_current['data_length'] = strlen($thisfile_ape_items_current['data']);
$thisfile_ape_items_current['image_mime'] = '';
$imageinfo = array();
$imagechunkcheck = getid3_lib::GetDataImageSize($thisfile_ape_items_current['data'], $imageinfo);
$thisfile_ape_items_current['image_mime'] = image_type_to_mime_type($imagechunkcheck[2]);
do {
if ($this->inline_attachments === false) {
// skip entirely
unset($thisfile_ape_items_current['data']);
break;
}
if ($this->inline_attachments === true) {
// great
} elseif (is_int($this->inline_attachments)) {
if ($this->inline_attachments < $thisfile_ape_items_current['data_length']) {
// too big, skip
$info['warning'][] = 'attachment at '.$thisfile_ape_items_current['offset'].' is too large to process inline ('.number_format($thisfile_ape_items_current['data_length']).' bytes)';
unset($thisfile_ape_items_current['data']);
break;
}
} elseif (is_string($this->inline_attachments)) {
$this->inline_attachments = rtrim(str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $this->inline_attachments), DIRECTORY_SEPARATOR);
if (!is_dir($this->inline_attachments) || !is_writable($this->inline_attachments)) {
// cannot write, skip
$info['warning'][] = 'attachment at '.$thisfile_ape_items_current['offset'].' cannot be saved to "'.$this->inline_attachments.'" (not writable)';
unset($thisfile_ape_items_current['data']);
break;
}
}
// if we get this far, must be OK
if (is_string($this->inline_attachments)) {
$destination_filename = $this->inline_attachments.DIRECTORY_SEPARATOR.md5($info['filenamepath']).'_'.$thisfile_ape_items_current['data_offset'];
if (!file_exists($destination_filename) || is_writable($destination_filename)) {
file_put_contents($destination_filename, $thisfile_ape_items_current['data']);
} else {
$info['warning'][] = 'attachment at '.$thisfile_ape_items_current['offset'].' cannot be saved to "'.$destination_filename.'" (not writable)';
}
$thisfile_ape_items_current['data_filename'] = $destination_filename;
unset($thisfile_ape_items_current['data']);
} else {
if (!isset($info['ape']['comments']['picture'])) {
$info['ape']['comments']['picture'] = array();
}
$info['ape']['comments']['picture'][] = array('data'=>$thisfile_ape_items_current['data'], 'image_mime'=>$thisfile_ape_items_current['image_mime']);
}
} while (false);
break;
default:
if (is_array($thisfile_ape_items_current['data'])) {
foreach ($thisfile_ape_items_current['data'] as $comment) {
$thisfile_ape['comments'][strtolower($item_key)][] = $comment;
}
}
break;
}
}
if (empty($thisfile_replaygain)) {
unset($info['replay_gain']);
}
return true;
}
public function parseAPEheaderFooter($APEheaderFooterData) {
// http://www.uni-jena.de/~pfk/mpp/sv8/apeheader.html
// shortcut
$headerfooterinfo['raw'] = array();
$headerfooterinfo_raw = &$headerfooterinfo['raw'];
$headerfooterinfo_raw['footer_tag'] = substr($APEheaderFooterData, 0, 8);
if ($headerfooterinfo_raw['footer_tag'] != 'APETAGEX') {
return false;
}
$headerfooterinfo_raw['version'] = getid3_lib::LittleEndian2Int(substr($APEheaderFooterData, 8, 4));
$headerfooterinfo_raw['tagsize'] = getid3_lib::LittleEndian2Int(substr($APEheaderFooterData, 12, 4));
$headerfooterinfo_raw['tag_items'] = getid3_lib::LittleEndian2Int(substr($APEheaderFooterData, 16, 4));
$headerfooterinfo_raw['global_flags'] = getid3_lib::LittleEndian2Int(substr($APEheaderFooterData, 20, 4));
$headerfooterinfo_raw['reserved'] = substr($APEheaderFooterData, 24, 8);
$headerfooterinfo['tag_version'] = $headerfooterinfo_raw['version'] / 1000;
if ($headerfooterinfo['tag_version'] >= 2) {
$headerfooterinfo['flags'] = $this->parseAPEtagFlags($headerfooterinfo_raw['global_flags']);
}
return $headerfooterinfo;
}
public function parseAPEtagFlags($rawflagint) {
// "Note: APE Tags 1.0 do not use any of the APE Tag flags.
// All are set to zero on creation and ignored on reading."
// http://www.uni-jena.de/~pfk/mpp/sv8/apetagflags.html
$flags['header'] = (bool) ($rawflagint & 0x80000000);
$flags['footer'] = (bool) ($rawflagint & 0x40000000);
$flags['this_is_header'] = (bool) ($rawflagint & 0x20000000);
$flags['item_contents_raw'] = ($rawflagint & 0x00000006) >> 1;
$flags['read_only'] = (bool) ($rawflagint & 0x00000001);
$flags['item_contents'] = $this->APEcontentTypeFlagLookup($flags['item_contents_raw']);
return $flags;
}
public function APEcontentTypeFlagLookup($contenttypeid) {
static $APEcontentTypeFlagLookup = array(
0 => 'utf-8',
1 => 'binary',
2 => 'external',
3 => 'reserved'
);
return (isset($APEcontentTypeFlagLookup[$contenttypeid]) ? $APEcontentTypeFlagLookup[$contenttypeid] : 'invalid');
}
public function APEtagItemIsUTF8Lookup($itemkey) {
static $APEtagItemIsUTF8Lookup = array(
'title',
'subtitle',
'artist',
'album',
'debut album',
'publisher',
'conductor',
'track',
'composer',
'comment',
'copyright',
'publicationright',
'file',
'year',
'record date',
'record location',
'genre',
'media',
'related',
'isrc',
'abstract',
'language',
'bibliography'
);
return in_array(strtolower($itemkey), $APEtagItemIsUTF8Lookup);
}
}

View File

@ -1,360 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
// also https://github.com/JamesHeinrich/getID3 //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.tag.id3v1.php //
// module for analyzing ID3v1 tags //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
class getid3_id3v1 extends getid3_handler
{
public function Analyze() {
$info = &$this->getid3->info;
if (!getid3_lib::intValueSupported($info['filesize'])) {
$info['warning'][] = 'Unable to check for ID3v1 because file is larger than '.round(PHP_INT_MAX / 1073741824).'GB';
return false;
}
$this->fseek(-256, SEEK_END);
$preid3v1 = $this->fread(128);
$id3v1tag = $this->fread(128);
if (substr($id3v1tag, 0, 3) == 'TAG') {
$info['avdataend'] = $info['filesize'] - 128;
$ParsedID3v1['title'] = $this->cutfield(substr($id3v1tag, 3, 30));
$ParsedID3v1['artist'] = $this->cutfield(substr($id3v1tag, 33, 30));
$ParsedID3v1['album'] = $this->cutfield(substr($id3v1tag, 63, 30));
$ParsedID3v1['year'] = $this->cutfield(substr($id3v1tag, 93, 4));
$ParsedID3v1['comment'] = substr($id3v1tag, 97, 30); // can't remove nulls yet, track detection depends on them
$ParsedID3v1['genreid'] = ord(substr($id3v1tag, 127, 1));
// If second-last byte of comment field is null and last byte of comment field is non-null
// then this is ID3v1.1 and the comment field is 28 bytes long and the 30th byte is the track number
if (($id3v1tag{125} === "\x00") && ($id3v1tag{126} !== "\x00")) {
$ParsedID3v1['track'] = ord(substr($ParsedID3v1['comment'], 29, 1));
$ParsedID3v1['comment'] = substr($ParsedID3v1['comment'], 0, 28);
}
$ParsedID3v1['comment'] = $this->cutfield($ParsedID3v1['comment']);
$ParsedID3v1['genre'] = $this->LookupGenreName($ParsedID3v1['genreid']);
if (!empty($ParsedID3v1['genre'])) {
unset($ParsedID3v1['genreid']);
}
if (isset($ParsedID3v1['genre']) && (empty($ParsedID3v1['genre']) || ($ParsedID3v1['genre'] == 'Unknown'))) {
unset($ParsedID3v1['genre']);
}
foreach ($ParsedID3v1 as $key => $value) {
$ParsedID3v1['comments'][$key][0] = $value;
}
// ID3v1 data is supposed to be padded with NULL characters, but some taggers pad with spaces
$GoodFormatID3v1tag = $this->GenerateID3v1Tag(
$ParsedID3v1['title'],
$ParsedID3v1['artist'],
$ParsedID3v1['album'],
$ParsedID3v1['year'],
(isset($ParsedID3v1['genre']) ? $this->LookupGenreID($ParsedID3v1['genre']) : false),
$ParsedID3v1['comment'],
(!empty($ParsedID3v1['track']) ? $ParsedID3v1['track'] : ''));
$ParsedID3v1['padding_valid'] = true;
if ($id3v1tag !== $GoodFormatID3v1tag) {
$ParsedID3v1['padding_valid'] = false;
$info['warning'][] = 'Some ID3v1 fields do not use NULL characters for padding';
}
$ParsedID3v1['tag_offset_end'] = $info['filesize'];
$ParsedID3v1['tag_offset_start'] = $ParsedID3v1['tag_offset_end'] - 128;
$info['id3v1'] = $ParsedID3v1;
}
if (substr($preid3v1, 0, 3) == 'TAG') {
// The way iTunes handles tags is, well, brain-damaged.
// It completely ignores v1 if ID3v2 is present.
// This goes as far as adding a new v1 tag *even if there already is one*
// A suspected double-ID3v1 tag has been detected, but it could be that
// the "TAG" identifier is a legitimate part of an APE or Lyrics3 tag
if (substr($preid3v1, 96, 8) == 'APETAGEX') {
// an APE tag footer was found before the last ID3v1, assume false "TAG" synch
} elseif (substr($preid3v1, 119, 6) == 'LYRICS') {
// a Lyrics3 tag footer was found before the last ID3v1, assume false "TAG" synch
} else {
// APE and Lyrics3 footers not found - assume double ID3v1
$info['warning'][] = 'Duplicate ID3v1 tag detected - this has been known to happen with iTunes';
$info['avdataend'] -= 128;
}
}
return true;
}
public static function cutfield($str) {
return trim(substr($str, 0, strcspn($str, "\x00")));
}
public static function ArrayOfGenres($allowSCMPXextended=false) {
static $GenreLookup = array(
0 => 'Blues',
1 => 'Classic Rock',
2 => 'Country',
3 => 'Dance',
4 => 'Disco',
5 => 'Funk',
6 => 'Grunge',
7 => 'Hip-Hop',
8 => 'Jazz',
9 => 'Metal',
10 => 'New Age',
11 => 'Oldies',
12 => 'Other',
13 => 'Pop',
14 => 'R&B',
15 => 'Rap',
16 => 'Reggae',
17 => 'Rock',
18 => 'Techno',
19 => 'Industrial',
20 => 'Alternative',
21 => 'Ska',
22 => 'Death Metal',
23 => 'Pranks',
24 => 'Soundtrack',
25 => 'Euro-Techno',
26 => 'Ambient',
27 => 'Trip-Hop',
28 => 'Vocal',
29 => 'Jazz+Funk',
30 => 'Fusion',
31 => 'Trance',
32 => 'Classical',
33 => 'Instrumental',
34 => 'Acid',
35 => 'House',
36 => 'Game',
37 => 'Sound Clip',
38 => 'Gospel',
39 => 'Noise',
40 => 'Alt. Rock',
41 => 'Bass',
42 => 'Soul',
43 => 'Punk',
44 => 'Space',
45 => 'Meditative',
46 => 'Instrumental Pop',
47 => 'Instrumental Rock',
48 => 'Ethnic',
49 => 'Gothic',
50 => 'Darkwave',
51 => 'Techno-Industrial',
52 => 'Electronic',
53 => 'Pop-Folk',
54 => 'Eurodance',
55 => 'Dream',
56 => 'Southern Rock',
57 => 'Comedy',
58 => 'Cult',
59 => 'Gangsta Rap',
60 => 'Top 40',
61 => 'Christian Rap',
62 => 'Pop/Funk',
63 => 'Jungle',
64 => 'Native American',
65 => 'Cabaret',
66 => 'New Wave',
67 => 'Psychedelic',
68 => 'Rave',
69 => 'Showtunes',
70 => 'Trailer',
71 => 'Lo-Fi',
72 => 'Tribal',
73 => 'Acid Punk',
74 => 'Acid Jazz',
75 => 'Polka',
76 => 'Retro',
77 => 'Musical',
78 => 'Rock & Roll',
79 => 'Hard Rock',
80 => 'Folk',
81 => 'Folk/Rock',
82 => 'National Folk',
83 => 'Swing',
84 => 'Fast-Fusion',
85 => 'Bebob',
86 => 'Latin',
87 => 'Revival',
88 => 'Celtic',
89 => 'Bluegrass',
90 => 'Avantgarde',
91 => 'Gothic Rock',
92 => 'Progressive Rock',
93 => 'Psychedelic Rock',
94 => 'Symphonic Rock',
95 => 'Slow Rock',
96 => 'Big Band',
97 => 'Chorus',
98 => 'Easy Listening',
99 => 'Acoustic',
100 => 'Humour',
101 => 'Speech',
102 => 'Chanson',
103 => 'Opera',
104 => 'Chamber Music',
105 => 'Sonata',
106 => 'Symphony',
107 => 'Booty Bass',
108 => 'Primus',
109 => 'Porn Groove',
110 => 'Satire',
111 => 'Slow Jam',
112 => 'Club',
113 => 'Tango',
114 => 'Samba',
115 => 'Folklore',
116 => 'Ballad',
117 => 'Power Ballad',
118 => 'Rhythmic Soul',
119 => 'Freestyle',
120 => 'Duet',
121 => 'Punk Rock',
122 => 'Drum Solo',
123 => 'A Cappella',
124 => 'Euro-House',
125 => 'Dance Hall',
126 => 'Goa',
127 => 'Drum & Bass',
128 => 'Club-House',
129 => 'Hardcore',
130 => 'Terror',
131 => 'Indie',
132 => 'BritPop',
133 => 'Negerpunk',
134 => 'Polsk Punk',
135 => 'Beat',
136 => 'Christian Gangsta Rap',
137 => 'Heavy Metal',
138 => 'Black Metal',
139 => 'Crossover',
140 => 'Contemporary Christian',
141 => 'Christian Rock',
142 => 'Merengue',
143 => 'Salsa',
144 => 'Thrash Metal',
145 => 'Anime',
146 => 'JPop',
147 => 'Synthpop',
255 => 'Unknown',
'CR' => 'Cover',
'RX' => 'Remix'
);
static $GenreLookupSCMPX = array();
if ($allowSCMPXextended && empty($GenreLookupSCMPX)) {
$GenreLookupSCMPX = $GenreLookup;
// http://www.geocities.co.jp/SiliconValley-Oakland/3664/alittle.html#GenreExtended
// Extended ID3v1 genres invented by SCMPX
// Note that 255 "Japanese Anime" conflicts with standard "Unknown"
$GenreLookupSCMPX[240] = 'Sacred';
$GenreLookupSCMPX[241] = 'Northern Europe';
$GenreLookupSCMPX[242] = 'Irish & Scottish';
$GenreLookupSCMPX[243] = 'Scotland';
$GenreLookupSCMPX[244] = 'Ethnic Europe';
$GenreLookupSCMPX[245] = 'Enka';
$GenreLookupSCMPX[246] = 'Children\'s Song';
$GenreLookupSCMPX[247] = 'Japanese Sky';
$GenreLookupSCMPX[248] = 'Japanese Heavy Rock';
$GenreLookupSCMPX[249] = 'Japanese Doom Rock';
$GenreLookupSCMPX[250] = 'Japanese J-POP';
$GenreLookupSCMPX[251] = 'Japanese Seiyu';
$GenreLookupSCMPX[252] = 'Japanese Ambient Techno';
$GenreLookupSCMPX[253] = 'Japanese Moemoe';
$GenreLookupSCMPX[254] = 'Japanese Tokusatsu';
//$GenreLookupSCMPX[255] = 'Japanese Anime';
}
return ($allowSCMPXextended ? $GenreLookupSCMPX : $GenreLookup);
}
public static function LookupGenreName($genreid, $allowSCMPXextended=true) {
switch ($genreid) {
case 'RX':
case 'CR':
break;
default:
if (!is_numeric($genreid)) {
return false;
}
$genreid = intval($genreid); // to handle 3 or '3' or '03'
break;
}
$GenreLookup = self::ArrayOfGenres($allowSCMPXextended);
return (isset($GenreLookup[$genreid]) ? $GenreLookup[$genreid] : false);
}
public static function LookupGenreID($genre, $allowSCMPXextended=false) {
$GenreLookup = self::ArrayOfGenres($allowSCMPXextended);
$LowerCaseNoSpaceSearchTerm = strtolower(str_replace(' ', '', $genre));
foreach ($GenreLookup as $key => $value) {
if (strtolower(str_replace(' ', '', $value)) == $LowerCaseNoSpaceSearchTerm) {
return $key;
}
}
return false;
}
public static function StandardiseID3v1GenreName($OriginalGenre) {
if (($GenreID = self::LookupGenreID($OriginalGenre)) !== false) {
return self::LookupGenreName($GenreID);
}
return $OriginalGenre;
}
public static function GenerateID3v1Tag($title, $artist, $album, $year, $genreid, $comment, $track='') {
$ID3v1Tag = 'TAG';
$ID3v1Tag .= str_pad(trim(substr($title, 0, 30)), 30, "\x00", STR_PAD_RIGHT);
$ID3v1Tag .= str_pad(trim(substr($artist, 0, 30)), 30, "\x00", STR_PAD_RIGHT);
$ID3v1Tag .= str_pad(trim(substr($album, 0, 30)), 30, "\x00", STR_PAD_RIGHT);
$ID3v1Tag .= str_pad(trim(substr($year, 0, 4)), 4, "\x00", STR_PAD_LEFT);
if (!empty($track) && ($track > 0) && ($track <= 255)) {
$ID3v1Tag .= str_pad(trim(substr($comment, 0, 28)), 28, "\x00", STR_PAD_RIGHT);
$ID3v1Tag .= "\x00";
if (gettype($track) == 'string') {
$track = (int) $track;
}
$ID3v1Tag .= chr($track);
} else {
$ID3v1Tag .= str_pad(trim(substr($comment, 0, 30)), 30, "\x00", STR_PAD_RIGHT);
}
if (($genreid < 0) || ($genreid > 147)) {
$genreid = 255; // 'unknown' genre
}
switch (gettype($genreid)) {
case 'string':
case 'integer':
$ID3v1Tag .= chr(intval($genreid));
break;
default:
$ID3v1Tag .= chr(255); // 'unknown' genre
break;
}
return $ID3v1Tag;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,294 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
// also https://github.com/JamesHeinrich/getID3 //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
/// //
// module.tag.lyrics3.php //
// module for analyzing Lyrics3 tags //
// dependencies: module.tag.apetag.php (optional) //
// ///
/////////////////////////////////////////////////////////////////
class getid3_lyrics3 extends getid3_handler
{
public function Analyze() {
$info = &$this->getid3->info;
// http://www.volweb.cz/str/tags.htm
if (!getid3_lib::intValueSupported($info['filesize'])) {
$info['warning'][] = 'Unable to check for Lyrics3 because file is larger than '.round(PHP_INT_MAX / 1073741824).'GB';
return false;
}
$this->fseek((0 - 128 - 9 - 6), SEEK_END); // end - ID3v1 - "LYRICSEND" - [Lyrics3size]
$lyrics3_id3v1 = $this->fread(128 + 9 + 6);
$lyrics3lsz = substr($lyrics3_id3v1, 0, 6); // Lyrics3size
$lyrics3end = substr($lyrics3_id3v1, 6, 9); // LYRICSEND or LYRICS200
$id3v1tag = substr($lyrics3_id3v1, 15, 128); // ID3v1
if ($lyrics3end == 'LYRICSEND') {
// Lyrics3v1, ID3v1, no APE
$lyrics3size = 5100;
$lyrics3offset = $info['filesize'] - 128 - $lyrics3size;
$lyrics3version = 1;
} elseif ($lyrics3end == 'LYRICS200') {
// Lyrics3v2, ID3v1, no APE
// LSZ = lyrics + 'LYRICSBEGIN'; add 6-byte size field; add 'LYRICS200'
$lyrics3size = $lyrics3lsz + 6 + strlen('LYRICS200');
$lyrics3offset = $info['filesize'] - 128 - $lyrics3size;
$lyrics3version = 2;
} elseif (substr(strrev($lyrics3_id3v1), 0, 9) == strrev('LYRICSEND')) {
// Lyrics3v1, no ID3v1, no APE
$lyrics3size = 5100;
$lyrics3offset = $info['filesize'] - $lyrics3size;
$lyrics3version = 1;
$lyrics3offset = $info['filesize'] - $lyrics3size;
} elseif (substr(strrev($lyrics3_id3v1), 0, 9) == strrev('LYRICS200')) {
// Lyrics3v2, no ID3v1, no APE
$lyrics3size = strrev(substr(strrev($lyrics3_id3v1), 9, 6)) + 6 + strlen('LYRICS200'); // LSZ = lyrics + 'LYRICSBEGIN'; add 6-byte size field; add 'LYRICS200'
$lyrics3offset = $info['filesize'] - $lyrics3size;
$lyrics3version = 2;
} else {
if (isset($info['ape']['tag_offset_start']) && ($info['ape']['tag_offset_start'] > 15)) {
$this->fseek($info['ape']['tag_offset_start'] - 15);
$lyrics3lsz = $this->fread(6);
$lyrics3end = $this->fread(9);
if ($lyrics3end == 'LYRICSEND') {
// Lyrics3v1, APE, maybe ID3v1
$lyrics3size = 5100;
$lyrics3offset = $info['ape']['tag_offset_start'] - $lyrics3size;
$info['avdataend'] = $lyrics3offset;
$lyrics3version = 1;
$info['warning'][] = 'APE tag located after Lyrics3, will probably break Lyrics3 compatability';
} elseif ($lyrics3end == 'LYRICS200') {
// Lyrics3v2, APE, maybe ID3v1
$lyrics3size = $lyrics3lsz + 6 + strlen('LYRICS200'); // LSZ = lyrics + 'LYRICSBEGIN'; add 6-byte size field; add 'LYRICS200'
$lyrics3offset = $info['ape']['tag_offset_start'] - $lyrics3size;
$lyrics3version = 2;
$info['warning'][] = 'APE tag located after Lyrics3, will probably break Lyrics3 compatability';
}
}
}
if (isset($lyrics3offset)) {
$info['avdataend'] = $lyrics3offset;
$this->getLyrics3Data($lyrics3offset, $lyrics3version, $lyrics3size);
if (!isset($info['ape'])) {
$GETID3_ERRORARRAY = &$info['warning'];
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.apetag.php', __FILE__, true);
$getid3_temp = new getID3();
$getid3_temp->openfile($this->getid3->filename);
$getid3_apetag = new getid3_apetag($getid3_temp);
$getid3_apetag->overrideendoffset = $info['lyrics3']['tag_offset_start'];
$getid3_apetag->Analyze();
if (!empty($getid3_temp->info['ape'])) {
$info['ape'] = $getid3_temp->info['ape'];
}
if (!empty($getid3_temp->info['replay_gain'])) {
$info['replay_gain'] = $getid3_temp->info['replay_gain'];
}
unset($getid3_temp, $getid3_apetag);
}
}
return true;
}
public function getLyrics3Data($endoffset, $version, $length) {
// http://www.volweb.cz/str/tags.htm
$info = &$this->getid3->info;
if (!getid3_lib::intValueSupported($endoffset)) {
$info['warning'][] = 'Unable to check for Lyrics3 because file is larger than '.round(PHP_INT_MAX / 1073741824).'GB';
return false;
}
$this->fseek($endoffset);
if ($length <= 0) {
return false;
}
$rawdata = $this->fread($length);
$ParsedLyrics3['raw']['lyrics3version'] = $version;
$ParsedLyrics3['raw']['lyrics3tagsize'] = $length;
$ParsedLyrics3['tag_offset_start'] = $endoffset;
$ParsedLyrics3['tag_offset_end'] = $endoffset + $length - 1;
if (substr($rawdata, 0, 11) != 'LYRICSBEGIN') {
if (strpos($rawdata, 'LYRICSBEGIN') !== false) {
$info['warning'][] = '"LYRICSBEGIN" expected at '.$endoffset.' but actually found at '.($endoffset + strpos($rawdata, 'LYRICSBEGIN')).' - this is invalid for Lyrics3 v'.$version;
$info['avdataend'] = $endoffset + strpos($rawdata, 'LYRICSBEGIN');
$rawdata = substr($rawdata, strpos($rawdata, 'LYRICSBEGIN'));
$length = strlen($rawdata);
$ParsedLyrics3['tag_offset_start'] = $info['avdataend'];
$ParsedLyrics3['raw']['lyrics3tagsize'] = $length;
} else {
$info['error'][] = '"LYRICSBEGIN" expected at '.$endoffset.' but found "'.substr($rawdata, 0, 11).'" instead';
return false;
}
}
switch ($version) {
case 1:
if (substr($rawdata, strlen($rawdata) - 9, 9) == 'LYRICSEND') {
$ParsedLyrics3['raw']['LYR'] = trim(substr($rawdata, 11, strlen($rawdata) - 11 - 9));
$this->Lyrics3LyricsTimestampParse($ParsedLyrics3);
} else {
$info['error'][] = '"LYRICSEND" expected at '.($this->ftell() - 11 + $length - 9).' but found "'.substr($rawdata, strlen($rawdata) - 9, 9).'" instead';
return false;
}
break;
case 2:
if (substr($rawdata, strlen($rawdata) - 9, 9) == 'LYRICS200') {
$ParsedLyrics3['raw']['unparsed'] = substr($rawdata, 11, strlen($rawdata) - 11 - 9 - 6); // LYRICSBEGIN + LYRICS200 + LSZ
$rawdata = $ParsedLyrics3['raw']['unparsed'];
while (strlen($rawdata) > 0) {
$fieldname = substr($rawdata, 0, 3);
$fieldsize = (int) substr($rawdata, 3, 5);
$ParsedLyrics3['raw'][$fieldname] = substr($rawdata, 8, $fieldsize);
$rawdata = substr($rawdata, 3 + 5 + $fieldsize);
}
if (isset($ParsedLyrics3['raw']['IND'])) {
$i = 0;
$flagnames = array('lyrics', 'timestamps', 'inhibitrandom');
foreach ($flagnames as $flagname) {
if (strlen($ParsedLyrics3['raw']['IND']) > $i++) {
$ParsedLyrics3['flags'][$flagname] = $this->IntString2Bool(substr($ParsedLyrics3['raw']['IND'], $i, 1 - 1));
}
}
}
$fieldnametranslation = array('ETT'=>'title', 'EAR'=>'artist', 'EAL'=>'album', 'INF'=>'comment', 'AUT'=>'author');
foreach ($fieldnametranslation as $key => $value) {
if (isset($ParsedLyrics3['raw'][$key])) {
$ParsedLyrics3['comments'][$value][] = trim($ParsedLyrics3['raw'][$key]);
}
}
if (isset($ParsedLyrics3['raw']['IMG'])) {
$imagestrings = explode("\r\n", $ParsedLyrics3['raw']['IMG']);
foreach ($imagestrings as $key => $imagestring) {
if (strpos($imagestring, '||') !== false) {
$imagearray = explode('||', $imagestring);
$ParsedLyrics3['images'][$key]['filename'] = (isset($imagearray[0]) ? $imagearray[0] : '');
$ParsedLyrics3['images'][$key]['description'] = (isset($imagearray[1]) ? $imagearray[1] : '');
$ParsedLyrics3['images'][$key]['timestamp'] = $this->Lyrics3Timestamp2Seconds(isset($imagearray[2]) ? $imagearray[2] : '');
}
}
}
if (isset($ParsedLyrics3['raw']['LYR'])) {
$this->Lyrics3LyricsTimestampParse($ParsedLyrics3);
}
} else {
$info['error'][] = '"LYRICS200" expected at '.($this->ftell() - 11 + $length - 9).' but found "'.substr($rawdata, strlen($rawdata) - 9, 9).'" instead';
return false;
}
break;
default:
$info['error'][] = 'Cannot process Lyrics3 version '.$version.' (only v1 and v2)';
return false;
break;
}
if (isset($info['id3v1']['tag_offset_start']) && ($info['id3v1']['tag_offset_start'] <= $ParsedLyrics3['tag_offset_end'])) {
$info['warning'][] = 'ID3v1 tag information ignored since it appears to be a false synch in Lyrics3 tag data';
unset($info['id3v1']);
foreach ($info['warning'] as $key => $value) {
if ($value == 'Some ID3v1 fields do not use NULL characters for padding') {
unset($info['warning'][$key]);
sort($info['warning']);
break;
}
}
}
$info['lyrics3'] = $ParsedLyrics3;
return true;
}
public function Lyrics3Timestamp2Seconds($rawtimestamp) {
if (preg_match('#^\\[([0-9]{2}):([0-9]{2})\\]$#', $rawtimestamp, $regs)) {
return (int) (($regs[1] * 60) + $regs[2]);
}
return false;
}
public function Lyrics3LyricsTimestampParse(&$Lyrics3data) {
$lyricsarray = explode("\r\n", $Lyrics3data['raw']['LYR']);
foreach ($lyricsarray as $key => $lyricline) {
$regs = array();
unset($thislinetimestamps);
while (preg_match('#^(\\[[0-9]{2}:[0-9]{2}\\])#', $lyricline, $regs)) {
$thislinetimestamps[] = $this->Lyrics3Timestamp2Seconds($regs[0]);
$lyricline = str_replace($regs[0], '', $lyricline);
}
$notimestamplyricsarray[$key] = $lyricline;
if (isset($thislinetimestamps) && is_array($thislinetimestamps)) {
sort($thislinetimestamps);
foreach ($thislinetimestamps as $timestampkey => $timestamp) {
if (isset($Lyrics3data['synchedlyrics'][$timestamp])) {
// timestamps only have a 1-second resolution, it's possible that multiple lines
// could have the same timestamp, if so, append
$Lyrics3data['synchedlyrics'][$timestamp] .= "\r\n".$lyricline;
} else {
$Lyrics3data['synchedlyrics'][$timestamp] = $lyricline;
}
}
}
}
$Lyrics3data['unsynchedlyrics'] = implode("\r\n", $notimestamplyricsarray);
if (isset($Lyrics3data['synchedlyrics']) && is_array($Lyrics3data['synchedlyrics'])) {
ksort($Lyrics3data['synchedlyrics']);
}
return true;
}
public function IntString2Bool($char) {
if ($char == '1') {
return true;
} elseif ($char == '0') {
return false;
}
return null;
}
}

View File

@ -1,292 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<PodcastGenerator>
<category>
<id></id>
<description></description>
</category>
<category>
<id>Arts</id>
<description>Arts</description>
</category>
<category>
<id>Arts:Design</id>
<description>Arts:Design</description>
</category>
<category>
<id>Arts:Fashion &amp; Beauty</id>
<description>Arts:Fashion &amp; Beauty</description>
</category>
<category>
<id>Arts:Food</id>
<description>Arts:Food</description>
</category>
<category>
<id>Arts:Literature</id>
<description>Arts:Literature</description>
</category>
<category>
<id>Arts:Performing Arts</id>
<description>Arts:Performing Arts</description>
</category>
<category>
<id>Arts:Visual Arts</id>
<description>Arts:Visual Arts</description>
</category>
<category>
<id>Business</id>
<description>Business</description>
</category>
<category>
<id>Business:Business News</id>
<description>Business:Business News</description>
</category>
<category>
<id>Business:Careers</id>
<description>Business:Careers</description>
</category>
<category>
<id>Business:Investing</id>
<description>Business:Investing</description>
</category>
<category>
<id>Business:Management &amp; Marketing</id>
<description>Business:Management &amp; Marketing</description>
</category>
<category>
<id>Business:Shopping</id>
<description>Business:Shopping</description>
</category>
<category>
<id>Comedy</id>
<description>Comedy</description>
</category>
<category>
<id>Education</id>
<description>Education</description>
</category>
<category>
<id>Education:Education Technology</id>
<description>Education:Education Technology</description>
</category>
<category>
<id>Education:Higher Education</id>
<description>Education:Higher Education</description>
</category>
<category>
<id>Education:K-12</id>
<description>Education:K-12</description>
</category>
<category>
<id>Education:Language Courses</id>
<description>Education:Language Courses</description>
</category>
<category>
<id>Education:Training</id>
<description>Education:Training</description>
</category>
<category>
<id>Games &amp; Hobbies</id>
<description>Games &amp; Hobbies</description>
</category>
<category>
<id>Games &amp; Hobbies:Automotive</id>
<description>Games &amp; Hobbies:Automotive</description>
</category>
<category>
<id>Games &amp; Hobbies:Aviation</id>
<description>Games &amp; Hobbies:Aviation</description>
</category>
<category>
<id>Games &amp; Hobbies:Hobbies</id>
<description>Games &amp; Hobbies:Hobbies</description>
</category>
<category>
<id>Games &amp; Hobbies:Other Games</id>
<description>Games &amp; Hobbies:Other Games</description>
</category>
<category>
<id>Games &amp; Hobbies:Video Games</id>
<description>Games &amp; Hobbies:Video Games</description>
</category>
<category>
<id>Government &amp; Organizations</id>
<description>Government &amp; Organizations</description>
</category>
<category>
<id>Government &amp; Organizations:Local</id>
<description>Government &amp; Organizations:Local</description>
</category>
<category>
<id>Government &amp; Organizations:National</id>
<description>Government &amp; Organizations:National</description>
</category>
<category>
<id>Government &amp; Organizations:Non-Profit</id>
<description>Government &amp; Organizations:Non-Profit</description>
</category>
<category>
<id>Government &amp; Organizations:Regional</id>
<description>Government &amp; Organizations:Regional</description>
</category>
<category>
<id>Health</id>
<description>Health</description>
</category>
<category>
<id>Health:Alternative Health</id>
<description>Health:Alternative Health</description>
</category>
<category>
<id>Health:Fitness &amp; Nutrition</id>
<description>Health:Fitness &amp; Nutrition</description>
</category>
<category>
<id>Health:Self-Help</id>
<description>Health:Self-Help</description>
</category>
<category>
<id>Health:Sexuality</id>
<description>Health:Sexuality</description>
</category>
<category>
<id>Kids &amp; Family</id>
<description>Kids &amp; Family</description>
</category>
<category>
<id>Music</id>
<description>Music</description>
</category>
<category>
<id>News &amp; Politics</id>
<description>News &amp; Politics</description>
</category>
<category>
<id>Religion &amp; Spirituality</id>
<description>Religion &amp; Spirituality</description>
</category>
<category>
<id>Religion &amp; Spirituality:Buddhism</id>
<description>Religion &amp; Spirituality:Buddhism</description>
</category>
<category>
<id>Religion &amp; Spirituality:Christianity</id>
<description>Religion &amp; Spirituality:Christianity</description>
</category>
<category>
<id>Religion &amp; Spirituality:Hinduism</id>
<description>Religion &amp; Spirituality:Hinduism</description>
</category>
<category>
<id>Religion &amp; Spirituality:Islam</id>
<description>Religion &amp; Spirituality:Islam</description>
</category>
<category>
<id>Religion &amp; Spirituality:Judaism</id>
<description>Religion &amp; Spirituality:Judaism</description>
</category>
<category>
<id>Religion &amp; Spirituality:Other</id>
<description>Religion &amp; Spirituality:Other</description>
</category>
<category>
<id>Religion &amp; Spirituality:Spirituality</id>
<description>Religion &amp; Spirituality:Spirituality</description>
</category>
<category>
<id>Science &amp; Medicine</id>
<description>Science &amp; Medicine</description>
</category>
<category>
<id>Science &amp; Medicine:Medicine</id>
<description>Science &amp; Medicine:Medicine</description>
</category>
<category>
<id>Science &amp; Medicine:Natural Sciences</id>
<description>Science &amp; Medicine:Natural Sciences</description>
</category>
<category>
<id>Science &amp; Medicine:Social Sciences</id>
<description>Science &amp; Medicine:Social Sciences</description>
</category>
<category>
<id>Society &amp; Culture</id>
<description>Society &amp; Culture</description>
</category>
<category>
<id>Society &amp; Culture:History</id>
<description>Society &amp; Culture:History</description>
</category>
<category>
<id>Society &amp; Culture:Personal Journals</id>
<description>Society &amp; Culture:Personal Journals</description>
</category>
<category>
<id>Society &amp; Culture:Philosophy</id>
<description>Society &amp; Culture:Philosophy</description>
</category>
<category>
<id>Society &amp; Culture:Places &amp; Travel</id>
<description>Society &amp; Culture:Places &amp; Travel</description>
</category>
<category>
<id>Sports &amp; Recreation</id>
<description>Sports &amp; Recreation</description>
</category>
<category>
<id>Sports &amp; Recreation:Amateur</id>
<description>Sports &amp; Recreation:Amateur</description>
</category>
<category>
<id>Sports &amp; Recreation:College &amp; High School</id>
<description>Sports &amp; Recreation:College &amp; High School</description>
</category>
<category>
<id>Sports &amp; Recreation:Outdoor</id>
<description>Sports &amp; Recreation:Outdoor</description>
</category>
<category>
<id>Sports &amp; Recreation:Professional</id>
<description>Sports &amp; Recreation:Professional</description>
</category>
<category>
<id>Technology</id>
<description>Technology</description>
</category>
<category>
<id>Technology:Gadgets</id>
<description>Technology:Gadgets</description>
</category>
<category>
<id>Technology:Tech News</id>
<description>Technology:Tech News</description>
</category>
<category>
<id>Technology:Podcasting</id>
<description>Technology:Podcasting</description>
</category>
<category>
<id>Technology:Software How-To</id>
<description>Technology:Software How-To</description>
</category>
<category>
<id>TV &amp; Film</id>
<description>TV &amp; Film</description>
</category>
</PodcastGenerator>

View File

@ -1,86 +0,0 @@
function cnt(w,x){
var y=w.value;
var r = 0;
a=y.replace(/\s/g,' ');
a=a.split(',');
for (z=0; z<a.length; z++) {if (a[z].length > 0) r++;}
x.value=r;
}
function limitText(limitField, limitCount, limitNum) {
if (limitField.value.length > limitNum) {
limitField.value = limitField.value.substring(0, limitNum);
} else {
limitCount.value = limitNum - limitField.value.length;
}
}
function checkMaxSelected (select, maxSelected, displ_error_nummaxcat) {
if (!select.storeSelections) {
select.storeSelections = new Array(select.options.length);
select.optionsSelected = 0;
}
for (var i = 0; i < select.options.length; i++) {
if (select.options[i].selected && !select.storeSelections[i]) {
if (select.optionsSelected < maxSelected) {
select.storeSelections[i] = true;
select.optionsSelected++;
}
else {
alert(displ_error_nummaxcat + maxSelected);
select.options[i].selected = false;
}
}
else if (!select.options[i].selected && select.storeSelections[i]) {
select.storeSelections[i] = false;
select.optionsSelected--;
}
}
}
///////////////////////
// DISPLAY LOADER
function getScrollTop() {
if ( document.documentElement.scrollTop )
return document.documentElement.scrollTop;
return document.body.scrollTop;
}
function showNotify( str ) {
var elem = document.getElementById('status_notification');
elem.style.display = 'block';
elem.style.visibility = 'visible';
if ( elem.currentStyle && elem.currentStyle.position == 'absolute' ) {
elem.style.top = getScrollTop();
}
elem.innerHTML = str;
}
function hideNotify() {
var elem = document.getElementById('status_notification');
elem.style.display = 'none';
elem.style.visibility = 'hidden';
}
window.onscroll = function () {
var elem = document.getElementById('status_notification');
if ( !elem.currentStyle || elem.currentStyle.position != 'absolute' ) {
window.onscroll = null;
} else {
window.onscroll = function () { elem.style.top = getScrollTop(); };
document.getElementById('status_notification').style.top = getScrollTop();
}
}
// END - DISPLAY LOADER
///////////////////////

File diff suppressed because one or more lines are too long

View File

@ -1,220 +0,0 @@
<?php
/*
======================================================================
lastRSS 0.9.1
Simple yet powerfull PHP class to parse RSS files.
by Vojtech Semecky, webmaster @ webdot . cz
Latest version, features, manual and examples:
http://lastrss.webdot.cz/
----------------------------------------------------------------------
LICENSE
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License (GPL)
as published by the Free Software Foundation; either version 2
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.
To read the license please visit http://www.gnu.org/copyleft/gpl.html
======================================================================
*/
/**
* lastRSS
* Simple yet powerfull PHP class to parse RSS files.
*/
class lastRSS {
// -------------------------------------------------------------------
// Public properties
// -------------------------------------------------------------------
var $default_cp = 'UTF-8';
var $CDATA = 'nochange';
var $cp = '';
var $items_limit = 1;
var $stripHTML = False;
var $date_format = 'M d, Y g:i A';
// -------------------------------------------------------------------
// Private variables
// -------------------------------------------------------------------
var $channeltags = array ('title', 'link', 'description', 'language', 'copyright', 'managingEditor', 'webMaster', 'lastBuildDate', 'rating', 'docs');
var $itemtags = array('title', 'link', 'description', 'author', 'category', 'comments', 'enclosure', 'guid', 'pubDate', 'source');
var $imagetags = array('title', 'url', 'link', 'width', 'height');
var $textinputtags = array('title', 'description', 'name', 'link');
// -------------------------------------------------------------------
// Parse RSS file and returns associative array.
// -------------------------------------------------------------------
function Get ($rss_url) {
// If CACHE ENABLED
if ($this->cache_dir != '') {
$cache_file = $this->cache_dir . '/rsscache_' . md5($rss_url);
$timedif = @(time() - filemtime($cache_file));
if ($timedif < $this->cache_time) {
// cached file is fresh enough, return cached array
$result = unserialize(join('', file($cache_file)));
// set 'cached' to 1 only if cached file is correct
if ($result) $result['cached'] = 1;
} else {
// cached file is too old, create new
$result = $this->Parse($rss_url);
$serialized = serialize($result);
if ($f = @fopen($cache_file, 'w')) {
fwrite ($f, $serialized, strlen($serialized));
fclose($f);
}
if ($result) $result['cached'] = 0;
}
}
// If CACHE DISABLED >> load and parse the file directly
else {
$result = $this->Parse($rss_url);
if ($result) $result['cached'] = 0;
}
// return result
return $result;
}
// -------------------------------------------------------------------
// Modification of preg_match(); return trimed field with index 1
// from 'classic' preg_match() array output
// -------------------------------------------------------------------
function my_preg_match ($pattern, $subject) {
// start regullar expression
preg_match($pattern, $subject, $out);
// if there is some result... process it and return it
if(isset($out[1])) {
// Process CDATA (if present)
if ($this->CDATA == 'content') { // Get CDATA content (without CDATA tag)
$out[1] = strtr($out[1], array('<![CDATA['=>'', ']]>'=>''));
} elseif ($this->CDATA == 'strip') { // Strip CDATA
$out[1] = strtr($out[1], array('<![CDATA['=>'', ']]>'=>''));
}
// If code page is set convert character encoding to required
if ($this->cp != '')
//$out[1] = $this->MyConvertEncoding($this->rsscp, $this->cp, $out[1]);
$out[1] = iconv($this->rsscp, $this->cp.'//TRANSLIT', $out[1]);
// Return result
return trim($out[1]);
} else {
// if there is NO result, return empty string
return '';
}
}
// -------------------------------------------------------------------
// Replace HTML entities &something; by real characters
// -------------------------------------------------------------------
function unhtmlentities ($string) {
// Get HTML entities table
$trans_tbl = get_html_translation_table (HTML_ENTITIES, ENT_QUOTES);
// Flip keys<==>values
$trans_tbl = array_flip ($trans_tbl);
// Add support for &apos; entity (missing in HTML_ENTITIES)
$trans_tbl += array('&apos;' => "'");
// Replace entities by values
return strtr ($string, $trans_tbl);
}
// -------------------------------------------------------------------
// Parse() is private method used by Get() to load and parse RSS file.
// Don't use Parse() in your scripts - use Get($rss_file) instead.
// -------------------------------------------------------------------
function Parse ($rss_url) {
// Open and load RSS file
if ($f = @fopen($rss_url, 'r')) {
$rss_content = '';
while (!feof($f)) {
$rss_content .= fgets($f, 4096);
}
fclose($f);
// Parse document encoding
$result['encoding'] = $this->my_preg_match("'encoding=[\'\"](.*?)[\'\"]'si", $rss_content);
// if document codepage is specified, use it
if ($result['encoding'] != '')
{ $this->rsscp = $result['encoding']; } // This is used in my_preg_match()
// otherwise use the default codepage
else
{ $this->rsscp = $this->default_cp; } // This is used in my_preg_match()
// Parse CHANNEL info
preg_match("'<channel.*?>(.*?)</channel>'si", $rss_content, $out_channel);
foreach($this->channeltags as $channeltag)
{
$temp = $this->my_preg_match("'<$channeltag.*?>(.*?)</$channeltag>'si", $out_channel[1]);
if ($temp != '') $result[$channeltag] = $temp; // Set only if not empty
}
// If date_format is specified and lastBuildDate is valid
if ($this->date_format != '' && ($timestamp = strtotime($result['lastBuildDate'])) !==-1) {
// convert lastBuildDate to specified date format
$result['lastBuildDate'] = date($this->date_format, $timestamp);
}
// Parse TEXTINPUT info
preg_match("'<textinput(|[^>]*[^/])>(.*?)</textinput>'si", $rss_content, $out_textinfo);
// This a little strange regexp means:
// Look for tag <textinput> with or without any attributes, but skip truncated version <textinput /> (it's not beggining tag)
if (isset($out_textinfo[2])) {
foreach($this->textinputtags as $textinputtag) {
$temp = $this->my_preg_match("'<$textinputtag.*?>(.*?)</$textinputtag>'si", $out_textinfo[2]);
if ($temp != '') $result['textinput_'.$textinputtag] = $temp; // Set only if not empty
}
}
// Parse IMAGE info
preg_match("'<image.*?>(.*?)</image>'si", $rss_content, $out_imageinfo);
if (isset($out_imageinfo[1])) {
foreach($this->imagetags as $imagetag) {
$temp = $this->my_preg_match("'<$imagetag.*?>(.*?)</$imagetag>'si", $out_imageinfo[1]);
if ($temp != '') $result['image_'.$imagetag] = $temp; // Set only if not empty
}
}
// Parse ITEMS
preg_match_all("'<item(| .*?)>(.*?)</item>'si", $rss_content, $items);
$rss_items = $items[2];
$i = 0;
$result['items'] = array(); // create array even if there are no items
foreach($rss_items as $rss_item) {
// If number of items is lower then limit: Parse one item
if ($i < $this->items_limit || $this->items_limit == 0) {
foreach($this->itemtags as $itemtag) {
$temp = $this->my_preg_match("'<$itemtag.*?>(.*?)</$itemtag>'si", $rss_item);
if ($temp != '') $result['items'][$i][$itemtag] = $temp; // Set only if not empty
}
// Strip HTML tags and other bullshit from DESCRIPTION
if ($this->stripHTML && $result['items'][$i]['description'])
$result['items'][$i]['description'] = strip_tags($this->unhtmlentities(strip_tags($result['items'][$i]['description'])));
// Strip HTML tags and other bullshit from TITLE
if ($this->stripHTML && $result['items'][$i]['title'])
$result['items'][$i]['title'] = strip_tags($this->unhtmlentities(strip_tags($result['items'][$i]['title'])));
// If date_format is specified and pubDate is valid
if ($this->date_format != '' && ($timestamp = strtotime($result['items'][$i]['pubDate'])) !==-1) {
// convert pubDate to specified date format
$result['items'][$i]['pubDate'] = date($this->date_format, $timestamp);
}
// Item counter
$i++;
}
}
$result['items_count'] = $i;
return $result;
}
else // Error in opening return False
{
return False;
}
}
}
?>

View File

@ -1,2 +0,0 @@
See this online document:
http://www.podcastgenerator.net/documentation/FAQ-localization

View File

@ -1,259 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<PodcastGenerator>
<language>
<id>ar_SA</id>
<description>العربية</description>
</language>
<language>
<id>as_IN</id>
<description>অসমীয়া</description>
</language>
<language>
<id>ast_ES</id>
<description>Asturianu</description>
</language>
<language>
<id>bg_BG</id>
<description>Български</description>
</language>
<language>
<id>bn_IN</id>
<description>বাংলা</description>
</language>
<language>
<id>bs_BA</id>
<description>Bosanski</description>
</language>
<language>
<id>ca_ES</id>
<description>Català</description>
</language>
<language>
<id>cs_CS</id>
<description>Česky</description>
</language>
<language>
<id>da_DK</id>
<description>Dansk</description>
</language>
<language>
<id>de_DE</id>
<description>Deutsch</description>
</language>
<language>
<id>ee_ET</id>
<description>Eesti</description>
</language>
<language>
<id>el_GR</id>
<description>ελληνικά</description>
</language>
<language>
<id>en_EN</id>
<description>English</description>
</language>
<language>
<id>es_ES</id>
<description>Español</description>
</language>
<language>
<id>fa_IR</id>
<description>فارسی</description>
</language>
<language>
<id>fi_FI</id>
<description>Suomi</description>
</language>
<language>
<id>fr_FR</id>
<description>Français</description>
</language>
<language>
<id>gl_ES</id>
<description>Galego</description>
</language>
<language>
<id>gu_IN</id>
<description>ગુજરાતી</description>
</language>
<language>
<id>he_IL</id>
<description>עברית</description>
</language>
<language>
<id>hi_IN</id>
<description>हिन्दी</description>
</language>
<language>
<id>hr_HR</id>
<description>Hrvatski</description>
</language>
<language>
<id>hu_HU</id>
<description>Magyar</description>
</language>
<language>
<id>id_ID</id>
<description>Bahasa Indonesia</description>
</language>
<language>
<id>is_IS</id>
<description>Icelandic</description>
</language>
<language>
<id>it_IT</id>
<description>Italiano</description>
</language>
<language>
<id>ja_JP</id>
<description>日本語</description>
</language>
<language>
<id>kn_IN</id>
<description>Kannada</description>
</language>
<language>
<id>ko_KR</id>
<description>한국어</description>
</language>
<language>
<id>lv_LV</id>
<description>Latvian</description>
</language>
<language>
<id>ml_IN</id>
<description>Malayalam</description>
</language>
<language>
<id>mr_IN</id>
<description>Marathi</description>
</language>
<language>
<id>nb_NO</id>
<description>Norsk</description>
</language>
<language>
<id>nl_NL</id>
<description>Nederlands</description>
</language>
<language>
<id>or_IN</id>
<description>ଓଡ଼ିଆ</description>
</language>
<language>
<id>pa_IN</id>
<description>ਪੰਜਾਬੀ</description>
</language>
<language>
<id>pl_PL</id>
<description>Polski</description>
</language>
<language>
<id>pt_BR</id>
<description>Português (Brazil)</description>
</language>
<language>
<id>pt_PT</id>
<description>Português (Portugal)</description>
</language>
<language>
<id>ro_RO</id>
<description>Română</description>
</language>
<language>
<id>ru_RU</id>
<description>Русский язык</description>
</language>
<language>
<id>si_LK</id>
<description>සිංහල</description>
</language>
<language>
<id>sk_SK</id>
<description>Slovenčina</description>
</language>
<language>
<id>sr_RS</id>
<description>српски</description>
</language>
<language>
<id>sv_SE</id>
<description>Svenska</description>
</language>
<language>
<id>ta_IN</id>
<description>தமிழ்</description>
</language>
<language>
<id>te_IN</id>
<description>తెలుగు</description>
</language>
<language>
<id>th_TH</id>
<description>ไทย</description>
</language>
<language>
<id>tr_TR</id>
<description>Türkçe</description>
</language>
<language>
<id>uk_UA</id>
<description>Українська</description>
</language>
<language>
<id>zh_CN</id>
<description>中文</description>
</language>
</PodcastGenerator>

View File

@ -1,536 +0,0 @@
<?php
/*
Copyright (c) 2005 Steven Armstrong <sa at c-area dot ch>
Copyright (c) 2009 Danilo Segan <danilo@kvota.net>
Drop in replacement for native gettext.
This file is part of PHP-gettext.
PHP-gettext 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 2 of the License, or
(at your option) any later version.
PHP-gettext 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 PHP-gettext; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
LC_CTYPE 0
LC_NUMERIC 1
LC_TIME 2
LC_COLLATE 3
LC_MONETARY 4
LC_MESSAGES 5
LC_ALL 6
*/
// LC_MESSAGES is not available if php-gettext is not loaded
// while the other constants are already available from session extension.
if (!defined('LC_MESSAGES')) {
define('LC_MESSAGES', 5);
}
require('streams.php');
require('gettext.php');
// Variables
global $text_domains, $default_domain, $LC_CATEGORIES, $EMULATEGETTEXT, $CURRENTLOCALE;
$text_domains = array();
$default_domain = 'messages';
$LC_CATEGORIES = array('LC_CTYPE', 'LC_NUMERIC', 'LC_TIME', 'LC_COLLATE', 'LC_MONETARY', 'LC_MESSAGES', 'LC_ALL');
$EMULATEGETTEXT = 0;
$CURRENTLOCALE = '';
/* Class to hold a single domain included in $text_domains. */
class domain {
var $l10n;
var $path;
var $codeset;
}
// Utility functions
/**
* Return a list of locales to try for any POSIX-style locale specification.
*/
function get_list_of_locales($locale) {
/* Figure out all possible locale names and start with the most
* specific ones. I.e. for sr_CS.UTF-8@latin, look through all of
* sr_CS.UTF-8@latin, sr_CS@latin, sr@latin, sr_CS.UTF-8, sr_CS, sr.
*/
$locale_names = array();
$lang = NULL;
$country = NULL;
$charset = NULL;
$modifier = NULL;
if ($locale) {
if (preg_match("/^(?P<lang>[a-z]{2,3})" // language code
."(?:_(?P<country>[A-Z]{2}))?" // country code
."(?:\.(?P<charset>[-A-Za-z0-9_]+))?" // charset
."(?:@(?P<modifier>[-A-Za-z0-9_]+))?$/", // @ modifier
$locale, $matches)) {
if (isset($matches["lang"])) $lang = $matches["lang"];
if (isset($matches["country"])) $country = $matches["country"];
if (isset($matches["charset"])) $charset = $matches["charset"];
if (isset($matches["modifier"])) $modifier = $matches["modifier"];
if ($modifier) {
if ($country) {
if ($charset)
array_push($locale_names, "${lang}_$country.$charset@$modifier");
array_push($locale_names, "${lang}_$country@$modifier");
} elseif ($charset)
array_push($locale_names, "${lang}.$charset@$modifier");
array_push($locale_names, "$lang@$modifier");
}
if ($country) {
if ($charset)
array_push($locale_names, "${lang}_$country.$charset");
array_push($locale_names, "${lang}_$country");
} elseif ($charset)
array_push($locale_names, "${lang}.$charset");
array_push($locale_names, $lang);
}
// If the locale name doesn't match POSIX style, just include it as-is.
if (!in_array($locale, $locale_names))
array_push($locale_names, $locale);
}
return $locale_names;
}
/**
* Utility function to get a StreamReader for the given text domain.
*/
function _get_reader($domain=null, $category=5, $enable_cache=true) {
global $text_domains, $default_domain, $LC_CATEGORIES;
if (!isset($domain)) $domain = $default_domain;
if (!isset($text_domains[$domain]->l10n)) {
// get the current locale
$locale = _setlocale(LC_MESSAGES, 0);
$bound_path = isset($text_domains[$domain]->path) ?
$text_domains[$domain]->path : './';
$subpath = $LC_CATEGORIES[$category] ."/$domain.mo";
$locale_names = get_list_of_locales($locale);
$input = null;
foreach ($locale_names as $locale) {
$full_path = $bound_path . $locale . "/" . $subpath;
if (file_exists($full_path)) {
$input = new FileReader($full_path);
break;
}
}
if (!array_key_exists($domain, $text_domains)) {
// Initialize an empty domain object.
$text_domains[$domain] = new domain();
}
$text_domains[$domain]->l10n = new gettext_reader($input,
$enable_cache);
}
return $text_domains[$domain]->l10n;
}
/**
* Returns whether we are using our emulated gettext API or PHP built-in one.
*/
function locale_emulation() {
global $EMULATEGETTEXT;
return $EMULATEGETTEXT;
}
/**
* Checks if the current locale is supported on this system.
*/
function _check_locale_and_function($function=false) {
global $EMULATEGETTEXT;
if ($function and !function_exists($function))
return false;
return !$EMULATEGETTEXT;
}
/**
* Get the codeset for the given domain.
*/
function _get_codeset($domain=null) {
global $text_domains, $default_domain, $LC_CATEGORIES;
if (!isset($domain)) $domain = $default_domain;
return (isset($text_domains[$domain]->codeset))? $text_domains[$domain]->codeset : ini_get('mbstring.internal_encoding');
}
/**
* Convert the given string to the encoding set by bind_textdomain_codeset.
*/
function _encode($text) {
$source_encoding = mb_detect_encoding($text);
$target_encoding = _get_codeset();
if ($source_encoding != $target_encoding) {
return mb_convert_encoding($text, $target_encoding, $source_encoding);
}
else {
return $text;
}
}
// Custom implementation of the standard gettext related functions
/**
* Returns passed in $locale, or environment variable $LANG if $locale == ''.
*/
function _get_default_locale($locale) {
if ($locale == '') // emulate variable support
return getenv('LANG');
else
return $locale;
}
/**
* Sets a requested locale, if needed emulates it.
*/
function _setlocale($category, $locale) {
global $CURRENTLOCALE, $EMULATEGETTEXT;
if ($locale === 0) { // use === to differentiate between string "0"
if ($CURRENTLOCALE != '')
return $CURRENTLOCALE;
else
// obey LANG variable, maybe extend to support all of LC_* vars
// even if we tried to read locale without setting it first
return _setlocale($category, $CURRENTLOCALE);
} else {
if (function_exists('setlocale')) {
$ret = setlocale($category, $locale);
if (($locale == '' and !$ret) or // failed setting it by env
($locale != '' and $ret != $locale)) { // failed setting it
// Failed setting it according to environment.
$CURRENTLOCALE = _get_default_locale($locale);
$EMULATEGETTEXT = 1;
} else {
$CURRENTLOCALE = $ret;
$EMULATEGETTEXT = 0;
}
} else {
// No function setlocale(), emulate it all.
$CURRENTLOCALE = _get_default_locale($locale);
$EMULATEGETTEXT = 1;
}
// Allow locale to be changed on the go for one translation domain.
global $text_domains, $default_domain;
if (array_key_exists($default_domain, $text_domains)) {
unset($text_domains[$default_domain]->l10n);
}
return $CURRENTLOCALE;
}
}
/**
* Sets the path for a domain.
*/
function _bindtextdomain($domain, $path) {
global $text_domains;
// ensure $path ends with a slash ('/' should work for both, but lets still play nice)
if (substr(php_uname(), 0, 7) == "Windows") {
if ($path[strlen($path)-1] != '\\' and $path[strlen($path)-1] != '/')
$path .= '\\';
} else {
if ($path[strlen($path)-1] != '/')
$path .= '/';
}
if (!array_key_exists($domain, $text_domains)) {
// Initialize an empty domain object.
$text_domains[$domain] = new domain();
}
$text_domains[$domain]->path = $path;
}
/**
* Specify the character encoding in which the messages from the DOMAIN message catalog will be returned.
*/
function _bind_textdomain_codeset($domain, $codeset) {
global $text_domains;
$text_domains[$domain]->codeset = $codeset;
}
/**
* Sets the default domain.
*/
function _textdomain($domain) {
global $default_domain;
$default_domain = $domain;
}
/**
* Lookup a message in the current domain.
*/
function _gettext($msgid) {
$l10n = _get_reader();
return _encode($l10n->translate($msgid));
}
/**
* Alias for gettext.
*/
function __($msgid) {
return _gettext($msgid);
}
/**
* Plural version of gettext.
*/
function _ngettext($singular, $plural, $number) {
$l10n = _get_reader();
return _encode($l10n->ngettext($singular, $plural, $number));
}
/**
* Override the current domain.
*/
function _dgettext($domain, $msgid) {
$l10n = _get_reader($domain);
return _encode($l10n->translate($msgid));
}
/**
* Plural version of dgettext.
*/
function _dngettext($domain, $singular, $plural, $number) {
$l10n = _get_reader($domain);
return _encode($l10n->ngettext($singular, $plural, $number));
}
/**
* Overrides the domain and category for a single lookup.
*/
function _dcgettext($domain, $msgid, $category) {
$l10n = _get_reader($domain, $category);
return _encode($l10n->translate($msgid));
}
/**
* Plural version of dcgettext.
*/
function _dcngettext($domain, $singular, $plural, $number, $category) {
$l10n = _get_reader($domain, $category);
return _encode($l10n->ngettext($singular, $plural, $number));
}
/**
* Context version of gettext.
*/
function _pgettext($context, $msgid) {
$l10n = _get_reader();
return _encode($l10n->pgettext($context, $msgid));
}
/**
* Override the current domain in a context gettext call.
*/
function _dpgettext($domain, $context, $msgid) {
$l10n = _get_reader($domain);
return _encode($l10n->pgettext($context, $msgid));
}
/**
* Overrides the domain and category for a single context-based lookup.
*/
function _dcpgettext($domain, $context, $msgid, $category) {
$l10n = _get_reader($domain, $category);
return _encode($l10n->pgettext($context, $msgid));
}
/**
* Context version of ngettext.
*/
function _npgettext($context, $singular, $plural) {
$l10n = _get_reader();
return _encode($l10n->npgettext($context, $singular, $plural));
}
/**
* Override the current domain in a context ngettext call.
*/
function _dnpgettext($domain, $context, $singular, $plural) {
$l10n = _get_reader($domain);
return _encode($l10n->npgettext($context, $singular, $plural));
}
/**
* Overrides the domain and category for a plural context-based lookup.
*/
function _dcnpgettext($domain, $context, $singular, $plural, $category) {
$l10n = _get_reader($domain, $category);
return _encode($l10n->npgettext($context, $singular, $plural));
}
// Wrappers to use if the standard gettext functions are available,
// but the current locale is not supported by the system.
// Use the standard impl if the current locale is supported, use the
// custom impl otherwise.
function T_setlocale($category, $locale) {
return _setlocale($category, $locale);
}
function T_bindtextdomain($domain, $path) {
if (_check_locale_and_function()) return bindtextdomain($domain, $path);
else return _bindtextdomain($domain, $path);
}
function T_bind_textdomain_codeset($domain, $codeset) {
// bind_textdomain_codeset is available only in PHP 4.2.0+
if (_check_locale_and_function('bind_textdomain_codeset'))
return bind_textdomain_codeset($domain, $codeset);
else return _bind_textdomain_codeset($domain, $codeset);
}
function T_textdomain($domain) {
if (_check_locale_and_function()) return textdomain($domain);
else return _textdomain($domain);
}
function T_gettext($msgid) {
if (_check_locale_and_function()) return gettext($msgid);
else return _gettext($msgid);
}
function T_($msgid) {
if (_check_locale_and_function()) return _($msgid);
return __($msgid);
}
function T_ngettext($singular, $plural, $number) {
if (_check_locale_and_function())
return ngettext($singular, $plural, $number);
else return _ngettext($singular, $plural, $number);
}
function T_dgettext($domain, $msgid) {
if (_check_locale_and_function()) return dgettext($domain, $msgid);
else return _dgettext($domain, $msgid);
}
function T_dngettext($domain, $singular, $plural, $number) {
if (_check_locale_and_function())
return dngettext($domain, $singular, $plural, $number);
else return _dngettext($domain, $singular, $plural, $number);
}
function T_dcgettext($domain, $msgid, $category) {
if (_check_locale_and_function())
return dcgettext($domain, $msgid, $category);
else return _dcgettext($domain, $msgid, $category);
}
function T_dcngettext($domain, $singular, $plural, $number, $category) {
if (_check_locale_and_function())
return dcngettext($domain, $singular, $plural, $number, $category);
else return _dcngettext($domain, $singular, $plural, $number, $category);
}
function T_pgettext($context, $msgid) {
if (_check_locale_and_function('pgettext'))
return pgettext($context, $msgid);
else
return _pgettext($context, $msgid);
}
function T_dpgettext($domain, $context, $msgid) {
if (_check_locale_and_function('dpgettext'))
return dpgettext($domain, $context, $msgid);
else
return _dpgettext($domain, $context, $msgid);
}
function T_dcpgettext($domain, $context, $msgid, $category) {
if (_check_locale_and_function('dcpgettext'))
return dcpgettext($domain, $context, $msgid, $category);
else
return _dcpgettext($domain, $context, $msgid, $category);
}
function T_npgettext($context, $singular, $plural, $number) {
if (_check_locale_and_function('npgettext'))
return npgettext($context, $singular, $plural, $number);
else
return _npgettext($context, $singular, $plural, $number);
}
function T_dnpgettext($domain, $context, $singular, $plural, $number) {
if (_check_locale_and_function('dnpgettext'))
return dnpgettext($domain, $context, $singular, $plural, $number);
else
return _dnpgettext($domain, $context, $singular, $plural, $number);
}
function T_dcnpgettext($domain, $context, $singular, $plural,
$number, $category) {
if (_check_locale_and_function('dcnpgettext'))
return dcnpgettext($domain, $context, $singular,
$plural, $number, $category);
else
return _dcnpgettext($domain, $context, $singular,
$plural, $number, $category);
}
// Wrappers used as a drop in replacement for the standard gettext functions
if (!function_exists('gettext')) {
function bindtextdomain($domain, $path) {
return _bindtextdomain($domain, $path);
}
function bind_textdomain_codeset($domain, $codeset) {
return _bind_textdomain_codeset($domain, $codeset);
}
function textdomain($domain) {
return _textdomain($domain);
}
function gettext($msgid) {
return _gettext($msgid);
}
function _($msgid) {
return __($msgid);
}
function ngettext($singular, $plural, $number) {
return _ngettext($singular, $plural, $number);
}
function dgettext($domain, $msgid) {
return _dgettext($domain, $msgid);
}
function dngettext($domain, $singular, $plural, $number) {
return _dngettext($domain, $singular, $plural, $number);
}
function dcgettext($domain, $msgid, $category) {
return _dcgettext($domain, $msgid, $category);
}
function dcngettext($domain, $singular, $plural, $number, $category) {
return _dcngettext($domain, $singular, $plural, $number, $category);
}
function pgettext($context, $msgid) {
return _pgettext($context, $msgid);
}
function npgettext($context, $singular, $plural, $number) {
return _npgettext($context, $singular, $plural, $number);
}
function dpgettext($domain, $context, $msgid) {
return _dpgettext($domain, $context, $msgid);
}
function dnpgettext($domain, $context, $singular, $plural, $number) {
return _dnpgettext($domain, $context, $singular, $plural, $number);
}
function dcpgettext($domain, $context, $msgid, $category) {
return _dcpgettext($domain, $context, $msgid, $category);
}
function dcnpgettext($domain, $context, $singular, $plural,
$number, $category) {
return _dcnpgettext($domain, $context, $singular, $plural,
$number, $category);
}
}
?>

View File

@ -1,432 +0,0 @@
<?php
/*
Copyright (c) 2003, 2009 Danilo Segan <danilo@kvota.net>.
Copyright (c) 2005 Nico Kaiser <nico@siriux.net>
This file is part of PHP-gettext.
PHP-gettext 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 2 of the License, or
(at your option) any later version.
PHP-gettext 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 PHP-gettext; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/**
* Provides a simple gettext replacement that works independently from
* the system's gettext abilities.
* It can read MO files and use them for translating strings.
* The files are passed to gettext_reader as a Stream (see streams.php)
*
* This version has the ability to cache all strings and translations to
* speed up the string lookup.
* While the cache is enabled by default, it can be switched off with the
* second parameter in the constructor (e.g. whenusing very large MO files
* that you don't want to keep in memory)
*/
class gettext_reader {
//public:
var $error = 0; // public variable that holds error code (0 if no error)
//private:
var $BYTEORDER = 0; // 0: low endian, 1: big endian
var $STREAM = NULL;
var $short_circuit = false;
var $enable_cache = false;
var $originals = NULL; // offset of original table
var $translations = NULL; // offset of translation table
var $pluralheader = NULL; // cache header field for plural forms
var $total = 0; // total string count
var $table_originals = NULL; // table for original strings (offsets)
var $table_translations = NULL; // table for translated strings (offsets)
var $cache_translations = NULL; // original -> translation mapping
/* Methods */
/**
* Reads a 32bit Integer from the Stream
*
* @access private
* @return Integer from the Stream
*/
function readint() {
if ($this->BYTEORDER == 0) {
// low endian
$input=unpack('V', $this->STREAM->read(4));
return array_shift($input);
} else {
// big endian
$input=unpack('N', $this->STREAM->read(4));
return array_shift($input);
}
}
function read($bytes) {
return $this->STREAM->read($bytes);
}
/**
* Reads an array of Integers from the Stream
*
* @param int count How many elements should be read
* @return Array of Integers
*/
function readintarray($count) {
if ($this->BYTEORDER == 0) {
// low endian
return unpack('V'.$count, $this->STREAM->read(4 * $count));
} else {
// big endian
return unpack('N'.$count, $this->STREAM->read(4 * $count));
}
}
/**
* Constructor
*
* @param object Reader the StreamReader object
* @param boolean enable_cache Enable or disable caching of strings (default on)
*/
function __construct($Reader, $enable_cache = true) {
// If there isn't a StreamReader, turn on short circuit mode.
if (! $Reader || isset($Reader->error) ) {
$this->short_circuit = true;
return;
}
// Caching can be turned off
$this->enable_cache = $enable_cache;
$MAGIC1 = "\x95\x04\x12\xde";
$MAGIC2 = "\xde\x12\x04\x95";
$this->STREAM = $Reader;
$magic = $this->read(4);
if ($magic == $MAGIC1) {
$this->BYTEORDER = 1;
} elseif ($magic == $MAGIC2) {
$this->BYTEORDER = 0;
} else {
$this->error = 1; // not MO file
return false;
}
// FIXME: Do we care about revision? We should.
$revision = $this->readint();
$this->total = $this->readint();
$this->originals = $this->readint();
$this->translations = $this->readint();
}
/**
* Loads the translation tables from the MO file into the cache
* If caching is enabled, also loads all strings into a cache
* to speed up translation lookups
*
* @access private
*/
function load_tables() {
if (is_array($this->cache_translations) &&
is_array($this->table_originals) &&
is_array($this->table_translations))
return;
/* get original and translations tables */
if (!is_array($this->table_originals)) {
$this->STREAM->seekto($this->originals);
$this->table_originals = $this->readintarray($this->total * 2);
}
if (!is_array($this->table_translations)) {
$this->STREAM->seekto($this->translations);
$this->table_translations = $this->readintarray($this->total * 2);
}
if ($this->enable_cache) {
$this->cache_translations = array ();
/* read all strings in the cache */
for ($i = 0; $i < $this->total; $i++) {
$this->STREAM->seekto($this->table_originals[$i * 2 + 2]);
$original = $this->STREAM->read($this->table_originals[$i * 2 + 1]);
$this->STREAM->seekto($this->table_translations[$i * 2 + 2]);
$translation = $this->STREAM->read($this->table_translations[$i * 2 + 1]);
$this->cache_translations[$original] = $translation;
}
}
}
/**
* Returns a string from the "originals" table
*
* @access private
* @param int num Offset number of original string
* @return string Requested string if found, otherwise ''
*/
function get_original_string($num) {
$length = $this->table_originals[$num * 2 + 1];
$offset = $this->table_originals[$num * 2 + 2];
if (! $length)
return '';
$this->STREAM->seekto($offset);
$data = $this->STREAM->read($length);
return (string)$data;
}
/**
* Returns a string from the "translations" table
*
* @access private
* @param int num Offset number of original string
* @return string Requested string if found, otherwise ''
*/
function get_translation_string($num) {
$length = $this->table_translations[$num * 2 + 1];
$offset = $this->table_translations[$num * 2 + 2];
if (! $length)
return '';
$this->STREAM->seekto($offset);
$data = $this->STREAM->read($length);
return (string)$data;
}
/**
* Binary search for string
*
* @access private
* @param string string
* @param int start (internally used in recursive function)
* @param int end (internally used in recursive function)
* @return int string number (offset in originals table)
*/
function find_string($string, $start = -1, $end = -1) {
if (($start == -1) or ($end == -1)) {
// find_string is called with only one parameter, set start end end
$start = 0;
$end = $this->total;
}
if (abs($start - $end) <= 1) {
// We're done, now we either found the string, or it doesn't exist
$txt = $this->get_original_string($start);
if ($string == $txt)
return $start;
else
return -1;
} else if ($start > $end) {
// start > end -> turn around and start over
return $this->find_string($string, $end, $start);
} else {
// Divide table in two parts
$half = (int)(($start + $end) / 2);
$cmp = strcmp($string, $this->get_original_string($half));
if ($cmp == 0)
// string is exactly in the middle => return it
return $half;
else if ($cmp < 0)
// The string is in the upper half
return $this->find_string($string, $start, $half);
else
// The string is in the lower half
return $this->find_string($string, $half, $end);
}
}
/**
* Translates a string
*
* @access public
* @param string string to be translated
* @return string translated string (or original, if not found)
*/
function translate($string) {
if ($this->short_circuit)
return $string;
$this->load_tables();
if ($this->enable_cache) {
// Caching enabled, get translated string from cache
if (array_key_exists($string, $this->cache_translations))
return $this->cache_translations[$string];
else
return $string;
} else {
// Caching not enabled, try to find string
$num = $this->find_string($string);
if ($num == -1)
return $string;
else
return $this->get_translation_string($num);
}
}
/**
* Sanitize plural form expression for use in PHP eval call.
*
* @access private
* @return string sanitized plural form expression
*/
function sanitize_plural_expression($expr) {
// Get rid of disallowed characters.
$expr = preg_replace('@[^a-zA-Z0-9_:;\(\)\?\|\&=!<>+*/\%-]@', '', $expr);
// Add parenthesis for tertiary '?' operator.
$expr .= ';';
$res = '';
$p = 0;
for ($i = 0; $i < strlen($expr); $i++) {
$ch = $expr[$i];
switch ($ch) {
case '?':
$res .= ' ? (';
$p++;
break;
case ':':
$res .= ') : (';
break;
case ';':
$res .= str_repeat( ')', $p) . ';';
$p = 0;
break;
default:
$res .= $ch;
}
}
return $res;
}
/**
* Parse full PO header and extract only plural forms line.
*
* @access private
* @return string verbatim plural form header field
*/
function extract_plural_forms_header_from_po_header($header) {
if (preg_match("/(^|\n)plural-forms: ([^\n]*)\n/i", $header, $regs))
$expr = $regs[2];
else
$expr = "nplurals=2; plural=n == 1 ? 0 : 1;";
return $expr;
}
/**
* Get possible plural forms from MO header
*
* @access private
* @return string plural form header
*/
function get_plural_forms() {
// lets assume message number 0 is header
// this is true, right?
$this->load_tables();
// cache header field for plural forms
if (! is_string($this->pluralheader)) {
if ($this->enable_cache) {
$header = $this->cache_translations[""];
} else {
$header = $this->get_translation_string(0);
}
$expr = $this->extract_plural_forms_header_from_po_header($header);
$this->pluralheader = $this->sanitize_plural_expression($expr);
}
return $this->pluralheader;
}
/**
* Detects which plural form to take
*
* @access private
* @param n count
* @return int array index of the right plural form
*/
function select_string($n) {
$string = $this->get_plural_forms();
$string = str_replace('nplurals',"\$total",$string);
$string = str_replace("n",$n,$string);
$string = str_replace('plural',"\$plural",$string);
$total = 0;
$plural = 0;
eval("$string");
if ($plural >= $total) $plural = $total - 1;
return $plural;
}
/**
* Plural version of gettext
*
* @access public
* @param string single
* @param string plural
* @param string number
* @return translated plural form
*/
function ngettext($single, $plural, $number) {
if ($this->short_circuit) {
if ($number != 1)
return $plural;
else
return $single;
}
// find out the appropriate form
$select = $this->select_string($number);
// this should contains all strings separated by NULLs
$key = $single . chr(0) . $plural;
if ($this->enable_cache) {
if (! array_key_exists($key, $this->cache_translations)) {
return ($number != 1) ? $plural : $single;
} else {
$result = $this->cache_translations[$key];
$list = explode(chr(0), $result);
return $list[$select];
}
} else {
$num = $this->find_string($key);
if ($num == -1) {
return ($number != 1) ? $plural : $single;
} else {
$result = $this->get_translation_string($num);
$list = explode(chr(0), $result);
return $list[$select];
}
}
}
function pgettext($context, $msgid) {
$key = $context . chr(4) . $msgid;
$ret = $this->translate($key);
if (strpos($ret, "\004") !== FALSE) {
return $msgid;
} else {
return $ret;
}
}
function npgettext($context, $singular, $plural, $number) {
$key = $context . chr(4) . $singular;
$ret = $this->ngettext($key, $plural, $number);
if (strpos($ret, "\004") !== FALSE) {
return $singular;
} else {
return $ret;
}
}
}
?>

View File

@ -1,167 +0,0 @@
<?php
/*
Copyright (c) 2003, 2005, 2006, 2009 Danilo Segan <danilo@kvota.net>.
This file is part of PHP-gettext.
PHP-gettext 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 2 of the License, or
(at your option) any later version.
PHP-gettext 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 PHP-gettext; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// Simple class to wrap file streams, string streams, etc.
// seek is essential, and it should be byte stream
class StreamReader {
// should return a string [FIXME: perhaps return array of bytes?]
function read($bytes) {
return false;
}
// should return new position
function seekto($position) {
return false;
}
// returns current position
function currentpos() {
return false;
}
// returns length of entire stream (limit for seekto()s)
function length() {
return false;
}
};
class StringReader {
var $_pos;
var $_str;
function __construct($str='') {
$this->_str = $str;
$this->_pos = 0;
}
function read($bytes) {
$data = substr($this->_str, $this->_pos, $bytes);
$this->_pos += $bytes;
if (strlen($this->_str)<$this->_pos)
$this->_pos = strlen($this->_str);
return $data;
}
function seekto($pos) {
$this->_pos = $pos;
if (strlen($this->_str)<$this->_pos)
$this->_pos = strlen($this->_str);
return $this->_pos;
}
function currentpos() {
return $this->_pos;
}
function length() {
return strlen($this->_str);
}
};
class FileReader {
var $_pos;
var $_fd;
var $_length;
function __construct($filename) {
if (file_exists($filename)) {
$this->_length=filesize($filename);
$this->_pos = 0;
$this->_fd = fopen($filename,'rb');
if (!$this->_fd) {
$this->error = 3; // Cannot read file, probably permissions
return false;
}
} else {
$this->error = 2; // File doesn't exist
return false;
}
}
function read($bytes) {
if ($bytes) {
fseek($this->_fd, $this->_pos);
// PHP 5.1.1 does not read more than 8192 bytes in one fread()
// the discussions at PHP Bugs suggest it's the intended behaviour
$data = '';
while ($bytes > 0) {
$chunk = fread($this->_fd, $bytes);
$data .= $chunk;
$bytes -= strlen($chunk);
}
$this->_pos = ftell($this->_fd);
return $data;
} else return '';
}
function seekto($pos) {
fseek($this->_fd, $pos);
$this->_pos = ftell($this->_fd);
return $this->_pos;
}
function currentpos() {
return $this->_pos;
}
function length() {
return $this->_length;
}
function close() {
fclose($this->_fd);
}
};
// Preloads entire file in memory first, then creates a StringReader
// over it (it assumes knowledge of StringReader internals)
class CachedFileReader extends StringReader {
function __construct($filename) {
if (file_exists($filename)) {
$length=filesize($filename);
$fd = fopen($filename,'rb');
if (!$fd) {
$this->error = 3; // Cannot read file, probably permissions
return false;
}
$this->_str = fread($fd, $length);
fclose($fd);
} else {
$this->error = 2; // File doesn't exist
return false;
}
}
};
?>

View File

@ -1,85 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<PodcastGenerator>
<mediaFile>
<extension>mp3</extension>
<mimetype>audio/mpeg</mimetype>
</mediaFile>
<mediaFile>
<extension>mpg</extension>
<mimetype>video/mpeg</mimetype>
</mediaFile>
<mediaFile>
<extension>mpeg</extension>
<mimetype>video/mpeg</mimetype>
</mediaFile>
<mediaFile>
<extension>mov</extension>
<mimetype>video/quicktime</mimetype>
</mediaFile>
<mediaFile>
<extension>wav</extension>
<mimetype>audio/x-wav</mimetype>
</mediaFile>
<mediaFile>
<extension>wma</extension>
<mimetype>audio/x-ms-wma</mimetype>
</mediaFile>
<mediaFile>
<extension>wmv</extension>
<mimetype>video/x-ms-wmv</mimetype>
</mediaFile>
<mediaFile>
<extension>ogg</extension>
<mimetype>application/ogg</mimetype>
</mediaFile>
<mediaFile>
<extension>mp4</extension>
<mimetype>video/mp4</mimetype>
</mediaFile>
<mediaFile>
<extension>asf</extension>
<mimetype>video/x-ms-asf</mimetype>
</mediaFile>
<mediaFile>
<extension>avi</extension>
<mimetype>video/x-msvideo</mimetype>
</mediaFile>
<mediaFile>
<extension>flv</extension>
<mimetype>video/x-flv</mimetype>
</mediaFile>
<mediaFile>
<extension>jpg</extension>
<mimetype>image/jpeg</mimetype>
</mediaFile>
<mediaFile>
<extension>jpeg</extension>
<mimetype>image/jpeg</mimetype>
</mediaFile>
<mediaFile>
<extension>pdf</extension>
<mimetype>application/pdf</mimetype>
</mediaFile>
<mediaFile>
<extension>aif</extension>
<mimetype>audio/x-aiff</mimetype>
</mediaFile>
<mediaFile>
<extension>aiff</extension>
<mimetype>audio/x-aiff</mimetype>
</mediaFile>
<mediaFile>
<extension>m4a</extension>
<mimetype>audio/x-m4a</mimetype>
</mediaFile>
<mediaFile>
<extension>m4v</extension>
<mimetype>video/x-m4v</mimetype>
</mediaFile>
<mediaFile>
<extension>epub</extension>
<mimetype>application/epub+zip</mimetype>
</mediaFile>
</PodcastGenerator>

View File

@ -1,15 +0,0 @@
<?php
############################################################
# PODCAST GENERATOR
#
# Created by Alberto Betella
# http://www.podcastgenerator.net
#
# This is Free Software released under the GNU/GPL License.
############################################################
### HERE IS DEFINED PODCASTGEN VERSION
$podcastgen_version = "2.7";
?>

View File

@ -1,212 +0,0 @@
<?php
############################################################
# PODCAST GENERATOR
#
# Created by Alberto Betella
# http://www.podcastgenerator.net
#
# This is Free Software released under the GNU/GPL License.
############################################################
########### Security code, avoids cross-site scripting (Register Globals ON)
if (isset($_REQUEST['GLOBALS']) OR isset($_REQUEST['absoluteurl']) OR isset($_REQUEST['amilogged']) OR isset($_REQUEST['theme_path'])) { exit; }
########### End
if (isset($_GET['p'])) if ($_GET['p']=="admin") { // if admin is called from the script in a GET variable - security issue
include("$absoluteurl"."core/admin/login.php");
# SET PODCAST FEED URL
if (isset($feed_URL_replace) AND $feed_URL_replace != "") {
$podcastFeedURL = $feed_URL_replace;
} else {
$podcastFeedURL = $url.$feed_dir.'feed.xml';
}
// check if user is already logged in
if(isUserLogged()) {
if (isset($_GET['do']) AND $_GET['do']=="ftpfeature") {
$PG_mainbody .= '<div class=" episodebox">';
include("$absoluteurl"."core/admin/ftpfeature.php");
$PG_mainbody .= '</div>'; //close episodebox
}
elseif (isset($_GET['do']) AND $_GET['do']=="generate") {
$PG_mainbody .= '<div class=" episodebox">';
include("$absoluteurl"."core/admin/feedgenerate.php");
$PG_mainbody .= '</div>'; //close episodebox
}
elseif (isset($_GET['do']) AND $_GET['do']=="upload") {
$PG_mainbody .= '<div class=" episodebox">';
include("$absoluteurl"."core/admin/upload.php");
$PG_mainbody .= '</div>'; //close episodebox
}
/*
elseif (isset($_GET['do']) AND $_GET['do']=="editdel") {
include("$absoluteurl"."core/admin/editdel.php");
}
*/
elseif (isset($_GET['do']) AND $_GET['do']=="edit") {
$PG_mainbody .= '<div class=" episodebox">';
include("$absoluteurl"."core/admin/edit.php");
$PG_mainbody .= '</div>'; //close episodebox
}
elseif (isset($_GET['do']) AND $_GET['do']=="delete") {
$PG_mainbody .= '<div class=" episodebox">';
include("$absoluteurl"."core/admin/delete.php");
$PG_mainbody .= '</div>'; //close episodebox
}
elseif (isset($_GET['do']) AND $_GET['do']=="categories") {
$PG_mainbody .= '<div class=" episodebox">';
include("$absoluteurl"."core/admin/categories.php");
$PG_mainbody .= '</div>'; //close episodebox
}
elseif (isset($_GET['do']) AND $_GET['do']=="freebox") {
$PG_mainbody .= '<div class=" episodebox">';
include("$absoluteurl"."core/admin/freebox.php");
$PG_mainbody .= '</div>'; //close episodebox
}
elseif (isset($_GET['do']) AND $_GET['do']=="theme") {
$PG_mainbody .= '<div class=" episodebox">';
include("$absoluteurl"."core/admin/selecttheme.php");
$PG_mainbody .= '</div>'; //close episodebox
}
elseif (isset($_GET['do']) AND $_GET['do']=="itunesimg") {
$PG_mainbody .= '<div class=" episodebox">';
include("$absoluteurl"."core/admin/itunesimg.php");
$PG_mainbody .= '</div>'; //close episodebox
}
elseif (isset($_GET['do']) AND $_GET['do']=="itunescat") {
$PG_mainbody .= '<div class=" episodebox">';
include("$absoluteurl"."core/admin/itunescategories.php");
$PG_mainbody .= '</div>'; //close episodebox
}
elseif (isset($_GET['do']) AND $_GET['do']=="changedetails") {
$PG_mainbody .= '<div class=" episodebox">';
include("$absoluteurl"."core/admin/podcastdetails.php");
$PG_mainbody .= '</div>'; //close episodebox
}
elseif (isset($_GET['do']) AND $_GET['do']=="config") {
$PG_mainbody .= '<div class=" episodebox">';
include("$absoluteurl"."core/admin/scriptconfig.php");
$PG_mainbody .= '</div>'; //close episodebox
}
elseif (isset($_GET['do']) AND $_GET['do']=="serverinfo") {
$PG_mainbody .= '<div class=" episodebox">';
include("$absoluteurl"."core/admin/server_info.php");
$PG_mainbody .= '</div>'; //close episodebox
}
else {
if (isset($firsttimehere) AND $firsttimehere == "yes") { // if it's the first time (parameter specified in config.php)
$PG_mainbody .= "
<div class=\"topseparator episodebox\">
<h3>"._("Welcome")."</h3>
<p><i>"._("This is possibly the first time you have entered this page: you haven't changed your podcast details yet. You are reccommended to provide a podcast title, description, etc... Try a different theme!")."</i> <a href=\"?p=admin&amp;do=changedetails\"><b>"._("Start now...")."</b></a></p>
</div>";
}
$PG_mainbody .= '
<div class="topseparator episodebox">
<h3>'._("Episodes").'</h3>
<ul>
<li><a href="?p=admin&amp;do=upload">'._("Upload New Episode").'</a></li>
<li><a href="?p=archive&amp;cat=all&amp;noextras">'._("Edit / Delete Episodes").'</a></li>';
if ($categoriesenabled == "yes") { //if categories are enabled in config.php
$PG_mainbody .= '
<li><a href="?p=admin&amp;do=categories">'._("Manage categories").'</a></li>';
} // end if categories enabled
$PG_mainbody .= '
<li><a href="?p=admin&do=ftpfeature">'._("FTP Feature").' '._("(Auto Indexing)").'</a></li>
<li><a href="?p=admin&do=generate">'._("Manually regenerate RSS feed").'</a></li>
</ul>
</div>';
$PG_mainbody .= '<div class="topseparator episodebox">
<h3>'._("Themes and aspect").'</h3>
<ul>
<li><a href="?p=admin&do=theme">'._("Change Theme").'</a></li>';
//Frebox
if ($freebox == "yes") { $PG_mainbody .= '<li><a href="?p=admin&do=freebox">'._("Customize your FreeBox").'</a></li>'; }
$PG_mainbody .= '</ul>
</div>
<div class="topseparator episodebox">
<h3>'._("iTunes Store Settings").'</h3>
<ul>
<li><a href="?p=admin&do=itunesimg">'._("Change iTunes Cover Art").'</a></li>
<li><a href="?p=admin&do=itunescat">'._("Select or change iTunes Categories").'</a></li>
<li><a href="https://podcastsconnect.apple.com/" target="_blank">'._("Submit your podcast to the iTunes Store").'</a></li>
</ul>
</div>
<div class="topseparator episodebox">
<h3>'._("Your podcast details").'</h3>
<ul>
<li><a href="?p=admin&do=changedetails">'._("Change your podcast details").'</a></li>
<li><a href="http://validator.w3.org/feed/check.cgi?url='.$podcastFeedURL.'" target="_blank">'._("Validate this feed with w3c validation service").'</a></li>
</ul>
</div>
<div class="topseparator episodebox">
<h3>'._("Podcast Generator Configuration").'</h3>
<ul>
<li><a href="?p=admin&do=config">'._("Change Podcast Generator Configuration").'</a></li>
</ul>
</div>
';
##### Display PodcastGen news
if ($enablepgnewsinadmin == "yes") { //if display news is enabled in config.php
$PG_mainbody .= '<div class="topseparator">
<h3>'._("Podcast Generator News").'</h3>';
include("$absoluteurl"."core/admin/pgRSSnews.php"); // display the latest RSS news of podcastgen
$PG_mainbody .= '</div>';
} // end if rss news enabled
####
}
}
}
?>

View File

@ -1,121 +0,0 @@
<?php
############################################################
# PODCAST GENERATOR
#
# Created by Alberto Betella
# http://www.podcastgenerator.net
#
# This is Free Software released under the GNU/GPL License.
############################################################
########### Security code, avoids cross-site scripting (Register Globals ON)
if (isset($_REQUEST['GLOBALS']) OR isset($_REQUEST['absoluteurl']) OR isset($_REQUEST['amilogged']) OR isset($_REQUEST['theme_path'])) { exit; }
########### End
### Check if user is logged ###
if (!isUserLogged()) { exit; }
###
if ($categoriesenabled == "yes") { /////// if categories are enabled in config.php
if (isset($_GET['do']) AND $_GET['do']=="categories" AND isset($_GET['action']) AND $_GET['action']=="add") { // if add a category
include ("$absoluteurl"."core/admin/categories_add.php");
}
elseif (isset($_GET['do']) AND $_GET['do']=="categories" AND isset($_GET['action']) AND $_GET['action']=="del") { // if remove a category
include ("$absoluteurl"."core/admin/categories_remove.php");
}
else { //001 (If no add or remove display main categories page)
$PG_mainbody .= "<h3>"._("Add / Delete categories")."</h3>";
$PG_mainbody .= '<span class="alert">'._("Hint: You don't need categories?").' <a href="?p=admin&do=config#setcategoriesfeature">'._("Disable them").'</a></span>';
/*
include ("$absoluteurl"."components/xmlparser/loadparser.php");
*/
include ("$absoluteurl"."core/admin/readXMLcategories.php");
if (file_exists("$absoluteurl"."categories.xml")) {
######
$PG_mainbody .= '
<form action="?p=admin&amp;do=categories&amp;action=add" method="POST" enctype="multipart/form-data" name="categoryform" id="categoryform" onsubmit="return submitForm();">
<br /><br />
<label for="addcategory"><b>'._("Add a new category:").'</b></label><br />
<input name="addcategory" id="addcategory" type="text" size="50" maxlength="255" ><br />
<input type="submit" value="'._("Add").'" class="btn btn-success btn-small" onClick="showNotify(\''._("Adding...").'\');">
';
#####
$PG_mainbody .= "<br /><br /><p><b>"._("Delete Categories")."</b> ($n)</p>";
$PG_mainbody .= "<ul>";
natcasesort($arr); // Natcasesort orders more naturally and is different from "sort", which is case sensitive
foreach ($arr as $key => $val) {
//$PG_mainbody .= "cat[" . $key . "] = " . $val . "<br>";;
$val = ampersandEntitiesConvert($val); // convert ampersands
$PG_mainbody .= '<li style="margin-bottom:10px;">' . $val . ' ';
// $PG_mainbody .= '<a id="confirmdelete" href="javascript:Effect.toggle(\''.$arrid[$key].'\',\'appear\');">['._("Delete").']</a></li>';
$PG_mainbody .= '<input type="button" id="confirmdelete-'.$arrid[$key].'" value="'._("Delete Category").'" class="btn btn-warning btn-mini" /></li>';
$PG_mainbody .= '<div id="confirmation-'.$arrid[$key].'" style="display:none;"><b>'._("Do you really want to permanently delete this category?").'</b><p>'._("Yes").' <input type="radio" name="'._("Delete").' '.$val.'" value="yes" onClick="showNotify(\''._("Deleting...").'\');location.href=\'?p=admin&do=categories&action=del&cat='.$arrid[$key].'\';"> &nbsp;&nbsp; '._("No").' <input type="radio" name="'._("No").'" value="no" onclick="$(\'#confirmation-'.$arrid[$key].'\').fadeOut();" />
</p>
</div>
';
}
$PG_mainbody .= '</ul>
';
} //if xml categories file doesn't exist
else
{
$PG_mainbody .= '<p><b>'._("Categories file doesn't exist or empty...").'</b></p>';
$PG_mainbody .= '
<form action="?p=admin&amp;do=categories&amp;action=add" method="POST" enctype="multipart/form-data" name="categoryform" id="categoryform" onsubmit="return submitForm();">
<br /><br />
<label for="addcategory"><b>'._("Add a new category:").'</b></label><br />
<input name="addcategory" id="addcategory" type="text" size="50" maxlength="255" ><br />
<input type="submit" value="'._("Add").'" class="btn btn-success btn-small" onClick="showNotify(\''._("Adding...").'\');">
';
}
} //001
} /////// end if categories enabled
else {
$PG_mainbody .= _("Categories disabled");
}
?>

View File

@ -1,146 +0,0 @@
<?php
############################################################
# PODCAST GENERATOR
#
# Created by Alberto Betella
# http://www.podcastgenerator.net
#
# This is Free Software released under the GNU/GPL License.
############################################################
########### Security code, avoids cross-site scripting (Register Globals ON)
if (isset($_REQUEST['GLOBALS']) OR isset($_REQUEST['absoluteurl']) OR isset($_REQUEST['amilogged']) OR isset($_REQUEST['theme_path'])) { exit; }
########### End
### Check if user is logged ###
if (!isUserLogged()) { exit; }
###
$PG_mainbody .= '<h3>'._("Add a category").'</h3>';
//include ("$absoluteurl"."components/xmlparser/loadparser.php");
//include ("$absoluteurl"."core/admin/readXMLcategories.php");
// define variables
$arrdesc = NULL;
$arrid = NULL;
$isduplicated = NULL;
$n = 0; // counter
$add = $_POST['addcategory']; // variable
// Depurate input
$add = stripslashes($add);
$add = htmlspecialchars($add);
$add = depurateContent($add);
if ($add != NULL and $add != "all") { /// 000
// create unique and depurated id from the description (using the function renamefilestrict)
$id = avoidXSS(renamefilestrict($add)); //deletes also accents
$id = ampersandRemove($id); //ampersand create issues
if (strlen($id) < 3) {
$suffix = random_str(5);
$id = $id.$suffix;
}
$parser = simplexml_load_file($absoluteurl."categories.xml",'SimpleXMLElement',LIBXML_NOCDATA);
//parse
// if (isset($parser->document->category)) {
foreach($parser->category as $singlecategory)
{
// echo $singlecategory->id[0]->tagData."<br>";
// echo $singlecategory->description[0]->tagData;
// echo "<br><br>";
if ($id != $singlecategory->id[0] AND $add !=$singlecategory->description[0]) { // if the id of the new category is different from the ids already present in the XML file and if the description is different (e.g. the description is compared cause the id is generated with random characters in case of conversion from japanese, corean etc...
// put into the array
$arrdesc[] .= htmlspecialchars($singlecategory->description[0]); // Encode special characters
$arrid[] .= $singlecategory->id[0];
}
else { // if ID already present in XML
$isduplicated = TRUE; // assign duplicated label
}
$n++; //increment count
}
// }
if ($isduplicated != TRUE) { // 001 if new category doesn't exist yet
$arrdesc[] .= $add; //Description
$arrid[] .= $id; // create Id
//echo "<br>tot elementi $n<BR>";
$xmlfiletocreate = '<?xml version="1.0" encoding="'.$feed_encoding.'"?>
<PodcastGenerator>';
foreach ($arrdesc as $key => $val) {
// echo "cat[" . $key . "] = " . $val . "<br>";
// echo $key."<br>";
$xmlfiletocreate .= '
<category>
<id>'.$arrid[$key].'</id>
<description>'.$val.'</description>
</category>';
}
$xmlfiletocreate .= '
</PodcastGenerator>';
/////////////////////
// WRITE THE XML FILE
$fp = fopen("categories.xml",'w+'); //open desc file or create it
fwrite($fp,$xmlfiletocreate);
fclose($fp);
$PG_mainbody .= '<p>'._("New category:").' <i>'.$val.'</i></p>';
$PG_mainbody .= '<p><b>'._("Category added!").'</b></p><p><a href="?p=admin&do=categories">'._("Back to category management").'</a>';
} // 001 end
else { //if new category already exists
$PG_mainbody .= _("The category you are trying to add already exists...").'<br /><br />
<form>
<input type="button" value="&laquo; '._("Back").'" onClick="history.back()" class="btn btn-danger btn-small" />
</form>';
}
} // 000
else { // if POST is empty or is = to the word "all", which is already taken to show all podcasts
$PG_mainbody .= _("Please write a category name...").'
<br /><br />
<form>
<input type="button" value="&laquo; '._("Back").'" onClick="history.back()" class="btn btn-danger btn-small" />
</form>';
}
?>

View File

@ -1,128 +0,0 @@
<?php
############################################################
# PODCAST GENERATOR
#
# Created by Alberto Betella
# http://www.podcastgenerator.net
#
# This is Free Software released under the GNU/GPL License.
############################################################
########### Security code, avoids cross-site scripting (Register Globals ON)
if (isset($_REQUEST['GLOBALS']) OR isset($_REQUEST['absoluteurl']) OR isset($_REQUEST['amilogged']) OR isset($_REQUEST['theme_path'])) { exit; }
########### End
### Check if user is logged ###
if (!isUserLogged()) { exit; }
###
//include ("$absoluteurl"."components/xmlparser/loadparser.php");
include ("$absoluteurl"."core/admin/readXMLcategories.php");
$PG_mainbody .= '<h3>'._("Delete a category").'</h3>';
// define variables
$arrdesc = NULL;
$arrid = NULL;
$existsinthefeed = NULL;
$n = 0; // counter
$rem = $_GET['cat']; // the variable passed is the category ID
//$PG_mainbody .= "<p>Category: $rem</p>"; //debug
## add depuration here.......
// create unique and depurated id from the description (use the function here) - the variable should already be in this format, but we perform this function anyway
$id = preg_replace("[^a-z0-9._]", "", str_replace(" ", "_", str_replace("%20", "_", strtolower($rem))));
//parse
if (isset($parser->category)) {
foreach($parser->category as $singlecategory)
{
// echo $singlecategory->id[0]->tagData."<br>";
// echo $singlecategory->description[0]->tagData;
// echo "<br><br>";
if ($id != ($singlecategory->id[0])) { // if the id of the new category is different from the ids already present in the XML file
// put into the array
//(yeah yeah I know I'm using arrays instead of XML commands... but I thought this solution, and it works...). If you have a more elegant solution (e.g. PHP native XML commands), please re-code this file and send your work to me under GPL license: beta@yellowjug.com (PS. your solution should work perfectly either with PHP 4 and 5, otherwise I won't be able to include it in the new releases of podcast generator)
$arrdesc[] .= htmlspecialchars($singlecategory->description[0]); // Encode special characters
$arrid[] .= $singlecategory->id[0];
}
else { // if ID already present in XML
$existsinthefeed = "yes"; // assign duplicated label
$duplicatedarrid = $singlecategory->id[0]; // set the the already present id name into a variable
}
$n++; //increment count
}
}
if ($existsinthefeed == "yes") { // 001 if the category already exists in the XML file proceed to delete (I use an "Ignore process")
$arrdesc[] .= $rem; //Description
$PG_mainbody .= '<p><b>'._("Category deleted").'</b></p><p><a href="?p=admin&do=categories">'._("Back to category management").'</a>';
$arrid[] .= $id; // create Id
//echo "<br>tot elementi $n<BR>";
$xmlfiletocreate = '<?xml version="1.0" encoding="'.$feed_encoding.'"?>
<PodcastGenerator>';
foreach ($arrdesc as $key => $val) {
// echo "cat[" . $key . "] = " . $val . "<br>";
//echo $key."<br>";
// explanation of the following if:
// if the category in this foreach cicle is not the one user wants to delete, then include it in the XML file... (if it is THE ONE, it doesn't include.. It Ignores it, the result will be the exclusion from the new XML file generated)
if ($duplicatedarrid != $arrid[$key]) { ////
$xmlfiletocreate .= '
<category>
<id>'.$arrid[$key].'</id>
<description>'.$val.'</description>
</category>';
} ////
} //end foreach cicle
$xmlfiletocreate .= '
</PodcastGenerator>';
/////////////////////
// WRITE THE XML FILE
$fp = fopen("categories.xml",'w+'); //open desc file or create it
fwrite($fp,$xmlfiletocreate);
fclose($fp);
} // 001 end
else { //if category doesn't exist in the XML
$PG_mainbody .= _("The category doesn't exist...").'<br /><br />
<p><a href="?p=admin&do=categories">'._("Back to category management").'</a>';
}
?>

View File

@ -1,156 +0,0 @@
<?php
############################################################
# PODCAST GENERATOR
#
# Created by Alberto Betella
# http://www.podcastgenerator.net
#
# This is Free Software released under the GNU/GPL License.
############################################################
########### Security code, avoids cross-site scripting (Register Globals ON)
if (isset($_REQUEST['GLOBALS']) OR isset($_REQUEST['absoluteurl']) OR isset($_REQUEST['amilogged']) OR isset($_REQUEST['theme_path'])) { exit; }
########### End
if(isUserLogged()) { //if logged
if(strpos(PHP_OS, "WIN") !== false) { //if we are in a windows environment...
$absoluteurl = addslashes($absoluteurl); // double slashes
}
include ("$absoluteurl"."core/admin/VERSION.php"); //read PodcastGenerator version
// Social networks are handled independently (through array) in the config.php file, so more can be added in future and some can also be excluded in the config file.
$social_networks_active_buttons = NULL;
foreach ($enablesocialnetworks as $singlesocialnetwork) {$social_networks_active_buttons .= $singlesocialnetwork.","; }
//New vars introduced in 2.2 This avoid a notice when upgrade
if (!isset($feed_iTunes_LINKS_Website)) $feed_iTunes_LINKS_Website = "";
if (!isset($feed_URL_replace)) $feed_URL_replace = "";
if (!isset($feed_iTunes_URL_replace)) $feed_iTunes_URL_replace = "";
if (!isset($first_installation)) $first_installation = time();
//If not existing, generate 8 character key for this PG installation
if (!isset($installationKey)) $installationKey = random_str(8);
// Pg cron
if (!isset($cronAutoIndex)) $cronAutoIndex = 1;
if (!isset($cronAutoRegenerateRSS)) $cronAutoRegenerateRSS = 1;
if (!isset($cronAutoRegenerateRSScacheTime)) $cronAutoRegenerateRSScacheTime = 21600;
//Regenerate the config.php file
$configfiletocreate = '<?php
#################################################################
# Podcast Generator
# http://www.podcastgenerator.net
# developed by Alberto Betella
#
# Config.php file created automatically - v.'.$podcastgen_version.'
$podcastgen_version = "'.$podcastgen_version.'"; // Version
$first_installation = '.$first_installation.';
$installationKey = "'.$installationKey.'";
$scriptlang = "'.$scriptlang.'";
$url = "'.$url.'"; // Complete URL of the script (Trailing slash REQUIRED)
$absoluteurl = "'.$absoluteurl.'"; // Absolute path on the server (Trailing slash REQUIRED)
$theme_path = "'.$theme_path.'";
$username = "'.$username.'";
$userpassword = "'.$userpassword.'";
$max_upload_form_size = "'.$max_upload_form_size.'"; //e.g.: "30000000" (about 30MB)
$upload_dir = "'.$upload_dir.'"; // "media/" the default folder (Trailing slash required). Set chmod 755
$img_dir = "'.$img_dir.'"; // (Trailing slash required). Set chmod 755
$feed_dir = "'.$feed_dir.'"; // Where to create feed.xml (empty value = root directory). Set chmod 755
$max_recent = '.$max_recent.'; // How many file to show in the home page
$recent_episode_in_feed = "'.$recent_episode_in_feed.'"; // How many file to show in the XML feed (1,2,5 etc.. or "All")
$episodeperpage = '.$episodeperpage.';
$enablestreaming = "'.$enablestreaming.'"; // Enable mp3 streaming? ("yes" or "no")
$enablesocialnetworks = array('.$social_networks_active_buttons.'); // Enable social networks integration? value 1 (true) or 0 (false) for each social network. Array order: Facebook, Twitter, G+
$dateformat = "'.$dateformat.'"; // d-m-Y OR m-d-Y OR Y-m-d
$freebox = "'.$freebox.'"; // enable freely customizable box
$enablehelphints = "'.$enablehelphints.'";
$enablepgnewsinadmin = "'.$enablepgnewsinadmin.'";
$strictfilenamepolicy = "'.$strictfilenamepolicy.'"; // strictly rename files (just characters A to Z and numbers)
$categoriesenabled = "'.$categoriesenabled.'";
$cronAutoIndex = '.$cronAutoIndex.'; //Auto Index New Episodes via Cron
$cronAutoRegenerateRSS = '.$cronAutoRegenerateRSS.'; //Auto regenerate RSS via Cron
$cronAutoRegenerateRSScacheTime = '.$cronAutoRegenerateRSScacheTime.'; //Cache (in seconds)
###################
# XML Feed elements
# The followings specifications will be included in your podcast "feed.xml" file.
$feed_iTunes_LINKS_Website = "'.$feed_iTunes_LINKS_Website.'";
$feed_URL_replace = "'.$feed_URL_replace.'";
$feed_iTunes_URL_replace = "'.$feed_iTunes_URL_replace.'";
$podcast_title = "'.$podcast_title.'";
$podcast_subtitle = "'.$podcast_subtitle.'";
$podcast_description = "'.$podcast_description.'";
$author_name = "'.$author_name.'";
$author_email = "'.$author_email.'";
$itunes_category[0] = "'.$itunes_category[0].'"; // iTunes categories (mainCategory:subcategory)
$itunes_category[1] = "'.$itunes_category[1].'";
$itunes_category[2] = "'.$itunes_category[2].'";
$link = $url."?name="; // permalink URL of single episode (appears in the <link> and <guid> tags in the feed)
$feed_language = "'.$feed_language.'"; // Language used in the XML feed (can differ from the script language).
$copyright = "'.$copyright.'"; // Copyright notice
$feed_encoding = "'.$feed_encoding.'"; // Feed Encoding (e.g. "iso-8859-1", "utf-8"). UTF-8 is strongly suggested
$explicit_podcast = "'.$explicit_podcast.'"; //does your podcast contain explicit language? ("yes", "no" or "clean")
// END OF CONFIGURATION
?>';
$createcf = fopen("$absoluteurl"."config.php",'w'); //open config file
fwrite($createcf,$configfiletocreate); //write content into the config file
fclose($createcf);
// $PG_mainbody .= '<b>'._("Config.php created!").'</b><br />';
} // end if logged
?>

View File

@ -1,60 +0,0 @@
<?php
############################################################
# PODCAST GENERATOR
#
# Created by Alberto Betella
# http://www.podcastgenerator.net
#
# This is Free Software released under the GNU/GPL License.
############################################################
########### Security code, avoids cross-site scripting (Register Globals ON)
if (isset($_REQUEST['GLOBALS']) OR isset($_REQUEST['absoluteurl']) OR isset($_REQUEST['amilogged']) OR isset($_REQUEST['theme_path'])) { exit; }
########### End
### Check if user is logged ###
if (!isUserLogged()) { exit; }
###
if (isset($_GET['file']) AND $_GET['file']!=NULL) {
$file = $_GET['file'];
$ext = $_GET['ext'];
// Remove slashes to avoid deleting of file outside media directory - AVOID EXPLOIT with register globals set to ON
$file = basename($file);
$ext = basename($ext);
if (file_exists("$absoluteurl$upload_dir$file.$ext")) {
unlink ("$upload_dir$file.$ext");
$PG_mainbody .="<p><b>$file.$ext</b> "._("has been deleted")."</p>";
}
if (file_exists("$absoluteurl$upload_dir$file.xml")) {
unlink ("$absoluteurl$upload_dir$file.xml"); // DELETE THE FILE
}
//Delete associated image
if (file_exists("$absoluteurl$img_dir$file.jpg")) {
unlink ("$absoluteurl$img_dir$file.jpg");
} else if (file_exists("$absoluteurl$img_dir$file.png")) {
unlink ("$absoluteurl$img_dir$file.png");
}
########## REGENERATE FEED
//include ("$absoluteurl"."core/admin/feedgenerate.php"); //(re)generate XML feed
generatePodcastFeed(TRUE,NULL,FALSE); //Output in file
##########
$PG_mainbody .= '<p><a href=?p=archive&amp;cat=all>'._("Delete other episodes").'</a></p>';
} else {
$PG_mainbody .= _("No file to delete...");
}
?>

View File

@ -1,247 +0,0 @@
<?php
############################################################
# PODCAST GENERATOR
#
# Created by Alberto Betella
# http://www.podcastgenerator.net
#
# This is Free Software released under the GNU/GPL License.
############################################################
########### Security code, avoids cross-site scripting (Register Globals ON)
if (isset($_REQUEST['GLOBALS']) OR isset($_REQUEST['absoluteurl']) OR isset($_REQUEST['amilogged']) OR isset($_REQUEST['theme_path'])) { exit; }
########### End
### Check if user is logged ###
if (!isUserLogged()) { exit; }
###
if (isset($_GET['p']) AND $_GET['p']=="admin" AND isset($_GET['do']) AND $_GET['do']=="edit" AND isset($_GET['c']) AND $_GET['c']=="ok") {
$PG_mainbody .= '<h3>'._("Edit podcast").'</h3>';
include("$absoluteurl"."core/admin/sendchanges.php");
// $PG_mainbody .= '</div>';
}
else {
###########
if (isset($_GET['name']) AND $_GET['name'] != NULL ) {
$singleEpisode = $_GET['name'];
////Validate the current episode
//NB. validateSingleEpisode returns [0] episode is supported (bool), [1] Episode Absolute path, [2] Episode XML DB absolute path,[3] File Extension (Type), [4] File MimeType, [5] File name without extension
$thisPodcastEpisode = validateSingleEpisode($singleEpisode);
////If episode is supported and has a related xml db, and if it's not set to a future date OR if it's set for a future date but you are logged in as admin
if ($thisPodcastEpisode[0]==TRUE) {
////Parse XML data related to the episode
// NB. Function parseXMLepisodeData returns: [0] episode title, [1] short description, [2] long description, [3] image associated, [4] iTunes keywords, [5] Explicit language,[6] Author's name,[7] Author's email,[8] PG category 1, [9] PG category 2, [10] PG category 3, [11] file_info_size, [12] file_info_duration, [13] file_info_bitrate, [14] file_info_frequency
$thisPodcastEpisodeData = parseXMLepisodeData($thisPodcastEpisode[2]);
//// content definition and depuration (solves problem with quotes etc...)
$text_title = depurateContent($thisPodcastEpisodeData[0]); //title
$thisPodcastEpisodeData[1] = depurateContent($thisPodcastEpisodeData[1]); //short desc
$text_shortdesc = depurateContent($thisPodcastEpisodeData[1]); //short desc
$text_longdesc = depurateContent($thisPodcastEpisodeData[2]); //long desc
$text_keywordspg = depurateContent($thisPodcastEpisodeData[4]); //Keywords
$text_authornamepg = depurateContent($thisPodcastEpisodeData[6]); //author's name
$text_authoremailpg = $thisPodcastEpisodeData[7];
$text_explicitpg = $thisPodcastEpisodeData[5];
$episodedate = filemtime ($thisPodcastEpisode[1]);
$text_category1 = $thisPodcastEpisodeData[8];
$text_category2 = $thisPodcastEpisodeData[9];
$text_category3 = $thisPodcastEpisodeData[10];
#########
$PG_mainbody .= '<div class="col-md-12">';
$PG_mainbody .= '<h3 class="sectionTitle">'._("Edit or Delete Episode").'</h3>';
$PG_mainbody .= '
<div class="span5 col-md-5 importantSection">
<form action="?p=admin&amp;do=edit&amp;c=ok" method="POST" enctype="multipart/form-data" name="uploadform" id="uploadform" onsubmit="return submitForm();">
<fieldset>
<legend><b>'._("Main information (required):").'</b></legend>
';
$PG_mainbody .= '<input type="hidden" name="userfile" value="'.$_GET['name'].'">';
//$PG_mainbody .= '<label for="userfile">'._("File to edit:").'</label><br />
//<p><b>'.$text_title.'</b> ('.$_GET['name'].')</p>';
$PG_mainbody .= '
<label for="title">'._("Title").' *</label>
<input class="form-control" style="max-width:220px;" name="title" id="title" type="text" size="50" maxlength="255" value="'.$text_title.'" /><br /><br />
<label for="description">'._("Short Description").' *</label>
<input class="form-control" style="max-width:220px;" name="description" id="description" type="text" onKeyDown="limitText(this.form.description,this.form.countdown,255);"
onKeyUp="limitText(this.form.description,this.form.countdown,255);" size="50" maxlength="255" value="'.$text_shortdesc.'">
<br />
<span>
<input name="countdown" class="readonlyinput" type="text" value="255" class ="alert" size="3" readonly> '._("characters left").'</span>
<br /><br />';
### INCLUDE CATEGORIES FORM
if ($categoriesenabled == "yes") { // if categories are enabled in config.php
include("$absoluteurl"."core/admin/showcat.php");
}
//else { // if categories are disabled, then use an empty value
//$PG_mainbody .= '<input type="hidden" name="category[0]" value="">';
// }
### END CATEGORIES FORM
$PG_mainbody .= '
<br /><br />
<label>'._("Change the episode date").'</label>
<span class="alert alert-warning">'._("The episodes of your podcast are automatically sorted by date. Changing the date of this episode will change its order in the podcast feed. If you specify a date in future, your episode won't be shown till then.").'</span><br /><br />
'.CreaFormData("",$episodedate,$dateformat); //dateformat is taken from config.php
$PG_mainbody .= '<br /><br />';
$PG_mainbody .= _("Fields marked with * are required.").'
';
// $PG_mainbody .= '<p><input type="checkbox" value="'._("add extra information to this episode").'" onClick="javascript:Effect.toggle(\'main\',\'appear\');">'._("add extra information to this episode").'</p>';
$PG_mainbody .= '</fieldset>
</div>';
$PG_mainbody .= '
<div class="span5 col-md-5">
<fieldset>
<legend><b>'._("Extras").'</b></legend>
<label for="long_description">'._("Long Description").'</label>
<textarea id="long_description" name="long_description" cols="50" rows="3">'.$text_longdesc.'</textarea>
<br />';
//UPLOAD IMAGE ASSOCIATED TO EACH EPISODE
//Disabled for the moment (does it really work in the podcast feed?
//better to upload images in the WYSIWYG editor in future
//$PG_mainbody .= '<label for="image">'._("Image").'</label><br /><span class ="alert">'._("You can associate an image to this episode; it will appear on the recent podcast page and on the details page.").'</span><br /><span class ="alert">'._("Upload a SMALL image (suggested dimensions: 150x150 pixels). Accepted formats: png, gif e jpg.").'</span><br /><br /><input name="image" type="file"><br /><br /><br />';
$PG_mainbody .= '
<label for="keywords">'._("iTunes Keywords").'</label>
<input class="form-control" name="keywords" type="text" onkeyup="cnt(this,document.uploadform.counttotalwords)" size="50" maxlength="255" placeholder="'._("Keyword1, Keyword2 (max 12)").'" value="'.$text_keywordspg.'">';
//count keywords
//$PG_mainbody .= '<span><input type="text" name="counttotalwords" value="0" onkeyup="cnt(document.uploadform.keywords,this)" class="readonlyinput" readonly />'._("keywords").'</span>';
$PG_mainbody .= '
<br /><br />
<label for="explicit">'._("Explicit content?").'</label>
<span class ="alert">'._("Select YES if this episode contains explicit language or adult content.").'</span><br /><br />
'._("Yes").'&nbsp;<input type="radio" name="explicit" value="yes"';
if ($text_explicitpg == "yes") {
$PG_mainbody .= ' checked';
}
$PG_mainbody .= '>&nbsp;'._("No").'&nbsp;<input type="radio" name="explicit" value="no"';
if ($text_explicitpg != "yes") {
$PG_mainbody .= ' checked';
}
$PG_mainbody .= '>
<br /><br />
<label for="auth_name">'._("Author").'</label>
<span class="alert alert-warning">'._("You can specify a different author for this episode, otherwise the default author will be the podcast owner").'</span><br />
<div class="form-inline">
<div class="form-group">
<input name="auth_name" type="text" class="form-control input-medium" id="auth_name" maxlength="255" placeholder="'._("Author's name").'" value="'.$text_authornamepg.'">
</div>
<div class="form-group">
<input name="auth_email" type="text" class="form-control input-medium" id="auth_email" maxlength="255" placeholder="'._("Author's email address").'" value="'.$text_authoremailpg.'">
</div>
</div>
</fieldset>
<br />
<input type="submit" value="'._("Update Episode").'" class="btn btn-default btn-success btn-lg btn-large" onClick="showNotify(\''._("Updating").'\');">
<input type="button" id="confirmdelete" value="'._("Delete Episode").'" class="btn btn-default btn-warning btn-medium" />
<div id="confirmation" style="display:none;">
<br />
'._("Do you really want to permanently delete this episode?").'
<a class="btn btn-danger btn-mini" href="?p=admin&do=delete&file='.$thisPodcastEpisode[5].'&ext='.$thisPodcastEpisode[3].'">'._("YES, I am sure").'</a>
</div>
<br /><br />
</form>
</div>
</div>';
}
} // END - If episode is supported
} // end else . if GET variable "c" is not = "ok"
?>

View File

@ -1,79 +0,0 @@
<?php
############################################################
# PODCAST GENERATOR
#
# Created by Alberto Betella
# http://www.podcastgenerator.net
#
# This is Free Software released under the GNU/GPL License.
############################################################
########### Security code, avoids cross-site scripting (Register Globals ON)
if (isset($_REQUEST['GLOBALS']) OR isset($_REQUEST['absoluteurl']) OR isset($_REQUEST['theme_path'])) { exit; }
########### End
### Check if user is logged ###
if (!isUserLogged()) { exit; }
###
if (isset($_GET['p'])) if ($_GET['p']=="admin") { // if admin is called from the script in a GET variable - security issue
if (isset($_GET['do']) AND $_GET['do']=="generate" AND !isset($_GET['c'])) { //show "Continue" Button
$PG_mainbody .= "<h3>"._("Generate XML feed")."</h3>";
$PG_mainbody .= "<p><span class=\"admin_hints\">"._("Manually regenerate xml feed")."</span></p>";
// include ("$absoluteurl"."components/loading_indicator/loading.js");
$PG_mainbody .= '<br /><br />
<form method="GET" action="index.php">
<input type="hidden" name="p" value="'.$_GET['p'].'">
<input type="hidden" name="do" value="'.$_GET['do'].'">
<input type="hidden" name="c" value="ok">
<input type="submit" value="'._("Continue").'" class="btn btn-success btn-small" onClick="showNotify(\''._("Regenerating Feed").'\');">
</form>
';
#########
}else{
if (isset($_GET['do']) AND $_GET['do']=="generate") { // do not show following text if included in other php files
$PG_mainbody .= "<h3>"._("Generate XML feed")."</h3>";
$PG_mainbody .= "<p><span class=\"admin_hints\">"._("Manually regenerate xml feed")."</span></p>";
}
/////////
//Generate RSS Feed in a file (feed.xml)
$episodesCounter = generatePodcastFeed(TRUE,NULL,TRUE); //Output in file
////////
$PG_mainbody .= "<br /><b>"._("Feed XML generated!")."</b><br />";
if ($recent_episode_in_feed == "0") {
$PG_mainbody .= "<br /><i>"._("All the episodes have been indexed in the feed")."</i><br /><span class=\"admin_hints\">"._("You can limit the feed to the last episodes")."</span>";
} else {
if (!isset($episodesCounter)) $episodesCounter = 0; //avoid notice
$PG_mainbody .= "<br /><i>$episodesCounter "._("episode(s) in the feed")."</i>";
}
//$PG_mainbody .= "<p><a href=\"$url\">"._("Go to the homepage")."</a></p>";
}
}
?>

View File

@ -1,74 +0,0 @@
<?php
############################################################
# PODCAST GENERATOR
#
# Created by Alberto Betella
# http://www.podcastgenerator.net
#
# This is Free Software released under the GNU/GPL License.
############################################################
########### Security code, avoids cross-site scripting (Register Globals ON)
if (isset($_REQUEST['GLOBALS']) OR isset($_REQUEST['absoluteurl']) OR isset($_REQUEST['amilogged']) OR isset($_REQUEST['theme_path'])) { exit; }
########### End
### Check if user is logged ###
if (!isUserLogged()) { exit; }
###
if (isset($_GET['p']) AND $_GET['p']=="admin" AND isset($_GET['do']) AND $_GET['do']=="freebox" AND isset($_GET['c']) AND $_GET['c']=="ok") {
$freeboxcontent = $_POST['long_description'];
$freeboxcontent = stripslashes($freeboxcontent); //depurate
$PG_mainbody .= '<h3>'._("FreeBox").'</h3>';
$fp1 = fopen("$absoluteurl"."freebox-content.txt", "w+"); //Apri il file in lettura e svuotalo (w+)
fclose($fp1);
$fp = fopen("$absoluteurl"."freebox-content.txt", "a+"); //testa xml
fwrite($fp, $freeboxcontent);
fclose($fp);
$PG_mainbody .= ""._("Your freebox has been updated!")."";
}
else {
$PG_mainbody .= '<h3>'._("FreeBox").'</h3>';
if(file_exists("$absoluteurl"."freebox-content.txt")){
$freeboxcontenttodisplay = file_get_contents("$absoluteurl"."freebox-content.txt");
} else { $freeboxcontenttodisplay = NULL; }
$PG_mainbody .= '
<span class ="alert">'._("(HTML tags accepted)").'</span><br /><br />
<form action="?p=admin&amp;do=freebox&amp;c=ok" method="POST" enctype="application/x-www-form-urlencoded" name="freeboxform" id="freeboxform">
<textarea id="long_description" name="long_description" cols="50" rows="10">'.$freeboxcontenttodisplay.'</textarea>
<br /><br />
<input type="submit" value="'._("Send").'" class="btn btn-success btn-small" onClick="showNotify(\''._("Setting...").'\');">
</form>
';
} // end else . if GET variable "c" is not = "ok"
?>

View File

@ -1,58 +0,0 @@
<?php
############################################################
# PODCAST GENERATOR
#
# Created by Alberto Betella
# http://www.podcastgenerator.net
#
# This is Free Software released under the GNU/GPL License.
############################################################
########### Security code, avoids cross-site scripting (Register Globals ON)
if (isset($_REQUEST['GLOBALS']) OR isset($_REQUEST['absoluteurl']) OR isset($_REQUEST['theme_path'])) { exit; }
########### End
### Check if user is logged ###
if (!isUserLogged()) { exit; }
###
if (isset($_GET['p'])) if ($_GET['p']=="admin") { // if admin is called from the script in a GET variable - security issue
$PG_mainbody .= "<h3>"._("FTP Feature")."</h3>";
$PG_mainbody .= "<p><span class=\"alert\">"._("Looking for manually uploaded podcast into directory:")." $upload_dir</span></p>";
if (!isset($_GET['c'])) { //show "Continue" Button
//include ("$absoluteurl"."components/loading_indicator/loading.js");
$PG_mainbody .= '<br /><br />
<form method="GET" action="index.php">
<input type="hidden" name="p" value="'.$_GET['p'].'">
<input type="hidden" name="do" value="'.$_GET['do'].'">
<input type="hidden" name="c" value="ok">
<input type="submit" value="'._("Continue").'" class="btn btn-success btn-small" onClick="showNotify(\''._("Searching...").'\');">
</form>
';
} elseif (isset($_GET['c']) AND isset($_GET['p']) AND $_GET['p']=="admin" AND isset($_GET['do']) AND $_GET['do']=="ftpfeature") {
$episodesCounter = autoIndexingEpisodes();
$PG_mainbody .= '<p><b>'._("Scan finished:").'</b> '.$episodesCounter.' '._("new episode(s) added.").'</p>';
$PG_mainbody .= "<p><a href=\"$url\">"._("Go to the homepage")."</a></p>";
//REGENERATE FEED ...
if ($episodesCounter > 0) {
generatePodcastFeed(TRUE,NULL,FALSE); //Output in file
}
} // if continue button is pressed
} // if is called from admin
?>

View File

@ -1,164 +0,0 @@
<?php
############################################################
# PODCAST GENERATOR
#
# Created by Alberto Betella
# http://www.podcastgenerator.net
#
# This is Free Software released under the GNU/GPL License.
############################################################
########### Security code, avoids cross-site scripting (Register Globals ON)
if (isset($_REQUEST['GLOBALS']) OR isset($_REQUEST['absoluteurl']) OR isset($_REQUEST['amilogged']) OR isset($_REQUEST['theme_path'])) { exit; }
########### End
### Check if user is logged ###
if (!isUserLogged()) { exit; }
###
// check if user is already logged in
if(isUserLogged()) {
$PG_mainbody .= '<h3>'._("iTunes categories").'</h3>
<span class="alert">'._("Select or change iTunes Categories (iTunes Store)").'</span>';
if (isset($_GET['action']) AND $_GET['action']=="change") { // if action is set
if (isset($_POST['category1'])) { //cat1
$itunes_category[0] = $_POST['category1']; }
if (isset($_POST['category2'])) { //cat2
$itunes_category[1] = $_POST['category2'];
}
if (isset($_POST['category3'])) { //cat3
$itunes_category[2] = $_POST['category3'];
}
include ("$absoluteurl"."core/admin/createconfig.php"); //regenerate config.php
$PG_mainbody .= '<br /><br /><p>'._("iTunes Categories successfully changed...").'</p>';
//REGENERATE FEED ...
//include ("$absoluteurl"."core/admin/feedgenerate.php");
generatePodcastFeed(TRUE,NULL,FALSE); //Output in file
}
else { // if action not set
/*
include ("$absoluteurl"."components/xmlparser/loadparser.php");
include ("$absoluteurl"."core/admin/readitunescategories.php");
*/
if (file_exists($absoluteurl."components/itunes_categories/itunes_categories.xml")) {
$parser = simplexml_load_file($absoluteurl.'components/itunes_categories/itunes_categories.xml','SimpleXMLElement',LIBXML_NOCDATA);
}
// define variables
$arr = NULL;
$arrid = NULL;
$n = 0;
foreach($parser->category as $singlecategory)
{
//echo $singlecategory->id[0]->tagData."<br>";
//echo $singlecategory->description[0]->tagData;
$arr[] .= $singlecategory->description[0];
$arrid[] .= $singlecategory->id[0];
$n++;
}
$PG_mainbody .= '<form name="'._("iTunes categories").'" method="POST" enctype="multipart/form-data" action="?p=admin&do=itunescat&action=change">';
## CATEGORY 1
$PG_mainbody .= "<br /><br /><p><b>"._("iTunes Category 1")."</b></p>";
$PG_mainbody .= '<select name="category1">';
natcasesort($arr); // Natcasesort orders more naturally and is different from "sort", which is case sensitive
foreach ($arr as $key => $val) {
if ( $val != "" ) { //just for 1st category - cannot be empty
$PG_mainbody .= '
<option value="' . $val . '"';
if ($itunes_category[0] == $val) {
$PG_mainbody .= ' selected';
}
$PG_mainbody .= '>' . $val . '</option>
';
}
}
$PG_mainbody .= '</select>';
## CATEGORY 2
$PG_mainbody .= "<br /><br /><p><b>"._("iTunes Category 2")."</b></p>";
$PG_mainbody .= '<select name="category2">';
natcasesort($arr); // Natcasesort orders more naturally and is different from "sort", which is case sensitive
foreach ($arr as $key => $val) {
$PG_mainbody .= '
<option value="' . $val . '"';
if ($itunes_category[1] == $val) {
$PG_mainbody .= ' selected';
}
$PG_mainbody .= '>' . $val . '</option>
';
}
$PG_mainbody .= '</select>';
## CATEGORY 3
$PG_mainbody .= "<br /><br /><p><b>"._("iTunes Category 3")."</b></p>";
$PG_mainbody .= '<select name="category3">';
natcasesort($arr); // Natcasesort orders more naturally and is different from "sort", which is case sensitive
foreach ($arr as $key => $val) {
$PG_mainbody .= '
<option value="' . $val . '"';
if ($itunes_category[2] == $val) {
$PG_mainbody .= ' selected';
}
$PG_mainbody .= '>' . $val . '</option>
';
}
$PG_mainbody .= '</select>';
$PG_mainbody .= '<p>
<input type="submit" name="'._("Send").'" class="btn btn-success btn-small" value="'._("Send").'" onClick="showNotify(\''._("Setting...").'\');"></p>';
}
}
?>

View File

@ -1,129 +0,0 @@
<?php
############################################################
# PODCAST GENERATOR
#
# Created by Alberto Betella
# http://www.podcastgenerator.net
#
# This is Free Software released under the GNU/GPL License.
############################################################
########### Security code, avoids cross-site scripting (Register Globals ON)
if (isset($_REQUEST['GLOBALS']) OR isset($_REQUEST['absoluteurl']) OR isset($_REQUEST['amilogged']) OR isset($_REQUEST['theme_path'])) { exit; }
########### End
### Check if user is logged ###
if (!isUserLogged()) { exit; }
###
// check if user is already logged in
if(isUserLogged()) {
$PG_mainbody .= '<h3>'._("iTunes cover art").'</h3>
<span class="admin_hints">'._("Podcast cover that will be displayed in the iTunes Store").'</span><br /><br />';
if (isset($_GET['action']) AND $_GET['action']=="change") {
if (isset($_FILES['image'] ['name']) AND $_FILES['image'] ['name'] != NULL) {
$img = $_FILES['image'] ['name'];
$img_ext=explode(".",$img); // divide filename from extension
if (strtolower($img_ext[1])=="jpg" OR strtolower($img_ext[1])=="jpeg" OR strtolower($img_ext[1])=="png") { // check image format
$iTunesCoverNameWithoutExtension = $absoluteurl.$img_dir."itunes_image.";
$newNameiTunesCoverUploaded = $iTunesCoverNameWithoutExtension.strtolower($img_ext[1]);
//Delete previous covers
if (file_exists($iTunesCoverNameWithoutExtension.'jpg')) unlink($iTunesCoverNameWithoutExtension.'jpg');
else if (file_exists($iTunesCoverNameWithoutExtension.'png')) unlink($iTunesCoverNameWithoutExtension.'png');
if (move_uploaded_file($_FILES['image']['tmp_name'], $newNameiTunesCoverUploaded))
{
$PG_mainbody .= "<p><b>"._("iTunes cover art replaced successfully.")."</b></p>"; // If upload is successful.
########## REGENERATE FEED
$episodesCounter = generatePodcastFeed(TRUE,NULL,FALSE); //Output in file
##########
}
else { //if upload NOT successful
$PG_mainbody .= "<p><b>"._("Error: image NOT sent!")."</b></p>";
// $temporaneo= $_FILES['image']['tmp_name'];
}
} else { // if image extension is NOT valid
$PG_mainbody .= "<p><b>"._("Image extension not valid. The image extension must end in .jpg or .png")."</b></p>";
// $PG_mainbody .= "<p>"._("You can replace the current image with a new one. To be eligible for featuring on iTunes Store, a podcast must have 1400 x 1400 pixel cover art in JPG or PNG.")."</p>";
$PG_mainbody .= '<br />
<form>
<input type="button" value="&laquo; '._("Back").'" onClick="history.back()" class="btn btn-danger btn-small" />
</form>';
}
}
else { //if new image NOT selected or empty field
$PG_mainbody .= "<p>"._("No file selected. Please go back and select an image.")."</p>";
$PG_mainbody .= '<br />
<form>
<input type="button" value="&laquo; '._("Back").'" onClick="history.back()" class="btn btn-danger btn-small" />
</form>';
}
###################### end image upload section
}
else { // if image is not posted open the form
if (file_exists($absoluteurl.$img_dir.'itunes_image.jpg')) {
$podcastCoverArt= $url.$img_dir.'itunes_image.jpg';
} else if (file_exists($absoluteurl.$img_dir.'itunes_image.png')) {
$podcastCoverArt= $url.$img_dir.'itunes_image.png';
}
//time() is added to the img URL so the browser doesn't cache it in the admin section
$PG_mainbody .= '
<div class="topseparator"><p>
'._("Current image:").'</p>
<p> <img src="'.$podcastCoverArt.'?'.time().'" width="300" height="300" alt="'._("iTunes image").'" />
</p><br /></div>
<div class="topseparator">
<form name="'._("iTunes cover art").'" method="POST" enctype="multipart/form-data" action="?p=admin&do=itunesimg&action=change">
<p><label for="'._("iTunes image").'">'._("New image:").'</label></p>
<input name="image" type="file">
<p><span class="admin_hints">'._("You can replace the current image with a new one. To be eligible for featuring on iTunes Store, a podcast must have 1400 x 1400 pixel cover art in JPG or PNG.").'</span></p>
<p>
<input type="submit" name="'._("Send").'" class="btn btn-success btn-small" value="'._("Send").'" class="btn btn-success btn-small" onClick="showNotify(\''._("Uploading...").'\');"></p>
</p>
</div>
';
}
}
?>

View File

@ -1,87 +0,0 @@
<?php
############################################################
# PODCAST GENERATOR
#
# Created by Alberto Betella
# http://www.podcastgenerator.net
#
# This is Free Software released under the GNU/GPL License.
############################################################
$loadjavascripts = '<script type="text/javascript" src="components/js/admin.js"></script>
<script type="text/javascript" src="components/js/jquery.js"></script>
';
if (isset($_GET["do"])) {
if ($_GET["do"]=="upload" OR $_GET["do"]=="freebox" OR $_GET["do"]=="edit" OR $_GET["do"]=="categories") {
//DELETE FADING IN CONFIRMATION (e.g. are you sure u want to delete?)
$loadjavascripts .='
<script type="text/javascript">
$(document).ready(
function() {
$("#confirmdelete").click(function() {
$("#confirmation").fadeToggle();
});
});
</script>';
// DELETE categories confirmation
$loadjavascripts .='
<script type="text/javascript">
$(document).ready(
function() {
$(\'[id^="confirmdelete-"]\').click(function() {
$(\'#confirmation-\'+$(this).attr(\'id\').replace(\'confirmdelete-\',\'\')).fadeToggle();
});
});
</script>';
### INSERT EDITOR WYSIWYG in specified pages
// TinyMCE is loaded from an external (offical) URL. If no connection available then a simple textarea will be shown
// Note: the - entity_encoding : "raw" - into tinyMCE.init solves issues with html entities (conversion of letter with accents, and other characters) in the "long description" of episodes
// extended_valid_elements and custom_elements allows to insert new html elements (e.g. Google custom search engine)
//NB in future enable "code" from toolbar below just for freebox
$loadjavascripts .='
<script src="//tinymce.cachefly.net/4.1/tinymce.min.js"></script>
<script>
tinymce.init({
selector:"#long_description",
extended_valid_elements : "gcse:search",
custom_elements : "gcse:search,~gcse:search",
entity_encoding : "raw",
width: 400,
height: 200,
menubar: false,
statusbar: false,
plugins: [
"advlist autolink link image lists charmap print preview hr anchor pagebreak spellchecker",
"searchreplace wordcount visualblocks visualchars code fullscreen insertdatetime media nonbreaking",
"save table contextmenu directionality emoticons template paste textcolor"
],
toolbar: "insertfile undo redo | styleselect | bold italic | alignleft aligncenter alignright | bullist numlist outdent indent | link image | forecolor | code",
});
</script>
';
}
}
?>

View File

@ -1,110 +0,0 @@
<?php
############################################################
# PODCAST GENERATOR
#
# Created by Alberto Betella
# http://www.podcastgenerator.net
#
# This is Free Software released under the GNU/GPL License.
############################################################
########### Security code, avoids cross-site scripting (Register Globals ON)
if (isset($_REQUEST['GLOBALS']) OR isset($_REQUEST['absoluteurl']) OR isset($_REQUEST['amilogged']) OR isset($_REQUEST['theme_path'])) { exit; }
########### End
//include ("$absoluteurl"."components/loading_indicator/loading.js"); //include top right loading indicator
// define login form
$loginform ='
<br /><br />
<form id="login" action="?p=admin" method="post">
<label for="user">'._("User").'</label><br />
<input type="text" id="user" name="user" size="20" maxlength="255"><br /><br />
<label for="password">'._("Password").'</label><br />
<input type="password" id="password" name="password" size="20" maxlength="255"><br /><br />
<input type="submit" value="'._("Log in").'" class="btn btn-success btn-small" onClick="showNotify(\''._("Logging in...").'\');">';
// logout section
if(isset($_GET['action']) AND $_GET['action'] == "logout" ){
$action = $_GET['action'];
//session_start();
session_unset();
session_destroy();
}
// end logout section
// check if user is already logged in
if(isset($_SESSION["user_session"]) AND $_SESSION["user_session"]==$username AND md5($_SESSION["password_session"])==$userpassword){ //if so, keep displaying the page
if (!useNewThemeEngine($theme_path)) { //if is not new theme engine
//write in the body the login / logout pointers
$PG_mainbody .= '<div class="episode">'._("Hello").' '.$username.' ';
if (isset($_GET['do']) AND $_GET['do'] != NULL) { //if we are in admin area and an action is performed
$PG_mainbody .= '(<a href="?p=admin">'._("Back to Admin").'</a> - <a href="?p=admin&amp;action=logout">'._("Log out").'</a>)';
} else {$PG_mainbody .= '(<a href="?p=admin&amp;action=logout">'._("Log out").'</a>)';}
$PG_mainbody .= '<br /><br /></div>';
}
}else{
if(isset($_POST["user"]) AND $_POST["user"]==$username AND isset($_POST["password"]) AND md5($_POST["password"])==$userpassword){ //if user and pwd are valid
if (!useNewThemeEngine($theme_path)) { //if is not new theme engine
$PG_mainbody .= '<div class="episode">
'._("Hello").' '.$username.' (<a href="?p=admin&amp;action=logout">'._("Log out").'</a>)
<br /><br />
</div>';
}
$_SESSION["user_session"] = $_POST["user"];
$_SESSION["password_session"] = $_POST["password"];
}else{
if(isset($_POST["user"]) AND isset($_POST["password"])) { //if user and pwd are not correct
//display AGAIN login form if usr/pwd not correct
$PG_mainbody .= '
<div class="topseparator">
<b>'._("Username or password not valid. Please try again...").'</b>
'.$loginform.'
</form>
</div>';
}else {
//display login form
$PG_mainbody .= '
<div class="topseparator">
<b>'._("Log in").'</b>
'.$loginform.'
</form>
</div>
';
}
}
}
?>

View File

@ -1,54 +0,0 @@
<?php
############################################################
# PODCAST GENERATOR
#
# Created by Alberto Betella
# http://www.podcastgenerator.net
#
# This is Free Software released under the GNU/GPL License.
############################################################
########### Security code, avoids cross-site scripting (Register Globals ON)
if (isset($_REQUEST['GLOBALS']) OR isset($_REQUEST['absoluteurl']) OR isset($_REQUEST['amilogged']) OR isset($_REQUEST['theme_path'])) { exit; }
########### End
## Here we read Podcast Generator RSS news feed to display in the admin section the latest news about the script
// Try to load and parse podcastgen RSS news file
$rssurl = 'http://feeds.podcastgenerator.net/podcastgenerator';
// include lastRSS
include("$absoluteurl"."components/lastRSS/lastRSS.php");
// Create lastRSS object
$rss = new lastRSS;
// Set cache dir and cache time limit (1200 seconds)
// (don't forget to chmod cache dir to 777 to allow writing)
### In podcastgen I set the ROOT directory as RSS cache dir, as it should already haver writing permissions:
$rss->cache_dir = $absoluteurl;
$rss->cache_time = 43200; // 12 hours cache time between each update of podcastgen news
if ($rs = $rss->get($rssurl)) {
// I could use also ['author']['guid']['link']
$RSSnews_title = $rs['items']['0']['title'];
$RSSnews_date = $rs['items']['0']['pubDate'];
$RSSnews_description = html_entity_decode($rs['items']['0']['description']); // I use html_entity_decode to enable html tags
//output RSS last item
$PG_mainbody .= '<p><b>'.$RSSnews_title.'</b><br /><span class ="admin_hints">
'.$RSSnews_date.'</span><br /><br />
'.$RSSnews_description.'
</p>';
}
else {
$PG_mainbody .= _("Error: It's not possible to get Podcast Generator news feed. News will be automatically disabled.");
//DISABLE news display if the server doesn't allow
$enablepgnewsinadmin = "no";
include ("$absoluteurl"."core/admin/createconfig.php"); //regenerate config.php
}
?>

View File

@ -1,221 +0,0 @@
<?php
############################################################
# PODCAST GENERATOR
#
# Created by Alberto Betella
# http://www.podcastgenerator.net
#
# This is Free Software released under the GNU/GPL License.
############################################################
########### Security code, avoids cross-site scripting (Register Globals ON)
if (isset($_REQUEST['GLOBALS']) OR isset($_REQUEST['absoluteurl']) OR isset($_REQUEST['amilogged']) OR isset($_REQUEST['theme_path'])) { exit; }
########### End
// check if user is already logged in
if(isUserLogged()) {
$PG_mainbody .= '<h3>'._("Change your podcast details").'</h3>
<p><span class="alert">'._("These information will be used both in this website and in the resulting RSS feed").'</span></p>';
if (isset($_GET['action']) AND $_GET['action']=="change") { // if action is set
//title
$title = $_POST['title'];
if ($title != "") {
$title = stripslashes($title);
$title = strip_tags($title);
$title = htmlspecialchars($title);
$title = depurateContent($title);
$podcast_title = $title;
}else{
$PG_mainbody .= '<p>'._("Podcast Title").' '._("is empty... (it will be ignored)").'</p>';
}
// subtitle
$subtitle = $_POST['subtitle'];
if ($subtitle != "") {
$subtitle = stripslashes($subtitle);
$subtitle = strip_tags($subtitle);
$subtitle = htmlspecialchars($subtitle);
$subtitle = depurateContent($subtitle);
$podcast_subtitle = $subtitle;
}else{
$PG_mainbody .= '<p>'._("Podcast Subtitle").' '._("is empty... (it will be ignored)").'</p>';
}
// description
$description = $_POST['description'];
if ($description != "") {
$descmax =4000; #set max characters variable. iTunes specifications by Apple say "max 4000 characters" for itunes:summary tag
if (strlen($description)<$descmax) { // (if long description IS NOT too long
$description = stripslashes($description);
$description = strip_tags($description);
$description = htmlspecialchars($description);
$description = depurateContent($description);
$podcast_description = $description;
}else { //if description is more than max characters allowed
$PG_mainbody .= "<p>"._("The podcast description is too long and will be ignored.")."<br />"._("Max:")." $descmax "._("characters")." - "._("Actual Length")." ".strlen($description)." "._("characters").".</p>";
} // end of description lenght checking
}else{
$PG_mainbody .= '<p>'._("Podcast Description").' '._("is empty... (it will be ignored)").'</p>';
}
// copyright
$copyright_notice = $_POST['copyright_notice'];
if ($copyright_notice != "") {
$copyright_notice = stripslashes($copyright_notice);
$copyright_notice = strip_tags($copyright_notice);
$copyright_notice = htmlspecialchars($copyright_notice);
$copyright_notice = depurateContent($copyright_notice);
$copyright = $copyright_notice;
}else{
$PG_mainbody .= '<p>'._("Copyright Notice").' '._("is empty... (it will be ignored)").'</p>';
}
// author's name
$authorname = $_POST['authorname'];
if ($authorname != "") {
$authorname = stripslashes($authorname);
$authorname = strip_tags($authorname);
$authorname = htmlspecialchars($authorname);
$authorname = depurateContent($authorname);
$author_name = $authorname;
}else{
$PG_mainbody .= '<p>'._("Author's name").' '._("is empty... (it will be ignored)").'</p>';
}
// author's email
$authoremail = $_POST['authoremail'];
$authoremail = stripslashes($authoremail);
$authoremail = strip_tags($authoremail);
$authoremail = htmlspecialchars($authoremail);
$authoremail = depurateContent($authoremail);
if (validate_email($authoremail)) { //if email is valid
$author_email = $authoremail;
}
else{ // if email not valid
$PG_mainbody .= '<p>'._("Author's email address not present or not valid").' '._("(it will be ignored)").'</p>';
}
//feed language
$feedlanguage = $_POST['feedlanguage'];
$feed_language = $feedlanguage;
//explicit
$explicit = $_POST['explicit'];
$explicit_podcast = $explicit;
include ("$absoluteurl"."core/admin/createconfig.php"); //regenerate config.php
$PG_mainbody .= '<p>'._("The information has been successfully sent.").'</p>';
//REGENERATE FEED ...
//include ("$absoluteurl"."core/admin/feedgenerate.php");
generatePodcastFeed(TRUE,NULL,FALSE); //Output in file
$PG_mainbody .= '<br /><br />';
}
else { // if action not set
$PG_mainbody .= '<form name="podcastdetails" method="POST" enctype="multipart/form-data" action="?p=admin&do=changedetails&action=change">';
$PG_mainbody .= '<br /><br />
<p><label for="title"><b>'._("Podcast Title").'</b></label></p>
<input name="title" type="text" id="title" size="50" maxlength="255" value="'.$podcast_title.'">
<br /><br />
<p><label for="subtitle"><b>'._("Podcast Subtitle or Slogan").'</b></label></p>
<input name="subtitle" type="text" id="title" size="50" maxlength="255" value="'.$podcast_subtitle.'">
<br /><br />
<p><label for="description"><b>'._("Podcast Description").'</b></label></p>
<textarea name="description" cols="50" rows="3">'.$podcast_description.'</textarea>
<br /><br />
<p><label for="copyright_notice"><b>'._("Copyright Notice").'</b></label></p>
<input name="copyright_notice" type="text" id="title" size="50" maxlength="255" value="'.$copyright.'">
<br /><br />
<p><label for="authorname"><b>'._("Author's name").'</b></label></p>
<input name="authorname" type="text" id="title" size="50" maxlength="255" value="'.$author_name.'">
<br /><br />
<p><label for="authoremail"><b>'._("Author's email address").'</b></label></p>
<input name="authoremail" type="text" id="title" size="50" maxlength="255" value="'.$author_email.'">';
$listWithLanguages = languagesList($absoluteurl,FALSE);
## FEED LANGUAGES LIST
$PG_mainbody .= '<br /><br /><p><label for="feedlanguage"><b>'._("Feed language").'</b></label></p>
<p><span class="alert">'._("Main language of your episodes").'</span></p>
';
$PG_mainbody .= '<select name="feedlanguage">';
natcasesort($listWithLanguages); // Natcasesort orders more naturally and is different from "sort", which is case sensitive
foreach ($listWithLanguages as $key => $val) {
$PG_mainbody .= '
<option value="' . $key . '"';
if ($feed_language == $key) {
$PG_mainbody .= ' selected';
}
$PG_mainbody .= '>' . $val . '</option>
';
}
$PG_mainbody .= '</select>';
$PG_mainbody .= '<br /><br /><p><label for="explicit"><b>'._("Explicit Podcast?").'</b></label></p>
<span class="alert">'._("Does your podcast contain explicit language?").'</span>
<p>'._("Yes").' <input type="radio" name="explicit" value="yes" ';
if ($explicit_podcast == "yes") {
$PG_mainbody .= 'checked';
}
$PG_mainbody .= '>&nbsp;&nbsp; '._("No").' <input type="radio" name="explicit" value="no" ';
if ($explicit_podcast == "no") {
$PG_mainbody .= 'checked';
}
$PG_mainbody .= '>&nbsp;&nbsp; '._("No, it's clean").'<input type="radio" name="explicit" value="clean" ';
if ($explicit_podcast == "clean") {
$PG_mainbody .= 'checked';
}
$PG_mainbody .= '></p>';
$PG_mainbody .= '<br /><p>
<input type="submit" name="'._("Send").'" class="btn btn-success btn-small" value="'._("Send").'" onClick="showNotify(\''._("Updating").'\');"></p>
</form>';
}
}
?>

View File

@ -1,53 +0,0 @@
<?php
############################################################
# PODCAST GENERATOR
#
# Created by Alberto Betella
# http://www.podcastgenerator.net
#
# This is Free Software released under the GNU/GPL License.
############################################################
########### Security code, avoids cross-site scripting (Register Globals ON)
if (isset($_REQUEST['GLOBALS']) OR isset($_REQUEST['absoluteurl']) OR isset($_REQUEST['amilogged']) OR isset($_REQUEST['theme_path'])) { exit; }
########### End
### here don't check if user is logged as this file is included also in pages which don't need admin privileges ###
//Get the XML document loaded into a variable (The xml parser must be previously included)
if (file_exists("$absoluteurl"."categories.xml")) {
$xml = file_get_contents("$absoluteurl"."categories.xml");
// define variables
$arr = NULL;
$arrid = NULL;
$n = 0;
$parser = simplexml_load_file($absoluteurl."categories.xml",'SimpleXMLElement',LIBXML_NOCDATA);
//var_dump($parser); //Debug
// $existingCategories = array();
$n = 0;
foreach($parser->category as $singlecategory) {
//create array containing category id as seed and description for each id
$catID = $singlecategory->id[0];
$catDescription = $singlecategory->description[0];
// $existingCategories[$catID] = $catDescription;
$arr[] .= $catDescription;
$arrid[] .= $catID;
$n++;
}
}
?>

View File

@ -1,39 +0,0 @@
<?php
############################################################
# PODCAST GENERATOR
#
# Created by Alberto Betella
# http://www.podcastgenerator.net
#
# This is Free Software released under the GNU/GPL License.
############################################################
########### Security code, avoids cross-site scripting (Register Globals ON)
if (isset($_REQUEST['GLOBALS']) OR isset($_REQUEST['absoluteurl']) OR isset($_REQUEST['amilogged']) OR isset($_REQUEST['theme_path'])) { exit; }
########### End
### Check if user is logged ###
if (!isUserLogged()) { exit; }
###
//Get the XML document loaded into a variable (The xml parser must be previously included)
if (file_exists($absoluteurl."components/feed_languages/feed_languages.xml")) {
// $xml = file_get_contents($absoluteurl."components/feed_languages/feed_languages.xml");
//Set up the parser object
// $parser = new XMLParser($xml);
$parser = simplexml_load_file($absoluteurl.'components/feed_languages/feed_languages.xml','SimpleXMLElement',LIBXML_NOCDATA);
//Parse the XML file with categories data...
// $parser->Parse();
}
?>

View File

@ -1,40 +0,0 @@
<?php
############################################################
# PODCAST GENERATOR
#
# Created by Alberto Betella
# http://www.podcastgenerator.net
#
# This is Free Software released under the GNU/GPL License.
############################################################
########### Security code, avoids cross-site scripting (Register Globals ON)
if (isset($_REQUEST['GLOBALS']) OR isset($_REQUEST['absoluteurl']) OR isset($_REQUEST['amilogged']) OR isset($_REQUEST['theme_path'])) { exit; }
########### End
### Check if user is logged ###
if (!isUserLogged()) { exit; }
###
//Get the XML document loaded into a variable (The xml parser must be previously included)
if (file_exists($absoluteurl."components/podcastgen_languages/podcastgen_languages.xml")) {
//$xml = file_get_contents(absoluteurl.'components/podcastgen_languages/podcastgen_languages.xml');
//Set up the parser object
// $parser = new XMLParser($xml);
//Parse the XML file with categories data...
// $parser->Parse();
$parser = simplexml_load_file($absoluteurl.'components/podcastgen_languages/podcastgen_languages.xml','SimpleXMLElement',LIBXML_NOCDATA);
}
?>

View File

@ -1,368 +0,0 @@
<?php
############################################################
# PODCAST GENERATOR
#
# Created by Alberto Betella
# http://www.podcastgenerator.net
#
# This is Free Software released under the GNU/GPL License.
############################################################
########### Security code, avoids cross-site scripting (Register Globals ON)
if (isset($_REQUEST['GLOBALS']) OR isset($_REQUEST['absoluteurl']) OR isset($_REQUEST['amilogged']) OR isset($_REQUEST['theme_path'])) { exit; }
########### End
// check if user is already logged in
if(isUserLogged()) {
$PG_mainbody .= '<h3>'._("Change Podcast Generator Configuration").'</h3>
';
if (isset($_GET['action']) AND $_GET['action']=="change") { // if action is set
//streaming
$streaming = $_POST['streaming'];
if ($streaming != "") {
$enablestreaming = $streaming;
}
// social networks integration
$socialnetworks = $_POST['socialnetworks'];
if ($socialnetworks != "") {
$enablesocialnetworks = array($socialnetworks); //create an array with values 1 or 0 for each social networks
}
//freebox
$fbox = $_POST['fbox'];
if ($fbox != "") {
$freebox = $fbox;
}
//categories
$cats = $_POST['cats'];
if ($cats != "") {
$categoriesenabled = $cats;
}
//news display
$newsinadmin = $_POST['newsinadmin'];
if ($newsinadmin != "") {
$enablepgnewsinadmin = $newsinadmin;
}
// strict rename
$strictfilename = $_POST['strictfilename'];
if ($strictfilename != "") {
$strictfilenamepolicy = $strictfilename;
}
// recent in home
$recent = $_POST['recent'];
if ($recent != "") {
$max_recent = $recent;
}
// recent in FEED
$recentinfeed = $_POST['recentinfeed'];
if ($recentinfeed != "") {
$recent_episode_in_feed = $recentinfeed;
}
// date format
$selectdateformat = $_POST['selectdateformat'];
if ($selectdateformat != "") {
$dateformat = $selectdateformat;
}
// script language
$scriptlanguage = $_POST['scriptlanguage'];
if ($scriptlanguage != "") {
$scriptlang = $scriptlanguage;
}
include ("$absoluteurl"."core/admin/createconfig.php"); //regenerate config.php
$PG_mainbody .= '<p>'._("The information has been successfully sent.").'</p>';
//REGENERATE FEED ...
//include ("$absoluteurl"."core/admin/feedgenerate.php");
$episodesCounter = generatePodcastFeed(TRUE,NULL,FALSE); //Output in file
$PG_mainbody .= '<br /><br />';
}
else { // if action not set
$PG_mainbody .= '<form name="podcastdetails" method="POST" enctype="multipart/form-data" action="?p=admin&do=config&action=change">';
##########streaming
$PG_mainbody .= '<br /><br /><p><label for="streaming"><b>'._("Enable Audio and Video Player?").'</b></label></p>
<span class="alert">'._("Enable Audio and Video web player for supported files and browsers.").'</span>
<p>'._("Yes").' <input type="radio" name="streaming" value="yes" ';
if ($enablestreaming == "yes") {
$PG_mainbody .= 'checked';
}
$PG_mainbody .= '>&nbsp;&nbsp; '._("No").' <input type="radio" name="streaming" value="no" ';
if ($enablestreaming == "no") {
$PG_mainbody .= 'checked';
}
$PG_mainbody .= '></p>';
####
########## social networks integration
$PG_mainbody .= '<br /><br /><p><label for="socialnetworks"><b>'._("Enable Social Networks Integration?").'</b></label></p>
<span class="alert">'._("Display Facebook, Twitter and Google+ buttons for each episode.").'</span>
<p>'._("Yes").' <input type="radio" name="socialnetworks" value="1,1,1" ';
if (in_array(TRUE,$enablesocialnetworks)) { //if at least one is true
$PG_mainbody .= 'checked';
}
$PG_mainbody .= '>&nbsp;&nbsp; '._("No").' <input type="radio" name="socialnetworks" value="0,0,0" ';
if (!in_array(TRUE,$enablesocialnetworks)) { //if all false
$PG_mainbody .= 'checked';
}
$PG_mainbody .= '></p>';
####
########## freebox
$PG_mainbody .= '<br /><br /><p><label for="fbox"><b>'._("Enable Freebox?").'</b></label></p>
<span class="alert">'._("Freebox allows you to write freely what you wish, add links or text through a visual editor in the admin section.").'</span>
<p>'._("Yes").' <input type="radio" name="fbox" value="yes" ';
if ($freebox == "yes") {
$PG_mainbody .= 'checked';
}
$PG_mainbody .= '>&nbsp;&nbsp; '._("No").' <input type="radio" name="fbox" value="no" ';
if ($freebox == "no") {
$PG_mainbody .= 'checked';
}
$PG_mainbody .= '></p>';
####
########## categories
$PG_mainbody .= '<br /><br /><a name="setcategoriesfeature" id="setcategoriesfeature"></a><p><label for="cats"><b>'._("Enable categories?").'</b></label></p>
<span class="alert">'._("Enable categories feature to make thematic lists of your podcasts.").'</span>
<p>'._("Yes").' <input type="radio" name="cats" value="yes" ';
if ($categoriesenabled == "yes") {
$PG_mainbody .= 'checked';
}
$PG_mainbody .= '>&nbsp;&nbsp; '._("No").' <input type="radio" name="cats" value="no" ';
if ($categoriesenabled == "no") {
$PG_mainbody .= 'checked';
}
$PG_mainbody .= '></p>';
####
########## newsinadmin
$PG_mainbody .= '<br /><br /><p><label for="newsinadmin"><b>'._("Enable news display?").'</b></label></p>
<span class="alert">'._("Displays Podcast Generator latest news in the main administration page of your podcast.").'</span>
<p>'._("Yes").' <input type="radio" name="newsinadmin" value="yes" ';
if ($enablepgnewsinadmin == "yes") {
$PG_mainbody .= 'checked';
}
$PG_mainbody .= '>&nbsp;&nbsp; '._("No").' <input type="radio" name="newsinadmin" value="no" ';
if ($enablepgnewsinadmin == "no") {
$PG_mainbody .= 'checked';
}
$PG_mainbody .= '></p>';
####
########## strictfilename
$PG_mainbody .= '<br /><br /><p><label for="strictfilename"><b>'._("Enable strict episode renaming policy?").'</b></label></p>
<span class="alert">'._("The uploaded episode files will be automatically renamed using just alphanumeric characters and the current date.").'</span>
<p>'._("Yes").' <input type="radio" name="strictfilename" value="yes" ';
if ($strictfilenamepolicy == "yes") {
$PG_mainbody .= 'checked';
}
$PG_mainbody .= '>&nbsp;&nbsp; '._("No").' <input type="radio" name="strictfilename" value="no" ';
if ($strictfilenamepolicy == "no") {
$PG_mainbody .= 'checked';
}
$PG_mainbody .= '></p>';
####
########## recent in home
$PG_mainbody .= '<br /><br /><p><label for="recent"><b>'._("How many recent podcasts in the home page?").'</b></label></p>
<select name="recent" id="recent">
<option value=\'2\'';
if ($max_recent == 2) { $PG_mainbody .= ' selected'; }
$PG_mainbody .= '>2</option>
<option value=\'4\'';
if ($max_recent == 4) { $PG_mainbody .= ' selected'; }
$PG_mainbody .= '>4</option>
<option value=\'6\'';
if ($max_recent == 6) { $PG_mainbody .= ' selected'; }
$PG_mainbody .= '>6</option>
<option value=\'8\'';
if ($max_recent == 8) { $PG_mainbody .= ' selected'; }
$PG_mainbody .= '>8</option>
<option value=\'10\'';
if ($max_recent == 10) { $PG_mainbody .= ' selected'; }
$PG_mainbody .= '>10</option>
<option value=\'20\'';
if ($max_recent == 20) { $PG_mainbody .= ' selected'; }
$PG_mainbody .= '>20</option>
</select>
';
####
########## recent in feed
$PG_mainbody .= '<br /><br /><br /><p><label for="recentinfeed"><b>'._("How many episodes indexed in the podcast feeds?").'</b></label></p>
<select name="recentinfeed" id="recentinfeed">
<option value=\'5\'';
if ($recent_episode_in_feed == "5") { $PG_mainbody .= ' selected'; }
$PG_mainbody .= '>5</option>
<option value=\'10\'';
if ($recent_episode_in_feed == "10") { $PG_mainbody .= ' selected'; }
$PG_mainbody .= '>10</option>
<option value=\'15\'';
if ($recent_episode_in_feed == "15") { $PG_mainbody .= ' selected'; }
$PG_mainbody .= '>15</option>
<option value=\'20\'';
if ($recent_episode_in_feed == "20") { $PG_mainbody .= ' selected'; }
$PG_mainbody .= '>20</option>
<option value=\'All\'';
if ($recent_episode_in_feed == "All") { $PG_mainbody .= ' selected'; }
$PG_mainbody .= '>'._("All").'</option>
</select>
';
####
########## date format
$PG_mainbody .= '<br /><br /><br /><p><label for="selectdateformat"><b>'._("Select date format").'</b></label></p>
<select name="selectdateformat" id="selectdateformat">
<option value=\'d-m-Y\'';
if ($dateformat == "d-m-Y") { $PG_mainbody .= ' selected'; }
$PG_mainbody .= '>'._("Day").' / '._("Month").' / '._("Year").'</option>
<option value=\'m-d-Y\'';
if ($dateformat == "m-d-Y") { $PG_mainbody .= ' selected'; }
$PG_mainbody .= '>'._("Month").' / '._("Day").' / '._("Year").'</option>
<option value=\'Y-m-d\'';
if ($dateformat == "Y-m-d") { $PG_mainbody .= ' selected'; }
$PG_mainbody .= '>'._("Year").' / '._("Month").' / '._("Day").'</option>
</select>
';
####
$listWithLanguages = languagesList($absoluteurl,TRUE);
## SCRIPT LANGUAGES LIST
$PG_mainbody .= '<br /><br /><br /><p><label for="scriptlanguage"><b>'._("Podcast Generator Language").'</b></label></p>
<p><span class="alert">'._("Choose among available languages *").'</span></p>
';
$PG_mainbody .= '<select name="scriptlanguage">';
natcasesort($listWithLanguages); // Natcasesort orders more naturally and is different from "sort", which is case sensitive
foreach ($listWithLanguages as $key => $val) {
$PG_mainbody .= '
<option value="' . $key. '"';
if ($scriptlang == languageISO639($key) OR $scriptlang == $key) {
$PG_mainbody .= ' selected';
}
$PG_mainbody .= '>' . $val . '</option>';
}
$PG_mainbody .= '</select>
<p><a href="http://www.podcastgenerator.net/documentation/FAQ-localization" target="_blank"><i class="fa fa-hand-o-right"></i> '._("Looking for another language?").'</a></p>
';
if (isset($installationKey) AND isset($cronAutoIndex) AND $cronAutoIndex == TRUE){
$PG_mainbody .= '<br /><br /><p><label for="cronURL"><b>'._("Use cron to auto index episodes").'</b></label></p>
<p><span class="alert">'._("This feature is enabled.")." "._("By calling periodically Podcast Generator via a cron job, you can check automatically the media folder for new episodes and regenerate the RSS feed.").'</span></p>
<p>'._("Copy and paste the URL below (including your unique key):").'</p>
<input type="text" name="cronURL" value="'.$url.'pg-cron.php?key='.$installationKey.'" style="width:80%;" readonly>
<p><a href="http://www.podcastgenerator.net/documentation/FAQ-cron-job" target="_blank"><i class="fa fa-hand-o-right"></i> '._("Visit the documentation for more information on how to setup a cron job").'</a></p>';
}
$PG_mainbody .= '<br /><br /><input type="submit" name="'._("Send").'" class="btn btn-success btn-small" value="'._("Send").'" onClick="showNotify(\''._("Updating").'\');"></p><br />
</form>';
}
}
?>

View File

@ -1,94 +0,0 @@
<?php
############################################################
# PODCAST GENERATOR
#
# Created by Alberto Betella
# http://www.podcastgenerator.net
#
# This is Free Software released under the GNU/GPL License.
############################################################
########### Security code, avoids cross-site scripting (Register Globals ON)
if (isset($_REQUEST['GLOBALS']) OR isset($_REQUEST['absoluteurl']) OR isset($_REQUEST['amilogged']) OR isset($_REQUEST['theme_path'])) { exit; }
########### End
// check if user is already logged in
if(isUserLogged()) {
$PG_mainbody .= '<h3>'._("Theme Selection").'</h3>';
if (isset($_POST['themedir']) AND $_POST['themedir'] != NULL) {
$new_theme_path = 'themes/'.$_POST['themedir'].'/'; // new theme
if ($new_theme_path != $theme_path) { // theme is different
$theme_path = $new_theme_path;
include ("$absoluteurl"."core/admin/createconfig.php"); //regenerate config.php
$PG_mainbody .= '<p>'._("Theme changed!").'</p>
<p><a href="?p=admin&do=theme">'._("Try another theme...").'</a></p>';
}
else { // if theme is already in use
$PG_mainbody .= '<p>'._("You are already using this theme").'</p>
<p><a href="?p=admin&do=theme">'._("Try another theme...").'</a></p>';
}
}
else {
$PG_mainbody .= '
<p>'._("Change Podcast Generator theme and aspect:").'</p>
<form name="'._("Theme Selection").'" method="POST" enctype="multipart/form-data" action="?p=admin&do=theme">
<select name="themedir">';
$dir = "$absoluteurl"."themes/";
$dirHandle = opendir($dir);
// $count = -1;
$returnstr = "";
while ($themedir = readdir($dirHandle)) {
if(!is_dir($themedir) AND $themedir != '..' AND $themedir != '.' AND $themedir != 'index.htm' AND $themedir != 'common.css' AND $themedir != '_vti_cnf' AND $themedir != '.DS_Store') {
// $count++; //if u want a theme counter
// $returnstr .= '&f'.$count.'='.$file;
$new_theme_path = 'themes/'.$themedir.'/'; //check theme and eventually select it in the form if it is in use
if ($new_theme_path == $theme_path) { // select current theme in the form
$PG_mainbody .= "<option value='$themedir' selected>$themedir</option>";
}
else {
$PG_mainbody .= "<option value='$themedir'>$themedir</option>";
}
}
}
$PG_mainbody .= '</select><br /><br />
<input type="submit" name="'._("Change").'" value="'._("Change").'" class="btn btn-success btn-small" onClick="showNotify(\''._("Setting...").'\');">
';
closedir($dirHandle);
}
$PG_mainbody .= '<br /><br /><div class="topseparator">
<span class="alert">'._("Hint: How to create your own theme?").' <a href="http://www.podcastgenerator.net/documentation/FAQ-themes" target="_blank">'._("See documentation").'</a></span>
</div>
';
}
?>

View File

@ -1,212 +0,0 @@
<?php
############################################################
# PODCAST GENERATOR
#
# Created by Alberto Betella
# http://www.podcastgenerator.net
#
# This is Free Software released under the GNU/GPL License.
############################################################
########### Security code, avoids cross-site scripting (Register Globals ON)
if (isset($_REQUEST['GLOBALS']) OR isset($_REQUEST['absoluteurl']) OR isset($_REQUEST['amilogged']) OR isset($_REQUEST['theme_path'])) { exit; }
########### End
### Check if user is logged ###
if (!isUserLogged()) { exit; }
###
if (isset($_POST['userfile']) AND $_POST['userfile']!=NULL AND isset($_POST['title']) AND $_POST['title']!=NULL AND isset($_POST['description']) AND $_POST['description']!=NULL){ //001
$file = $_POST['userfile']; //episode file
if (isset($_FILES['image'])) $img = $_FILES['image'] ['name']; // image file
if (isset($_POST['existentimage'])) $existentimage = $_POST['existentimage']; else $existentimage = NULL;
$title = $_POST['title'];
$description = $_POST['description'];
if (isset($_POST['category']) AND $_POST['category'] != NULL) {
$category = $_POST['category'];
} else {
$category = NULL;
}
$long_description = $_POST['long_description'];
$keywords = $_POST['keywords'];
$explicit = $_POST['explicit'];
$auth_name = $_POST['auth_name'];
$auth_email = $_POST['auth_email'];
// echo "<br /><br /><br />$file - err $errore - temp: $temporaneo<br /><br /><br />";
$filesuffix = NULL; // declare variable for duplicated filenames
$image_new_name = NULL; // declare variable for image name
####
## here I check lenght of long description: according to the iTunes technical specifications
## the itunes:summary field can be up to 4000 characters, while the other fields up to 255
$longdescmax =4000; #set max characters variable. iTunes specifications by Apple say "max 4000 characters" for long description field
if (strlen($long_description)<$longdescmax) { // 002 (if long description IS NOT too long, go on executing...
####
#### INPUT DEPURATION
$title = depurateContent($title); //title
$description = depurateContent($description); //short desc
$long_description = depurateContent($long_description); //long desc
$keywords = depurateContent($keywords); //Keywords
$auth_name = depurateContent($auth_name); //author's name
##############
### processing Long Description
#$PG_mainbody .= "QUI: $long_description<br>lunghezza:".strlen($long_description)."<br>"; //debug
if ($long_description == NULL OR $long_description == " ") { //if user didn't input long description the long description is equal to short description
$PG_mainbody .= "<p>"._("Long description not present; I'll use short description...")."</p>";
$long_description = $description;
}
else {
$PG_mainbody .= "<p>"._("Long Description present")."</p>";
$long_description = str_replace("&nbsp;", " ", $long_description);
}
##############
### processing iTunes KEYWORDS
## iTunes supports a maximum of 12 keywords for searching: don't know how many keywords u can add in a feed. Anyway it's better to add a few keyword, so we display a warning if user submits more than 12 keywords
# $PG_mainbody .= "$keywords<br>"; /debug
if (isset($ituneskeywords) AND $ituneskeywords != NULL) {
$PG_mainbody .= "<p>"._("iTunes Keywords:")." $ituneskeywords</p>";
$singlekeyword=explode(",",$keywords); // divide filename from extension
if ($singlekeyword[12] != NULL) { //if more than 12 keywords
$PG_mainbody .= "<p>- "._("You submitted more than 12 keywords for iTunes...")."</p>";
}
}
##############
### processing Author
if (isset($auth_name) AND $auth_name != NULL) { //if a different author is specified
$PG_mainbody .= "<p>"._("Author specified for this episode...")."</p>";
if (!validate_email($auth_email)) { //if author doesn't have a valid email address, just ignore it and use default author
$PG_mainbody .= "<p>"._("Author's email address not present or not valid.")." "._("Author will be IGNORED")."</p>";
$auth_name = NULL; //ignore author
$auth_email = NULL; //ignore email
}
}
else { //if author's name doesn't exist unset also email field
$auth_email = NULL; //ignore email
}
$file_ext = divideFilenameFromExtension($file); //supports more full stops . in the file name. PHP >= 5.2.0 needed
############################################
# START CHANGE DATE
//print_r($_POST);
if (isset($_POST['Day']) AND isset($_POST['Month']) AND isset($_POST['Year']) AND isset($_POST['Hour']) AND isset($_POST['Minute'])) {
$filefullpath = $absoluteurl.$upload_dir.$file;
$oradelfile = filemtime($filefullpath);
$oracambiata = mktime($_POST['Hour'],$_POST['Minute'],0,$_POST['Month'],$_POST['Day'],$_POST['Year']); //seconds are simply 0, no need to handle them
if ($oradelfile != $oracambiata AND checkdate($_POST['Month'],$_POST['Day'],$_POST['Year']) == TRUE) { //is date posted is different from file date and if php function CHECKDATE == TRUE
touch($filefullpath,$oracambiata);
$PG_mainbody .= "<p>"._("Date and time of the episode have been modified (this might change the order of your episodes in the podcast feed).")."</p>";
}
}
# END CHANGE DATE
############################################
$PG_mainbody .= "<p><b>"._("Processing changes...")."</b></p>";
//// RE-CREATING XML FILE ASSOCIATED TO EPISODE
$thisEpisodeData = array($title,$description,$long_description,$image_new_name,$category,$keywords,$explicit,$auth_name,$auth_email);
$episodeXMLDBAbsPath = $absoluteurl.$upload_dir.$file_ext[0].'.xml'; // extension = XML
//// Creating xml file associated to episode
writeEpisodeXMLDB($thisEpisodeData,$absoluteurl,$filefullpath,$episodeXMLDBAbsPath,$file_ext[0],TRUE);
# $PG_mainbody .= "<p><b><font color=\"green\">"._("File")."sent</font></b></p>"; // If upload is successful.
########## REGENERATE FEED
//include ("$absoluteurl"."core/admin/feedgenerate.php"); //(re)generate XML feed
$episodesCounter = generatePodcastFeed(TRUE,NULL,FALSE); //Output in file
##########
$PG_mainbody .= "<p><a href=\"$url\">"._("Go to the homepage")."</a> - <a href=\"?p=archive&amp;cat=all\">"._("Edit other episodes")."</a></p>";
} // 002
else { //if long description is more than max characters allowed
$PG_mainbody .= "<b>"._("Long Description")."toolong</b><p>"._("Long Description")."maxchar $longdescmax "._("characters")." - "._("Actual Length")." <font color=red>".strlen($long_description)."</font> "._("characters").".</p>
<form>
<INPUT TYPE=\"button\" VALUE=\""._("Back")."\" onClick=\"history.back()\">
</form>";
}
#### end of long desc lenght checking
} //001
else { //if file, description or title not present...
$PG_mainbody .= '<p>'._("Error: No file, description or title present").'
<br />
<form>
<input type="button" value="&laquo; '._("Back").'" onClick="history.back()" class="btn btn-danger btn-small" />
</form>
</p>
';
}
?>

View File

@ -1,317 +0,0 @@
<?php
############################################################
# PODCAST GENERATOR
#
# Created by Alberto Betella
# http://www.podcastgenerator.net
#
# This is Free Software released under the GNU/GPL License.
############################################################
########### Security code, avoids cross-site scripting (Register Globals ON)
if (isset($_REQUEST['GLOBALS']) OR isset($_REQUEST['absoluteurl']) OR isset($_REQUEST['amilogged']) OR isset($_REQUEST['theme_path'])) { exit; }
########### End
### Check if user is logged ###
if (!isUserLogged()) { exit; }
###
if (isset($_FILES['userfile']) AND $_FILES['userfile']!=NULL AND isset($_POST['title']) AND $_POST['title']!=NULL AND isset($_POST['description']) AND $_POST['description']!=NULL){ //001
$file= $_FILES['userfile'] ['name']; //episode file
// if (isset($_FILES['image'])) $img= $_FILES['image'] ['name']; // image file
$title = $_POST['title'];
$description = $_POST['description'];
if (isset($_POST['category']) AND $_POST['category'] != NULL) $category = $_POST['category'];
$long_description = $_POST['long_description'];
$keywords = $_POST['keywords'];
$explicit = $_POST['explicit'];
$auth_name = $_POST['auth_name'];
$auth_email = $_POST['auth_email'];
// $errore= $_FILES['userfile']['error'];
$temporaneo= $_FILES['userfile']['tmp_name'];
// echo "<br /><br /><br />$file - err $errore - temp: $temporaneo<br /><br /><br />";
$filesuffix = NULL; // declare variable for duplicated filenames
$image_new_name = NULL; // declare variable for image name
####
## here I check lenght of long description: according to the iTunes technical specifications
## the itunes:summary field can be up to 4000 characters, while the other fields up to 255
$longdescmax = 4000; #set max characters variable. iTunes specifications by Apple say "max 4000 characters" for long description field
if (strlen($long_description)<$longdescmax) { // 002 (if long description IS NOT too long, go on executing...
####
#### INPUT DEPURATION
$title = depurateContent($title); //title
$description = depurateContent($description); //short desc
$long_description = depurateContent($long_description); //long desc
$keywords = depurateContent($keywords); //Keywords
$auth_name = depurateContent($auth_name); //author's name
##############
### processing Long Description
#$PG_mainbody .= "QUI: $long_description<br>lunghezza:".strlen($long_description)."<br>"; //debug
if ($long_description == NULL OR $long_description == " ") { //if user didn't input long description the long description is equal to short description
$PG_mainbody .= "<p>"._("Long description not present (the short description will be used)")."</p>";
$long_description = $description;
}
else {
$PG_mainbody .= "<p>"._("Long Description present")."</p>";
$long_description = str_replace("&nbsp;", " ", $long_description);
}
##############
### processing iTunes KEYWORDS
## iTunes supports a maximum of 12 keywords for searching: don't know how many keywords u can add in a feed. Anyway it's better to add a few keyword, so we display a warning if user submits more than 12 keywords
# $PG_mainbody .= "$keywords<br>"; /debug
if (isset($ituneskeywords) AND $ituneskeywords != NULL) {
$PG_mainbody .= "<p>"._("iTunes Keywords:")." $ituneskeywords</p>";
$singlekeyword=explode(",",$keywords); // divide filename from extension
if ($singlekeyword[12] != NULL) { //if more than 12 keywords
$PG_mainbody .= "<p>- "._("You submitted more than 12 keywords for iTunes...")."</p>";
}
}
##############
### processing Author
if (isset($auth_name) AND $auth_name != NULL) { //if a different author is specified
$PG_mainbody .= "<p>"._("Author specified for this episode...")."</p>";
if (!validate_email($auth_email)) { //if author doesn't have a valid email address, just ignore it and use default author
$PG_mainbody .= "<p>"._("No")."authemail "._("Author will be IGNORED")."</p>";
$auth_name = NULL; //ignore author
$auth_email = NULL; //ignore email
}
}
else { //if author's name doesn't exist unset also email field
$auth_email = NULL; //ignore email
}
#show submitted data (debug purposes)
//$PG_mainbody .= "Dati inseriti:</b><br><br>Titolo: <i>$title</i> <br>Descrizione breve: <i>$description</i> <br>Descrizione lunga: <i>$long_description</i>";
###
## start processing podcast
$PG_mainbody .= "<p><b>"._("Processing episode...")."</b></p>";
$PG_mainbody .= "<p>"._("Original filename:")." <i>$file</i></p>";
$file_parts = divideFilenameFromExtension($file);
$filenameWithoutExtension = $file_parts[0];
$fileExtension = $file_parts[1];
// $PG_mainbody .= "<p>"._("File")."_ext <i>$fileExtension</i></p>"; //display file extension
##############
### processing file extension
$fileData = checkFileType(strtolower($fileExtension),$absoluteurl); //lowercase extension to compare with the accepted extensions array
if (isset($fileData[0])){ //avoids php notice if array [0] doesn't exist
$podcast_filetype=$fileData[0];
}else {
$podcast_filetype=NULL;
}
if ($fileExtension==strtoupper($podcast_filetype)) $podcast_filetype = strtoupper($podcast_filetype); //accept also uppercase extension
if ($fileExtension==$podcast_filetype) { //003 (if file extension is accepted, go on....
##############
##############
### file name depuration!!!! Important... By default Podcastgen uses a "strict" depuration policy (just characters from a to z and numbers... no accents and other characters).
if ($strictfilenamepolicy == "yes") {
#enable this to have a very strict filename policy
$filenameWithoutExtension = renamefilestrict ($filenameWithoutExtension);
}
else {
# LESS strict renaming policy
$filenameWithoutExtension = renamefile ($filenameWithoutExtension);
}
$fileExtension = strtolower ($fileExtension); //lowercase file extension
##############
############## end filename depuration
if ($strictfilenamepolicy == "yes") $filenamechanged = date('Y-m-d')."_".$filenameWithoutExtension; //add date, to order files in mp3 players
else $filenamechanged = $filenameWithoutExtension;
$uploadFile = $upload_dir . $filenamechanged.".".$fileExtension ;
$uploadFileXML = $upload_dir . $filenamechanged.".xml" ;
while (file_exists("$uploadFile") OR file_exists("$uploadFileXML")) { //if file already exists add an incremental suffix
$filesuffix++;
# $PG_mainbody .= "$filesuffix"; //debug
$uploadFile = $absoluteurl . $upload_dir . $filenamechanged . $filesuffix.".".$fileExtension ;
$uploadFileXML = $absoluteurl . $upload_dir . $filenamechanged . $filesuffix.".xml" ;
}
$PG_mainbody .= _("File Renamed:")." <i>$filenamechanged$filesuffix.$fileExtension</i><br />";
$uploadFile == NULL ;
#$PG_mainbody .= "<br>Uploaded file:$uploadFile<br>";
//move file from the temp directory to the upload directory
if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadFile))
{
############################################
# START CHANGE DATE
//print_r($_POST);
if (isset($_POST['Day']) AND isset($_POST['Month']) AND isset($_POST['Year']) AND isset($_POST['Hour']) AND isset($_POST['Minute'])) {
$filefullpath = $absoluteurl.$upload_dir.$filenamechanged.$filesuffix.'.'.$fileExtension;
//$oradelfile = filemtime($filefullpath);
$oracambiata = mktime($_POST['Hour'],$_POST['Minute'],0,$_POST['Month'],$_POST['Day'],$_POST['Year']); //seconds are simply 0, no need to handle them
// echo $oracambiata;
if ($oracambiata > time() AND checkdate($_POST['Month'],$_POST['Day'],$_POST['Year']) == TRUE) {
touch($filefullpath,$oracambiata);
$PG_mainbody .= "<p>"._("The episode date has been set to future. This episode won't show up till then.")."</p>";
}
}
# END CHANGE DATE
############################################
$thisEpisodeData = array($title,$description,$long_description,$image_new_name,$category,$keywords,$explicit,$auth_name,$auth_email);
$episodeXMLDBAbsPath = $absoluteurl.$upload_dir.$filenamechanged.$filesuffix.'.xml'; // extension = XML
//// Creating xml file associated to episode
writeEpisodeXMLDB($thisEpisodeData,$absoluteurl,$filefullpath,$episodeXMLDBAbsPath,$filenamechanged.$filesuffix,TRUE);
$PG_mainbody .= "<p><b><font color=\"green\">"._("File sent")."</font></b></p>"; // If upload is successful.
########## REGENERATE FEED
//include ("$absoluteurl"."core/admin/feedgenerate.php"); //(re)generate XML feed
$episodesCounter = generatePodcastFeed(TRUE,NULL,FALSE); //Output in file
##########
$PG_mainbody .= "<p><a href=\"$url\">"._("Go to the homepage")."</a> - <a href=\"?p=admin&do=upload\">"._("Upload another episode")."</a></p>";
}
else //If upload is not successful
{
$PG_mainbody .= "<p><b><font color=\"red\">"._("FILE ERROR")." "._("Upload Failed")."</font></b></p>";
$PG_mainbody .= "<p><b>"._("FILE ERROR")."1</b></p>";
$PG_mainbody .= "<p> - "._("You didn't assign writing permission to the media folder and the uploaded file can't be saved on the server.")."</p>";
$PG_mainbody .= "<p> - "._("Your file is bigger than upload max filesize on your server.")."</p>";
$PG_mainbody .= "<p><b>"._("Useful information for debugging:")."</b> <a href=\"?p=admin&amp;do=serverinfo\">"._("Your server configuration")."</a></p>";
$PG_mainbody .= "<p>"._("FILE ERROR")." <a href=\"http://www.podcastgenerator.net/\" target=\"_blank\">"._("Podcast Generator web page")."</a></p>";
$PG_mainbody .= '<p><form>
<input type="button" value="'._("Back").'" class="btn btn-danger btn-small" onClick="history.back()">
</form></p>';
}
} // 003 (if file extension is not accepted)
else {
$PG_mainbody .= "<p><i>$fileExtension</i> "._("is not a supported extension or your filename contains forbidden characters.")."</p>";
$PG_mainbody .= '<form>
<input type="button" value="'._("Back").'" class="btn btn-danger btn-small" onClick="history.back()">
</form>';
}
} // 002
else { //if long description is more than max characters allowed
$PG_mainbody .= "<b>"._("Long Description")."toolong</b><p>"._("Long Description")."maxchar $longdescmax "._("characters")." - "._("Actual Length")." <font color=red>".strlen($long_description)."</font> "._("characters").".</p>";
$PG_mainbody .= '<form>
<input type="button" value="'._("Back").'" class="btn btn-danger btn-small" onClick=\"history.back()\">
</form>';
}
#### end of long desc lenght checking
} //001
else { //if file, description or title not present...
$PG_mainbody .= '<p>'._("Error: No file, description or title present").'
<br />
<form>
<input type="button" value="&laquo; '._("Back").'" onClick="history.back()" class="btn btn-danger btn-small" />
</form>
</p>
';
}
?>

View File

@ -1,71 +0,0 @@
<?php
############################################################
# PODCAST GENERATOR
#
# Created by Alberto Betella
# http://www.podcastgenerator.net
#
# This is Free Software released under the GNU/GPL License.
############################################################
if (isset($_GET['p'])) if ($_GET['p']=="admin") { // if admin is called from the script in a GET variable - security issue
##############
#show server information
# convert max upload size set in config.php in megabytes
$max_upload_form_size_MB = $max_upload_form_size/1048576;
$max_upload_form_size_MB = round($max_upload_form_size_MB, 2);
$PG_mainbody .= '
<div>
<h3>'._("Your server configuration").'</h3>';
if (php_uname('s')!= NULL) { $PG_mainbody .= '<p>'._("Operating System:").' '.php_uname('s'); }
$PG_mainbody .= '
<p>'._("PHP Version:").' '.phpversion().'
<br />
<br />display_errors = ' . ini_get('display_errors').'';
//IF GETTEXT EXTENSION INSTALLED IN THE SERVER OR NOT
//note that $gettextInstalled is created in language.php
if ($gettextInstalled == 0) $PG_mainbody .= '<br />'._("GETTEXT extension: not installed (php-gettext will be used)");
else $PG_mainbody .= '<br />'._("GETTEXT extension: installed");
if (ini_get('register_globals')!= NULL) { //if value not null
$PG_mainbody .= '<br />register_globals = ' . ini_get('register_globals').'';
} else {
$PG_mainbody .= '<br />register_globals = OFF '._("(this is good)");
}
$PG_mainbody .= '<br />
<br />upload_max_filesize (php.ini) = ' . ini_get('upload_max_filesize') . '
<br />post_max_size (php.ini) = ' . ini_get('post_max_size') . '<br />';
if (ini_get('memory_limit')!= NULL) { //if value not null
$PG_mainbody .= 'memory_limit (php.ini) = ' . ini_get('memory_limit') . '<br />';
}
$PG_mainbody .= '
<br />'._("Max upload size set in the script (config.php):").' '.$max_upload_form_size_MB.'M</p>';
########### Determine max upload file size through php script reading the server parameters (and the form parameter specified in config.php. We find the minimum value: it should be the max file size allowed...
$showmin = min($max_upload_form_size_MB, ini_get('upload_max_filesize')+0, ini_get('post_max_size')+0); // min function
// Note: if I add +0 it eliminates the "M" (e.g. 8M,9M) and this solves some issues with the "min" function
#############################
if ($showmin!=NULL and $showmin!="0") {
$PG_mainbody .= '<p><b>'._("Your server configuration allows you to upload files up to").' '.$showmin._("MB").'</b></p>';
}
$PG_mainbody .= '</div>';
}
?>

View File

@ -1,129 +0,0 @@
<?php
############################################################
# PODCAST GENERATOR
#
# Created by Alberto Betella
# http://www.podcastgenerator.net
#
# This is Free Software released under the GNU/GPL License.
############################################################
########### Security code, avoids cross-site scripting (Register Globals ON)
if (isset($_REQUEST['GLOBALS']) OR isset($_REQUEST['absoluteurl']) OR isset($_REQUEST['amilogged']) OR isset($_REQUEST['theme_path'])) { exit; }
########### End
### Check if user is logged ###
if (!isUserLogged()) { exit; }
###
/*
include ("$absoluteurl"."components/xmlparser/loadparser.php"); */
include ("$absoluteurl"."core/admin/readXMLcategories.php");
if (file_exists("$absoluteurl"."categories.xml")) {
//if (file_exists("$absoluteurl"."categories.xml") AND isset($parser->document->category)) {
///// DETERMINE NEW PODCAST OR EDIT PODCAST MODE
if (isset($_GET['do']) AND $_GET['do']=="edit") { //if edit mode
$preselectcat = "yes"; //this variable will preselect categories assigned to an episode
} else {
$preselectcat = "no";
}
/////
/*
foreach($parser->category as $singlecategory)
{
//echo $singlecategory->id[0]->tagData."<br>";
//echo $singlecategory->description[0]->tagData;
$arr[] .= $singlecategory->description[0]->tagData;
$arrid[] .= $singlecategory->id[0]->tagData;
$n++;
}
*/
$PG_mainbody .= '<label for="category">'._("Categories").' *</label>
<span class="alert alert-warning">'._("Select up to 3 categories for your episode...").'</span>';
/*
if ($preselectcat == "yes") {
$PG_mainbody .= '<span class ="alert">'._("(The categories already associated to this episode are pre-selected in the form below)").'</span><br />';
}
*/
$PG_mainbody .= '<br /><select class="form-control" style="max-width:220px" name="category[]"';
if ($n<5) { //height of the category form
$PG_mainbody .= 'size="'.$n.'" ';
} else {
$PG_mainbody .= 'size="5" '; //standard height if more than 5 categories
}
$PG_mainbody .= 'multiple id="category" onchange="checkMaxSelected(this, 3, \''._("Maximum number of selectable category per single episode: ").'\');">'; // 3 = max category number... if u change this value, you should also change php code in other files...
natcasesort($arr); // Natcasesort orders more naturally and is different from "sort", which is case sensitive
$firstselect = 0; //value to determine the first category of the form, which will be selected by default
foreach ($arr as $key => $val) {
//$PG_mainbody .= "cat[" . $key . "] = " . $val . "<br>";
if ($firstselect == "0" AND $preselectcat != "yes") { //pre-select the first category (except in edit mode which is set in this var: $preselectcat == "yes")
$PG_mainbody .= '<option value=\'' . $arrid[$key] . '\' selected>' . $val .'</option>';
}
else { // other arrays not pre-selected
$PG_mainbody .= '<option value=\'' . $arrid[$key] . '\' ';
if ($preselectcat == "yes") {
if ($text_category1 == $arrid[$key] OR $text_category2 == $arrid[$key] OR $text_category3 == $arrid[$key]) {
$PG_mainbody .= 'selected';
}
}
$PG_mainbody .= '>' . $val .'</option>';
}
$firstselect++; //increment
}
$PG_mainbody .= '</select>';
} //if xml categories file doesn't exist
else
{
$PG_mainbody .= '<p><b>'._("Categories file doesn't exist or empty...").'</b></p>';
$PG_mainbody .= '
<form action="?p=admin&amp;do=categories&amp;action=add" method="POST" enctype="multipart/form-data" name="categoryform" id="categoryform" onsubmit="return submitForm();">
<br /><br />
<label for="addcategory"><b>'._("Add a new category:").'</b></label><br />
<input name="addcategory" id="addcategory" type="text" size="50" maxlength="255" ><br />
<input type="submit" value="'._("Add").'" onClick="showNotify(\''._("Adding...").'\');">
';
}
?>

View File

@ -1,186 +0,0 @@
<?php
############################################################
# PODCAST GENERATOR
#
# Created by Alberto Betella
# http://www.podcastgenerator.net
#
# This is Free Software released under the GNU/GPL License.
############################################################
########### Security code, avoids cross-site scripting (Register Globals ON)
if (isset($_REQUEST['GLOBALS']) OR isset($_REQUEST['absoluteurl']) OR isset($_REQUEST['amilogged']) OR isset($_REQUEST['theme_path'])) { exit; }
########### End
### Check if user is logged ###
if (!isUserLogged()) { exit; }
###
if (isset($_GET['p']) AND $_GET['p']=="admin" AND isset($_GET['do']) AND $_GET['do']=="upload" AND isset($_GET['c']) AND $_GET['c']=="ok") {
$PG_mainbody .= '<h3>'._("Upload Podcast").'</h3>';
include("$absoluteurl"."core/admin/sendfile.php");
// $PG_mainbody .= '</div>';
}
else {
########### Determine max upload file size through php script reading the server parameters (and the form parameter specified in config.php. We find the minimum value: it should be the max file size allowed...
# convert max upload size set in config.php in megabytes
$max_upload_form_size_MB = $max_upload_form_size/1048576;
$max_upload_form_size_MB = round($max_upload_form_size_MB, 2);
$showmin = min($max_upload_form_size_MB, ini_get('upload_max_filesize')+0, ini_get('post_max_size')+0); // min function
// Note: if I add +0 it eliminates the "M" (e.g. 8M, 9M) and this solves some issues with the "min" function
#############################
#########
$PG_mainbody .= '<h3 class="sectionTitle">'._("Upload New Episode").'</h3>';
$PG_mainbody .= '
<div class="span5 col-md-5 importantSection">
<form action="?p=admin&amp;do=upload&amp;c=ok" method="POST" enctype="multipart/form-data" name="uploadform" id="uploadform" onsubmit="return submitForm();">
<fieldset>
<legend><b>'._("Main information").'</b></legend>
<input type="hidden" name="MAX_FILE_SIZE" value="'.$max_upload_form_size.'">
<label for="userfile">'._("File").' *</label>
<input name="userfile" id="userfile" type="file"><br />';
if ($showmin!=NULL and $showmin!="0") {
$PG_mainbody .= '<span class = "alert">'._("Your server configuration allows you to upload files up to").' '.$showmin._("MB").' '._("- If you need to upload larger files you can use the").' <a href="?p=admin&amp;do=ftpfeature">'._("FTP Feature").'</a></span>';
}
$PG_mainbody .= '<br /><br />
<label for="title">'._("Title").' *</label>
<input name="title" id="title" type="text" size="50" maxlength="255" ><br /><br />
<label for="description">'._("Short Description").' *</label>
<input name="description" id="description" type="text" onKeyDown="limitText(this.form.description,this.form.countdown,255);"
onKeyUp="limitText(this.form.description,this.form.countdown,255);" size="50" maxlength="255">
<br />
<span>
<input name="countdown" class="readonlyinput" type="text" value="255" class ="alert" size="3" readonly> '._("characters left").'</span>
<br /><br />';
### INCLUDE CATEGORIES FORM
if ($categoriesenabled == "yes") { // if categories are enabled in config.php
include("$absoluteurl"."core/admin/showcat.php");
}
//else { // if categories are disabled, then use an empty value
//$PG_mainbody .= '<input type="hidden" name="category[0]" value="">';
// }
### END CATEGORIES FORM
// $PG_mainbody .= '<a href="javascript:;" onclick="$(\'#dateForm\').fadeToggle();"> '._("Publication Date").'</a><br />';
// $PG_mainbody .= '<div id="dateForm" style="display:none;">HERE THE DATE FORM</div>';
$PG_mainbody .= '
<br /><br />
<label>'._("Publication Date").'</label>
<span class ="alert">'._("The form below reports the current time and date of the server. If you specify a date in future, your episode won't be shown till then.").'</span><br /><br />
'.CreaFormData("",time(),$dateformat); //dateformat is taken from config.php
$PG_mainbody .= '<br /><br />';
$PG_mainbody .= _("Fields marked with * are required.").'
';
// $PG_mainbody .= '<p><input type="checkbox" value="'._("add extra information to this episode").'" onClick="javascript:Effect.toggle(\'main\',\'appear\');">'._("add extra information to this episode").'</p>';
$PG_mainbody .= '</fieldset>
</div>';
$PG_mainbody .= '
<div class="span5 col-md-5">
<fieldset>
<legend><b>'._("Extras").'</b></legend>
<label for="long_description">'._("Long Description").'</label>
<textarea id="long_description" name="long_description" cols="50" rows="3"></textarea>
<br />';
//UPLOAD IMAGE ASSOCIATED TO EACH EPISODE
//Disabled for the moment (does it really work in the podcast feed?
//better to upload images in the WYSIWYG editor in future
//$PG_mainbody .= '<label for="image">'._("Image").'</label><br /><span class ="alert">'._("You can associate an image to this episode; it will appear on the recent podcast page and on the details page.").'</span><br /><span class ="alert">'._("Upload a SMALL image (suggested dimensions: 150x150 pixels). Accepted formats: png, gif e jpg.").'</span><br /><br /><input name="image" type="file"><br /><br /><br />';
$PG_mainbody .= '
<label for="keywords">'._("iTunes Keywords").'</label>
<input name="keywords" type="text" onkeyup="cnt(this,document.uploadform.counttotalwords)" size="50" maxlength="255" placeholder="'._("Keyword1, Keyword2 (max 12)").'">';
//count keywords
//$PG_mainbody .= '<span><input type="text" name="counttotalwords" value="0" onkeyup="cnt(document.uploadform.keywords,this)" class="readonlyinput" readonly />'._("keywords").'</span>';
$PG_mainbody .= '
<br /><br />
<label for="explicit">'._("Explicit content").'</label>
<span class ="alert">'._("Select YES if this episode contains explicit language or adult content").'</span><br /><br />
'._("Yes").'&nbsp;<input type="radio" name="explicit" value="yes">&nbsp;
'._("No").'&nbsp;<input type="radio" name="explicit" value="no" checked>
<br /><br />
<label for="auth_name">'._("Author").'</label>
<span class ="alert">'._("You can specify a different author for this episode, otherwise the default author will be the podcast owner").'</span><br />
<input name="auth_name" type="text" id="auth_name" size="30" maxlength="255" placeholder="'._("Author's name").'" class="input-medium">
<input name="auth_email" type="text" id="auth_email" size="30" maxlength="255" placeholder="'._("Author's email address").'" class="input-medium">
</fieldset>
<br />
<input type="submit" value="'._("Upload Episode").'" class="btn btn-success btn-large" onClick="showNotify(\''._("Uploading...").'\');">
<br /><br />
</form>
</div>
';
} // end else . if GET variable "c" is not = "ok"
?>

File diff suppressed because it is too large Load Diff

View File

@ -1,27 +0,0 @@
<?php
############################################################
# PODCAST GENERATOR
#
# Created by Alberto Betella
# http://www.podcastgenerator.net
#
# This is Free Software released under the GNU/GPL License.
############################################################
//// Security code, avoids cross-site scripting (Register Globals ON)
if (isset($_REQUEST['GLOBALS']) OR isset($_REQUEST['absoluteurl']) OR isset($_REQUEST['theme_path'])) { exit; }
//if config.php doesn't exist, stop
if (!file_exists("config.php")) {
header("HTTP/1.1 301 Moved Permanently");
header("Location: setup/"); // redirect to setup
}
include("config.php");
include_once($absoluteurl."core/functions.php"); //LOAD ONCE
include($absoluteurl."core/language.php");
?>

View File

@ -1,89 +0,0 @@
<?php
############################################################
# PODCAST GENERATOR
#
# Created by Alberto Betella
# http://www.podcastgenerator.net
#
# This is Free Software released under the GNU/GPL License.
############################################################
/*
NOTE: podcastgen uses gettext to handle locale and translations
English is the main language and will work always. However, when using translations:
if the gettext extension is not installed in the server then a php lib is used.
if installed, then podcastgen will use native gettext.
Tested under various linux distro and mac os (mamp)
It WON'T probably work flawlessly with a windows server.
This is due to different way windows has to handle locales (not easy to solve, not reliable): http://php.net/manual/en/function.setlocale.php
Well, I hope there are not so many people out there using windows as a web server!!!
If you are just using WAMP to test podcastgenerator, and you need localization in a language
different than english, then you can go to mamp menu -> PHP -> PHP extensions
and disable php_gettext. It will work.
*/
########### Security code, avoids cross-site scripting (Register Globals ON)
if (isset($_REQUEST['GLOBALS']) OR isset($_REQUEST['scriptlang'])) { exit; }
########### End
//FIRST CHECK IF GETTEXT IS INSTALLED AS A PHP EXTENSION IN THE SERVER (Otherwise php-gettext lib will be installed)
//the var $gettextInstalled is used to show the server info (for future debugs)
if (function_exists("gettext")) $gettextInstalled = 1; //1 = extension installed
else $gettextInstalled = 0;
if (!defined('LOCALE_DIR')) define('LOCALE_DIR', $absoluteurl .'/components/locale'); //dir containing locales - define just if not already defined
if (isset($scriptlang)) {
//define('DEFAULT_LOCALE', $scriptlang);
$locale = $scriptlang;
}
elseif (!isset($scriptlang) AND isset($_POST['setuplanguage'])) { //if setup
$locale = $_POST['setuplanguage'];
}
else {
//define('DEFAULT_LOCALE', 'en_EN');
$locale = "en_EN";
}
//Encoding! UT8 recommended!
$encoding = 'UTF-8';
// Set the text domain as 'messages'
$domain = 'messages';
if ($gettextInstalled == 0) {
//WE USE PHPGETTEXT LIB - https://launchpad.net/php-gettext/
require_once($absoluteurl.'components/php-gettext/gettext.inc');
//$locale = (isset($_GET['lang']))? $_GET['lang'] : DEFAULT_LOCALE;
// gettext setup
// TO DEBUG T_setlocale in /core/language.php doesn't work on IIS8, PHP5.5alpha4 when php_gettext.dll is enabled in php.ini -> switching to setlocale doesn't generate errors but doesn't change language either
T_setlocale(LC_MESSAGES, $locale);
T_bindtextdomain($domain, LOCALE_DIR);
T_bind_textdomain_codeset($domain, $encoding); //encoding
T_textdomain($domain);
}
else { //IF GETTEXT EXTENSION INSTALLED
if (!ini_get('safe_mode')) putenv("LC_ALL=$locale");
setlocale(LC_ALL, $locale);
bindtextdomain($domain, LOCALE_DIR);
bind_textdomain_codeset($domain, $encoding); //encoding
textdomain($domain);
}
?>

View File

@ -1,416 +0,0 @@
<?php
############################################################
# PODCAST GENERATOR
#
# Created by Alberto Betella
# http://www.podcastgenerator.net
#
# This is Free Software released under the GNU/GPL License.
############################################################
//THIS FILE IS SIMILAR to themes.php and is used instead of it when we
//have a new theme for version 2.0+
//The old themes.php is kept for retro-compatibility with old themes
//The choice between themes.php and templates.php is made in index.php
//and depends on the theme.xml file (a file that must be included
//in the main folder of each new theme for PG 2.0+
/*Common CSS classes to add to a PG theme:
active (menu active)
nav-header (titles in sidebar)
navbar-link (links in the navbar (e.g. log out)
*/
########### Security code, avoids cross-site scripting (Register Globals ON)
if (isset($_REQUEST['GLOBALS']) OR isset($_REQUEST['absoluteurl']) OR isset($_REQUEST['amilogged']) OR isset($_REQUEST['theme_path'])) { exit; }
########### End
if (isUserLogged()) {
$loginmenu = _("Hello").' '.$username.' (<a href="?p=admin" class="navbar-link">'._("Admin").'</a> - <a href="?p=admin&amp;action=logout" class="navbar-link">'._("Log out").'</a>)';
} else {
//standard login menu item (replaced with the authenticated one if logged in
$loginmenu = '<a href="?p=admin" class="navbar-link">'._("Admin").'</a>';
}
if(($theme_file_contents = file_get_contents($theme_path."index.htm")) === FALSE) {
echo "<p class=\"error\">"._("Failed to open theme file")."</p>";
exit;
}
#Replace URLs
$theme_file_contents = str_replace("href=\"style/", "href=\"".$theme_path."style/", $theme_file_contents); // Replace CSS location
$theme_file_contents = str_replace("src=\"img/", "src=\"".$theme_path."img/", $theme_file_contents); // Replace image location
$theme_file_contents = str_replace("src=\"js/", "src=\"".$theme_path."js/", $theme_file_contents); // Replace js location
$theme_file_contents = str_replace("<param name=movie value=\"", "<param name=movie value=\"".$theme_path, $theme_file_contents); // Replace flash objects IE
$theme_file_contents = str_replace("<embed src=\"", "<embed src=\"".$theme_path, $theme_file_contents); // Replace flash objects embed
####### INCLUDE PHP FUNCTIONS SPECIFIED IN THE THEME (functions.php)
if (file_exists($theme_path."functions.php")) {
include ($theme_path."functions.php");
}
####### END INCLUDE PHP FUNCTIONS
#########################
# SET PAGE TITLE
$page_title_prefix = NULL;
//Show category name
if (isset($_GET['cat']) AND $_GET['cat'] != "all" AND !isset($_GET['action'])) {
$existingCategories = readPodcastCategories ($absoluteurl);
if (isset($existingCategories[avoidXSS($_GET['cat'])])) {
//URL depuration (avoidXSS)
$page_title_prefix .= $existingCategories[avoidXSS($_GET['cat'])]." - ";
}
}
//Show a generic "All episodes"
elseif (isset($_GET['p']) AND $_GET['p']=="archive") {
$page_title_prefix .= _("All Episodes")." - ";
}
//if is single episode, add title of episode to title of page
elseif (isset($_GET['name'])) {
$titleOfEpisode = showSingleEpisode(avoidXSS($_GET['name']),1); //the last parameter (1) requires just the title to that function
if ($titleOfEpisode != NULL) $page_title_prefix .= "$titleOfEpisode - ";
}
$page_title = $page_title_prefix.$podcast_title;
$theme_file_contents = str_replace("-----PG_PAGETITLE-----", $page_title, $theme_file_contents);
include($absoluteurl."core/admin/loadjavascripts.php");
$theme_file_contents = str_replace("-----PG_JSLOAD-----", $loadjavascripts, $theme_file_contents);
###############################
###############################
//LOAD A CSS WITH CLASSES COMMON TO ALL THE THEMES
$commonCSSurl = '<link href="themes/common.css" rel="stylesheet">';
//ADDING FONT AWESOME, FOR AWESOME ICONS
$commonCSSurl .= '<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet">';
$theme_file_contents = str_replace("-----PG_COMMONCSSLOAD-----", $commonCSSurl, $theme_file_contents);
// SET PODCAST FEED custom or default URL
if (isset($feed_URL_replace) AND $feed_URL_replace != "") {
$podcastFeedURL = $feed_URL_replace;
$podcastFeedURLiTunes = str_replace("http://", "itpc://", $podcastFeedURL);
} else {
$podcastFeedURL = $url.$feed_dir.'feed.xml';
$podcastFeedURLiTunes = str_replace("http://", "itpc://", $podcastFeedURL);
}
// If a particular URL is specified for iTunes (e.g. direct link to store) use it
if (isset($feed_iTunes_URL_replace) AND $feed_iTunes_URL_replace != "") {
$podcastFeedURLiTunes = $feed_iTunes_URL_replace;
}
$rightboxcontent = '<div class="rightbox">
<span class="nav-header">'.$podcast_title.' '._("feed").'</span>
<p>'._("Copy the feed link and paste it into your aggregator").'<br /><br />
<a href="'.$podcastFeedURL.'"><img src="rss-podcast.gif" alt="'._("Copy the feed link and paste it into your aggregator").'" title="'._("Copy the feed link and paste it into your aggregator").'" border="0" /></a>
</p>
<p>'._("Subscribe to this podcast with iTunes").'<br /><br /><a href="'.$podcastFeedURLiTunes.'"><img src="podcast_itunes.jpg" alt="'._("Subscribe to this podcast with iTunes").'" title="'._("Subscribe to this podcast with iTunes").'" border="0" /></a></p>
</div>';
# If you are logged show right boxes
$adminrightboxcontent = NULL;
if(isUserLogged()) { //if admin page
//show donation box after 3 days from installation
if (isset($first_installation) and time()-$first_installation>259200) {//259200 seconds = 3 days
if (isset($author_name) and $author_name != NULL) $nameToAddressUser = $author_name.", ";
else $nameToAddressUser = NULL;
$adminrightboxcontent .= '
<div class="rightbox">
<span class="nav-header">'._("Support Podcast Generator").'</span>
<p>'.$nameToAddressUser._("if you like Podcast Generator please consider").' <a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&amp;hosted_button_id=K6KLDE3KPP6VN" target="_blank"><strong>'._(" making a donation").'</strong></a>.
'._("No matter the amount you donate, your contribution will support future development and bug fixes. Thank you!").'</p>
<p><a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&amp;hosted_button_id=K6KLDE3KPP6VN" target="_blank">
<i class="fa fa-cc-paypal fa-2x"></i> <i class="fa fa-cc-visa fa-2x"></i> <i class="fa fa-cc-mastercard fa-2x"></i> <i class="fa fa-cc-amex fa-2x"></i>
</a>
</div>
';
}
//show PG box
$adminrightboxcontent .= '
<div class="rightbox">
<span class="nav-header">'._("Help").'</span>
<ul>
<li><a href="?p=admin&amp;do=serverinfo">'._("Your server configuration").'</a></li>
<li><a href="http://www.podcastgenerator.net/checkforupdates.php?v='.$podcastgen_version.'" target="_blank">'._("Check for updates").'</a></li>
<li><a href="http://www.podcastgenerator.net/documentation/#faq?ref=local-admin" target="_blank">'._("Read Documentation").'</a></li>
<li><a href="http://www.podcastgenerator.net/support/?ref=local-admin" target="_blank">'._("Get Support").'</a></li>
</ul>
</div>
';
}
$theme_file_contents = str_replace("-----PG_RIGHTBOX-----", $rightboxcontent, $theme_file_contents);
$theme_file_contents = str_replace("-----PG2_ADMINRIGHTBOX-----", $adminrightboxcontent, $theme_file_contents);
# SET RIGHT OPTIONAL BOX ("freebox")
$freeboxcontent = NULL;
if ($freebox == "yes") { //if admin is logged do not display freebox - and freebox is enabled
if(file_exists($absoluteurl."freebox-content.txt")){
$freeboxcontenttodisplay = file_get_contents($absoluteurl."freebox-content.txt");
$freeboxcontent = '<div class="rightbox">
'.$freeboxcontenttodisplay.'
</div>';
}
$theme_file_contents = str_replace("-----PG_FREEBOX-----", $freeboxcontent, $theme_file_contents);
} else {
$freeboxcontent = NULL;
$theme_file_contents = str_replace("-----PG_FREEBOX-----", $freeboxcontent, $theme_file_contents);
}
# Othere Theme elements replacing
$theme_file_contents = str_replace("-----PG_MAINBODY-----", $PG_mainbody, $theme_file_contents);
$theme_file_contents = str_replace("-----PG_PAGECHARSET-----", $feed_encoding, $theme_file_contents);
$theme_file_contents = str_replace("-----PG_PODCASTTITLE-----", $podcast_title, $theme_file_contents);
$theme_file_contents = str_replace("-----PG_PODCASTSUBTITLE-----", $podcast_subtitle, $theme_file_contents);
$theme_file_contents = str_replace("-----PG_PODCASTDESC-----", $podcast_description, $theme_file_contents);
$theme_file_contents = str_replace("-----PG2_URLRSSFEED-----", $podcastFeedURL, $theme_file_contents);
$theme_file_contents = str_replace("-----PG2_URLFORITUNES-----", $podcastFeedURLiTunes, $theme_file_contents);
#### MENU TOP
// Replace menu top (class active assigned to the active menu)
//home button
$contentmenuhome = '<li';
if (isset($_GET['p']) and $_GET['p'] == "home") $contentmenuhome .= ' class="active"';
$contentmenuhome .= '><a href="?p=home">'._("Home").'</a></li>';
$theme_file_contents = str_replace("-----PG_MENUHOME-----", $contentmenuhome, $theme_file_contents);
// end home button
//archive button
$contentmenuarchive = NULL; //DEFINE VARIABLE
if ($categoriesenabled == "yes") { //if categories are enabled
$contentmenuarchive .= '
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">'._("Archive").' <b class="caret"></b></a>
<ul class="dropdown-menu">';
// READ THE CATEGORIES
$existingCategories = readPodcastCategories ($absoluteurl);
//var_dump($existingCategories); //Debug
ksort($existingCategories); //sort array by key alphabetically
for ($i = 0; $i < count($existingCategories); $i++) {
$key=key($existingCategories);
$val=$existingCategories[$key];
if ($val<> ' ') {
$contentmenuarchive .= '<li><a href="?p=archive&amp;cat='.$key.'">'.$val.'</a></li>';
}
next($existingCategories);
}
// END - READ THE CATEGORIES
$contentmenuarchive .= '
<li class="divider"></li>
<li><a href="?p=archive&amp;cat=all">'._("All Episodes").'</a></li>
</ul></li>';
} else {
$contentmenuarchive = '<li';
if (isset($_GET['p']) and $_GET['p'] == "archive") $contentmenuarchive .= ' class="active"';
$contentmenuarchive .= '><a href="?p=archive">'._("All Episodes").'</a></li>';
}
$theme_file_contents = str_replace("-----PG_MENUARCHIVE-----", $contentmenuarchive, $theme_file_contents);
// end home button
// $theme_file_contents = str_replace("-----PG_MENUARCHIVE-----", _("Podcast Archive"), $theme_file_contents);
$theme_file_contents = str_replace("-----PG_MENUADMIN-----", $loginmenu, $theme_file_contents);
#FOOTER
$definefooter = _("Powered by").' <a href="http://www.podcastgenerator.net" title="'._("Podcast Generator")._(", an open source podcast publishing solution").'">'._("Podcast Generator").'</a>'._(", an open source podcast publishing solution");
$theme_file_contents = str_replace("-----PG_FOOTER-----", $definefooter, $theme_file_contents);
#########################
# META TAGS AND FEED LINK
//meta tags
//new meta tags HTML5 - deleted the obsolete
$metatagstoreplace = '
<meta name="Generator" content="Podcast Generator '.$podcastgen_version.'" />
<meta name="Author" content="'.depuratecontent($author_name).'" />
';
if (isset($_GET['p']) and $_GET['p'] == "admin" and isset($_GET['do']) and $_GET['do'] == "itunesimg") { // no cache in itunes image admin page
$metatagstoreplace .= '<meta http-equiv="expires" content="0" />
';
}
# define META KEYWORDS
// on single episode page (permalink), use itunes keywords and episode description as meta tags...
if (isset($_GET['p']) AND $_GET['p']=="episode" AND isset($episode_present) AND $episode_present == "yes") {
if ($text_keywordspg != NULL) { // ...if keywords exist
$metatagstoreplace .= '<meta name="Keywords" content="'.depuratecontent($text_keywordspg).'" />
';
}
$metatagstoreplace .= '<meta name="Description" content="'.depuratecontent($text_shortdesc).'" />
'; // use episode short description
}
else { // if not permalink page, use podcast general description as meta tag
$metatagstoreplace .= '<meta name="Description" content="'.depuratecontent($podcast_description).'" />
';
}
// on the home page (recent_list.php) use keywords of the most recent episode
if (isset($assignmetakeywords) AND $assignmetakeywords != NULL) { // the variable $assignmetakeywords is assigned in recent_list.php
$metatagstoreplace .= '<meta name="Keywords" content="'.depuratecontent($assignmetakeywords).'" />
';
}
// general XML feed of the podcast
$metatagstoreplace .= '
<link href="'.$podcastFeedURL.'" rel="alternate" type="application/rss+xml" title="'.$podcast_title.' RSS" />';
//CUSTOMIZE THE PAGES DEDICATED TO SINGLE EPISODES (with dedicated meta tags to increase SEO)
//reconstruct the full URL of the episode
if (isset($_GET['name'])) {
$episodeURLreconstructed = $url.'?name='.avoidXSS($_GET['name']);
// then ADD SOME OPEN GRAPH META TAGS
$metatagstoreplace .= '
<meta property="og:title" content="'.$titleOfEpisode.' &laquo; '.$podcast_title.'"/>
<meta property="og:url" content="'.$episodeURLreconstructed.'"/>
';
// and the canonical link
$metatagstoreplace .= '
<link rel="canonical" href="'.$episodeURLreconstructed.'" />
';
}
else { //IF IS HOME PAGE
$metatagstoreplace .= '
<meta property="og:title" content="'.$podcast_title.'"/>
<meta property="og:url" content="'.$url.'"/>
<meta property="og:image" content="'.$url.$img_dir.'itunes_image.jpg"/>
';
// and the canonical link
$metatagstoreplace .= '
<link rel="canonical" href="'.$url.'" />
';
}
$theme_file_contents = str_replace("-----PG_METATAGS-----", $metatagstoreplace, $theme_file_contents);
# END META TAGS DEFINITION
#########################
//INCLUDE LOADING INDICATOR IN ALL THE PAGES
//The indicator is included in all the pages just before closing the tag </html> so we are sure it is outside others relative containers (e.g. bootstrap theme). Otherwise it would be displayed relative to the main container, not to the body
if (isset($_GET['p']) AND $_GET['p']=="admin") { //all admin pages included login
//NB the closing body tag has been added below!
$loading_indicator_code = '
<div id="status_notification">Uploading...</div>
</body>
';
$theme_file_contents = str_replace("</body>", $loading_indicator_code, $theme_file_contents);
}
//END - INCLUDE LOADING INDICATOR IN ALL THE PAGES
?>

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